|
|
1.1 root 1: /*
2: MS-DOS Player for Win32 console
3:
4: Author : Takeda.Toshiya
5: Date : 2009.11.09-
6: */
7:
8: #include "msdos.h"
9:
1.1.1.28 root 10: void exit_handler();
11:
1.1 root 12: #define fatalerror(...) { \
13: fprintf(stderr, __VA_ARGS__); \
1.1.1.28 root 14: exit_handler(); \
1.1 root 15: exit(1); \
16: }
17: #define error(...) fprintf(stderr, "error: " __VA_ARGS__)
1.1.1.22 root 18: #define nolog(...)
19:
1.1.1.33 root 20: //#define ENABLE_DEBUG_LOG
21: #ifdef ENABLE_DEBUG_LOG
1.1.1.22 root 22: #define EXPORT_DEBUG_TO_FILE
23: #define ENABLE_DEBUG_SYSCALL
24: #define ENABLE_DEBUG_UNIMPLEMENTED
1.1.1.25 root 25: #define ENABLE_DEBUG_IOPORT
1.1.1.22 root 26:
27: #ifdef EXPORT_DEBUG_TO_FILE
1.1.1.33 root 28: FILE* fp_debug_log = NULL;
1.1.1.22 root 29: #else
1.1.1.33 root 30: #define fp_debug_log stderr
1.1.1.22 root 31: #endif
32: #ifdef ENABLE_DEBUG_UNIMPLEMENTED
33: #define unimplemented_10h fatalerror
1.1.1.25 root 34: #define unimplemented_14h fatalerror
1.1.1.22 root 35: #define unimplemented_15h fatalerror
36: #define unimplemented_16h fatalerror
1.1.1.37 root 37: #define unimplemented_17h fatalerror
1.1.1.22 root 38: #define unimplemented_1ah fatalerror
39: #define unimplemented_21h fatalerror
40: #define unimplemented_2fh fatalerror
1.1.1.24 root 41: #define unimplemented_33h fatalerror
1.1.1.22 root 42: #define unimplemented_67h fatalerror
43: #define unimplemented_xms fatalerror
44: #endif
45: #endif
46: #ifndef unimplemented_10h
47: #define unimplemented_10h nolog
48: #endif
1.1.1.25 root 49: #ifndef unimplemented_14h
50: #define unimplemented_14h nolog
51: #endif
1.1.1.22 root 52: #ifndef unimplemented_15h
53: #define unimplemented_15h nolog
54: #endif
55: #ifndef unimplemented_16h
56: #define unimplemented_16h nolog
57: #endif
1.1.1.37 root 58: #ifndef unimplemented_17h
59: #define unimplemented_17h nolog
60: #endif
1.1.1.22 root 61: #ifndef unimplemented_1ah
62: #define unimplemented_1ah nolog
63: #endif
64: #ifndef unimplemented_21h
65: #define unimplemented_21h nolog
66: #endif
67: #ifndef unimplemented_2fh
68: #define unimplemented_2fh nolog
69: #endif
1.1.1.24 root 70: #ifndef unimplemented_33h
71: #define unimplemented_33h nolog
72: #endif
1.1.1.22 root 73: #ifndef unimplemented_67h
74: #define unimplemented_67h nolog
75: #endif
76: #ifndef unimplemented_xms
77: #define unimplemented_xms nolog
78: #endif
79:
1.1.1.32 root 80: #define array_length(array) (sizeof(array) / sizeof(array[0]))
1.1.1.22 root 81: #define my_strchr(str, chr) (char *)_mbschr((unsigned char *)(str), (unsigned int)(chr))
82: #define my_strtok(tok, del) (char *)_mbstok((unsigned char *)(tok), (const unsigned char *)(del))
83: #define my_strupr(str) (char *)_mbsupr((unsigned char *)(str))
1.1 root 84:
1.1.1.12 root 85: #if defined(__MINGW32__)
86: extern "C" int _CRT_glob = 0;
87: #endif
88:
89: /*
90: kludge for "more-standardized" C++
91: */
92: #if !defined(_MSC_VER)
93: inline int kludge_min(int a, int b) { return (a<b ? a:b); }
94: inline int kludge_max(int a, int b) { return (a>b ? a:b); }
95: #define min(a,b) kludge_min(a,b)
96: #define max(a,b) kludge_max(a,b)
1.1.1.14 root 97: #elif _MSC_VER >= 1400
98: void ignore_invalid_parameters(const wchar_t *, const wchar_t *, const wchar_t *, unsigned int, uintptr_t)
99: {
100: }
101: #endif
102:
1.1.1.35 root 103: #define USE_VRAM_THREAD
1.1.1.14 root 104:
1.1.1.35 root 105: #ifdef USE_VRAM_THREAD
1.1.1.14 root 106: static CRITICAL_SECTION vram_crit_sect;
107: #else
108: #define vram_flush()
1.1.1.12 root 109: #endif
110:
1.1.1.14 root 111: #define VIDEO_REGEN *(UINT16 *)(mem + 0x44c)
112: #define SCR_BUF(y,x) scr_buf[(y) * scr_buf_size.X + (x)]
113:
114: void change_console_size(int width, int height);
115: void clear_scr_buffer(WORD attr);
116:
117: static UINT32 vram_length_char = 0, vram_length_attr = 0;
118: static UINT32 vram_last_length_char = 0, vram_last_length_attr = 0;
119: static COORD vram_coord_char, vram_coord_attr;
120:
1.1.1.28 root 121: char temp_file_path[MAX_PATH];
122: bool temp_file_created = false;
123:
1.1.1.14 root 124: bool ignore_illegal_insn = false;
125: bool limit_max_memory = false;
126: bool no_windows = false;
127: bool stay_busy = false;
1.1.1.19 root 128: bool support_ems = false;
129: #ifdef SUPPORT_XMS
130: bool support_xms = false;
131: #endif
1.1.1.29 root 132: int sio_port_number[4] = {0, 0, 0, 0};
1.1.1.14 root 133:
134: BOOL is_vista_or_later;
135:
1.1.1.35 root 136: #define UPDATE_OPS 16384
137: #define REQUEST_HARDWRE_UPDATE() { \
138: update_ops = UPDATE_OPS - 1; \
139: }
140: UINT32 update_ops = 0;
141: UINT32 idle_ops = 0;
142:
1.1.1.14 root 143: inline void maybe_idle()
144: {
145: // if it appears to be in a tight loop, assume waiting for input
146: // allow for one updated video character, for a spinning cursor
1.1.1.35 root 147: if(!stay_busy && idle_ops < 1024 && vram_length_char <= 1 && vram_length_attr <= 1) {
1.1.1.14 root 148: Sleep(10);
1.1.1.35 root 149: REQUEST_HARDWRE_UPDATE();
1.1.1.14 root 150: }
1.1.1.35 root 151: idle_ops = 0;
1.1.1.14 root 152: }
1.1.1.12 root 153:
1.1 root 154: /* ----------------------------------------------------------------------------
1.1.1.3 root 155: MAME i86/i386
1.1 root 156: ---------------------------------------------------------------------------- */
157:
1.1.1.10 root 158: #ifndef __BIG_ENDIAN__
1.1 root 159: #define LSB_FIRST
1.1.1.10 root 160: #endif
1.1 root 161:
162: #ifndef INLINE
163: #define INLINE inline
164: #endif
165: #define U64(v) UINT64(v)
166:
167: //#define logerror(...) fprintf(stderr, __VA_ARGS__)
168: #define logerror(...)
169: //#define popmessage(...) fprintf(stderr, __VA_ARGS__)
170: #define popmessage(...)
171:
172: /*****************************************************************************/
1.1.1.10 root 173: /* src/emu/devcpu.h */
174:
175: // CPU interface functions
176: #define CPU_INIT_NAME(name) cpu_init_##name
177: #define CPU_INIT(name) void CPU_INIT_NAME(name)()
178: #define CPU_INIT_CALL(name) CPU_INIT_NAME(name)()
179:
180: #define CPU_RESET_NAME(name) cpu_reset_##name
181: #define CPU_RESET(name) void CPU_RESET_NAME(name)()
182: #define CPU_RESET_CALL(name) CPU_RESET_NAME(name)()
183:
184: #define CPU_EXECUTE_NAME(name) cpu_execute_##name
185: #define CPU_EXECUTE(name) void CPU_EXECUTE_NAME(name)()
186: #define CPU_EXECUTE_CALL(name) CPU_EXECUTE_NAME(name)()
187:
188: #define CPU_TRANSLATE_NAME(name) cpu_translate_##name
189: #define CPU_TRANSLATE(name) int CPU_TRANSLATE_NAME(name)(address_spacenum space, int intention, offs_t *address)
190: #define CPU_TRANSLATE_CALL(name) CPU_TRANSLATE_NAME(name)(space, intention, address)
191:
192: #define CPU_DISASSEMBLE_NAME(name) cpu_disassemble_##name
193: #define CPU_DISASSEMBLE(name) int CPU_DISASSEMBLE_NAME(name)(char *buffer, offs_t eip, const UINT8 *oprom)
194: #define CPU_DISASSEMBLE_CALL(name) CPU_DISASSEMBLE_NAME(name)(buffer, eip, oprom)
195:
1.1.1.14 root 196: #define CPU_MODEL_STR(name) #name
197: #define CPU_MODEL_NAME(name) CPU_MODEL_STR(name)
198:
1.1.1.10 root 199: /*****************************************************************************/
200: /* src/emu/didisasm.h */
201:
202: // Disassembler constants
203: const UINT32 DASMFLAG_SUPPORTED = 0x80000000; // are disassembly flags supported?
204: const UINT32 DASMFLAG_STEP_OUT = 0x40000000; // this instruction should be the end of a step out sequence
205: const UINT32 DASMFLAG_STEP_OVER = 0x20000000; // this instruction should be stepped over by setting a breakpoint afterwards
206: const UINT32 DASMFLAG_OVERINSTMASK = 0x18000000; // number of extra instructions to skip when stepping over
207: const UINT32 DASMFLAG_OVERINSTSHIFT = 27; // bits to shift after masking to get the value
208: const UINT32 DASMFLAG_LENGTHMASK = 0x0000ffff; // the low 16-bits contain the actual length
209:
210: /*****************************************************************************/
1.1 root 211: /* src/emu/diexec.h */
212:
213: // I/O line states
214: enum line_state
215: {
216: CLEAR_LINE = 0, // clear (a fired or held) line
217: ASSERT_LINE, // assert an interrupt immediately
218: HOLD_LINE, // hold interrupt line until acknowledged
219: PULSE_LINE // pulse interrupt line instantaneously (only for NMI, RESET)
220: };
221:
222: // I/O line definitions
223: enum
224: {
225: INPUT_LINE_IRQ = 0,
226: INPUT_LINE_NMI
227: };
228:
229: /*****************************************************************************/
1.1.1.10 root 230: /* src/emu/dimemory.h */
1.1 root 231:
1.1.1.10 root 232: // Translation intentions
233: const int TRANSLATE_TYPE_MASK = 0x03; // read write or fetch
234: const int TRANSLATE_USER_MASK = 0x04; // user mode or fully privileged
235: const int TRANSLATE_DEBUG_MASK = 0x08; // debug mode (no side effects)
236:
237: const int TRANSLATE_READ = 0; // translate for read
238: const int TRANSLATE_WRITE = 1; // translate for write
239: const int TRANSLATE_FETCH = 2; // translate for instruction fetch
240: const int TRANSLATE_READ_USER = (TRANSLATE_READ | TRANSLATE_USER_MASK);
241: const int TRANSLATE_WRITE_USER = (TRANSLATE_WRITE | TRANSLATE_USER_MASK);
242: const int TRANSLATE_FETCH_USER = (TRANSLATE_FETCH | TRANSLATE_USER_MASK);
243: const int TRANSLATE_READ_DEBUG = (TRANSLATE_READ | TRANSLATE_DEBUG_MASK);
244: const int TRANSLATE_WRITE_DEBUG = (TRANSLATE_WRITE | TRANSLATE_DEBUG_MASK);
245: const int TRANSLATE_FETCH_DEBUG = (TRANSLATE_FETCH | TRANSLATE_DEBUG_MASK);
1.1 root 246:
1.1.1.10 root 247: /*****************************************************************************/
248: /* src/emu/emucore.h */
1.1 root 249:
1.1.1.10 root 250: // constants for expression endianness
251: enum endianness_t
252: {
253: ENDIANNESS_LITTLE,
254: ENDIANNESS_BIG
255: };
1.1 root 256:
1.1.1.10 root 257: // declare native endianness to be one or the other
258: #ifdef LSB_FIRST
259: const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_LITTLE;
260: #else
261: const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_BIG;
262: #endif
263:
264: // endian-based value: first value is if 'endian' is little-endian, second is if 'endian' is big-endian
265: #define ENDIAN_VALUE_LE_BE(endian,leval,beval) (((endian) == ENDIANNESS_LITTLE) ? (leval) : (beval))
266:
267: // endian-based value: first value is if native endianness is little-endian, second is if native is big-endian
268: #define NATIVE_ENDIAN_VALUE_LE_BE(leval,beval) ENDIAN_VALUE_LE_BE(ENDIANNESS_NATIVE, leval, beval)
269:
270: // endian-based value: first value is if 'endian' matches native, second is if 'endian' doesn't match native
271: #define ENDIAN_VALUE_NE_NNE(endian,leval,beval) (((endian) == ENDIANNESS_NATIVE) ? (neval) : (nneval))
1.1 root 272:
273: /*****************************************************************************/
274: /* src/emu/memory.h */
275:
1.1.1.10 root 276: // address spaces
277: enum address_spacenum
278: {
279: AS_0, // first address space
280: AS_1, // second address space
281: AS_2, // third address space
282: AS_3, // fourth address space
283: ADDRESS_SPACES, // maximum number of address spaces
284:
285: // alternate address space names for common use
286: AS_PROGRAM = AS_0, // program address space
287: AS_DATA = AS_1, // data address space
288: AS_IO = AS_2 // I/O address space
289: };
290:
1.1 root 291: // offsets and addresses are 32-bit (for now...)
1.1.1.30 root 292: //typedef UINT32 offs_t;
1.1 root 293:
294: // read accessors
295: UINT8 read_byte(offs_t byteaddress)
1.1.1.33 root 296: #ifdef USE_DEBUGGER
297: {
298: if(now_debugging) {
299: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
300: if(rd_break_point.table[i].status == 1) {
301: if(byteaddress == rd_break_point.table[i].addr) {
302: rd_break_point.hit = i + 1;
303: now_suspended = true;
304: break;
305: }
306: }
307: }
308: }
309: return(debugger_read_byte(byteaddress));
310: }
311: UINT8 debugger_read_byte(offs_t byteaddress)
312: #endif
1.1 root 313: {
1.1.1.4 root 314: #if defined(HAS_I386)
1.1 root 315: if(byteaddress < MAX_MEM) {
316: return mem[byteaddress];
1.1.1.3 root 317: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
318: // return read_byte(byteaddress & 0xfffff);
1.1 root 319: }
320: return 0;
1.1.1.4 root 321: #else
322: return mem[byteaddress];
323: #endif
1.1 root 324: }
325:
326: UINT16 read_word(offs_t byteaddress)
1.1.1.33 root 327: #ifdef USE_DEBUGGER
328: {
329: if(now_debugging) {
330: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
331: if(rd_break_point.table[i].status == 1) {
332: if(byteaddress >= rd_break_point.table[i].addr && byteaddress < rd_break_point.table[i].addr + 2) {
333: rd_break_point.hit = i + 1;
334: now_suspended = true;
335: break;
336: }
337: }
338: }
339: }
340: return(debugger_read_word(byteaddress));
341: }
342: UINT16 debugger_read_word(offs_t byteaddress)
343: #endif
1.1 root 344: {
1.1.1.14 root 345: if(byteaddress == 0x41c) {
346: // pointer to first free slot in keyboard buffer
347: // XXX: the buffer itself doesn't actually exist in DOS memory
1.1.1.35 root 348: if(key_buf_char != NULL && key_buf_scan != NULL) {
349: #ifdef USE_SERVICE_THREAD
350: EnterCriticalSection(&key_buf_crit_sect);
351: #endif
1.1.1.41! root 352: int count = min(key_buf_char->count(), 15);
! 353: // write to top of key buffer
! 354: for(int i = 0; i < count; i++) {
! 355: mem[0x41e + 2 * i + 0] = key_buf_char->read_not_remove(i);
! 356: mem[0x41e + 2 * i + 1] = key_buf_scan->read_not_remove(i);
! 357: }
1.1.1.35 root 358: #ifdef USE_SERVICE_THREAD
359: LeaveCriticalSection(&key_buf_crit_sect);
360: #endif
361: if(count == 0) {
1.1.1.32 root 362: maybe_idle();
363: }
1.1.1.41! root 364: return (UINT16)(0x1e + 2 * count);
1.1.1.14 root 365: }
1.1.1.41! root 366: return 0x1e;
1.1.1.14 root 367: }
1.1.1.4 root 368: #if defined(HAS_I386)
1.1 root 369: if(byteaddress < MAX_MEM - 1) {
370: return *(UINT16 *)(mem + byteaddress);
1.1.1.3 root 371: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
372: // return read_word(byteaddress & 0xfffff);
1.1 root 373: }
374: return 0;
1.1.1.4 root 375: #else
376: return *(UINT16 *)(mem + byteaddress);
377: #endif
1.1 root 378: }
379:
380: UINT32 read_dword(offs_t byteaddress)
1.1.1.33 root 381: #ifdef USE_DEBUGGER
382: {
383: if(now_debugging) {
384: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
385: if(rd_break_point.table[i].status == 1) {
386: if(byteaddress >= rd_break_point.table[i].addr && byteaddress < rd_break_point.table[i].addr + 4) {
387: rd_break_point.hit = i + 1;
388: now_suspended = true;
389: break;
390: }
391: }
392: }
393: }
394: return(debugger_read_dword(byteaddress));
395: }
396: UINT32 debugger_read_dword(offs_t byteaddress)
397: #endif
1.1 root 398: {
1.1.1.4 root 399: #if defined(HAS_I386)
1.1 root 400: if(byteaddress < MAX_MEM - 3) {
401: return *(UINT32 *)(mem + byteaddress);
1.1.1.3 root 402: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
403: // return read_dword(byteaddress & 0xfffff);
1.1 root 404: }
405: return 0;
1.1.1.4 root 406: #else
407: return *(UINT32 *)(mem + byteaddress);
408: #endif
1.1 root 409: }
410:
411: // write accessors
1.1.1.35 root 412: #ifdef USE_VRAM_THREAD
1.1.1.14 root 413: void vram_flush_char()
414: {
415: if(vram_length_char != 0) {
416: DWORD num;
1.1.1.23 root 417: WriteConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), scr_char, vram_length_char, vram_coord_char, &num);
1.1.1.14 root 418: vram_length_char = vram_last_length_char = 0;
419: }
420: }
421:
422: void vram_flush_attr()
423: {
424: if(vram_length_attr != 0) {
425: DWORD num;
1.1.1.23 root 426: WriteConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE), scr_attr, vram_length_attr, vram_coord_attr, &num);
1.1.1.14 root 427: vram_length_attr = vram_last_length_attr = 0;
428: }
429: }
430:
431: void vram_flush()
432: {
433: if(vram_length_char != 0 || vram_length_attr != 0) {
434: EnterCriticalSection(&vram_crit_sect);
435: vram_flush_char();
436: vram_flush_attr();
437: LeaveCriticalSection(&vram_crit_sect);
438: }
439: }
440: #endif
441:
442: void write_text_vram_char(offs_t offset, UINT8 data)
1.1.1.8 root 443: {
1.1.1.35 root 444: #ifdef USE_VRAM_THREAD
1.1.1.14 root 445: static offs_t first_offset_char, last_offset_char;
446:
447: if(vram_length_char != 0) {
448: if(offset <= last_offset_char && offset >= first_offset_char) {
449: scr_char[(offset - first_offset_char) >> 1] = data;
450: return;
451: }
452: if(offset != last_offset_char + 2) {
453: vram_flush_char();
454: }
455: }
456: if(vram_length_char == 0) {
457: first_offset_char = offset;
458: vram_coord_char.X = (offset >> 1) % scr_width;
459: vram_coord_char.Y = (offset >> 1) / scr_width + scr_top;
460: }
461: scr_char[vram_length_char++] = data;
462: last_offset_char = offset;
463: #else
1.1.1.8 root 464: COORD co;
465: DWORD num;
466:
1.1.1.14 root 467: co.X = (offset >> 1) % scr_width;
468: co.Y = (offset >> 1) / scr_width;
469: scr_char[0] = data;
1.1.1.23 root 470: WriteConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), scr_char, 1, co, &num);
1.1.1.14 root 471: #endif
472: }
473:
474: void write_text_vram_attr(offs_t offset, UINT8 data)
475: {
1.1.1.35 root 476: #ifdef USE_VRAM_THREAD
1.1.1.14 root 477: static offs_t first_offset_attr, last_offset_attr;
478:
479: if(vram_length_attr != 0) {
480: if(offset <= last_offset_attr && offset >= first_offset_attr) {
481: scr_attr[(offset - first_offset_attr) >> 1] = data;
482: return;
483: }
484: if(offset != last_offset_attr + 2) {
485: vram_flush_attr();
486: }
487: }
488: if(vram_length_attr == 0) {
489: first_offset_attr = offset;
490: vram_coord_attr.X = (offset >> 1) % scr_width;
491: vram_coord_attr.Y = (offset >> 1) / scr_width + scr_top;
492: }
493: scr_attr[vram_length_attr++] = data;
494: last_offset_attr = offset;
495: #else
496: COORD co;
497: DWORD num;
1.1.1.8 root 498:
1.1.1.14 root 499: co.X = (offset >> 1) % scr_width;
500: co.Y = (offset >> 1) / scr_width;
501: scr_attr[0] = data;
1.1.1.23 root 502: WriteConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE), scr_attr, 1, co, &num);
1.1.1.14 root 503: #endif
504: }
505:
506: void write_text_vram_byte(offs_t offset, UINT8 data)
507: {
1.1.1.35 root 508: #ifdef USE_VRAM_THREAD
1.1.1.14 root 509: EnterCriticalSection(&vram_crit_sect);
1.1.1.35 root 510: #endif
1.1.1.8 root 511: if(offset & 1) {
1.1.1.14 root 512: write_text_vram_attr(offset, data);
1.1.1.8 root 513: } else {
1.1.1.14 root 514: write_text_vram_char(offset, data);
1.1.1.8 root 515: }
1.1.1.35 root 516: #ifdef USE_VRAM_THREAD
1.1.1.14 root 517: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35 root 518: #endif
1.1.1.8 root 519: }
520:
521: void write_text_vram_word(offs_t offset, UINT16 data)
522: {
1.1.1.35 root 523: #ifdef USE_VRAM_THREAD
1.1.1.14 root 524: EnterCriticalSection(&vram_crit_sect);
1.1.1.35 root 525: #endif
1.1.1.8 root 526: if(offset & 1) {
1.1.1.14 root 527: write_text_vram_attr(offset , (data ) & 0xff);
528: write_text_vram_char(offset + 1, (data >> 8) & 0xff);
1.1.1.8 root 529: } else {
1.1.1.14 root 530: write_text_vram_char(offset , (data ) & 0xff);
531: write_text_vram_attr(offset + 1, (data >> 8) & 0xff);
1.1.1.8 root 532: }
1.1.1.35 root 533: #ifdef USE_VRAM_THREAD
1.1.1.14 root 534: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35 root 535: #endif
1.1.1.8 root 536: }
537:
538: void write_text_vram_dword(offs_t offset, UINT32 data)
539: {
1.1.1.35 root 540: #ifdef USE_VRAM_THREAD
1.1.1.14 root 541: EnterCriticalSection(&vram_crit_sect);
1.1.1.35 root 542: #endif
1.1.1.8 root 543: if(offset & 1) {
1.1.1.14 root 544: write_text_vram_attr(offset , (data ) & 0xff);
545: write_text_vram_char(offset + 1, (data >> 8) & 0xff);
546: write_text_vram_attr(offset + 2, (data >> 16) & 0xff);
547: write_text_vram_char(offset + 3, (data >> 24) & 0xff);
548: } else {
549: write_text_vram_char(offset , (data ) & 0xff);
550: write_text_vram_attr(offset + 1, (data >> 8) & 0xff);
551: write_text_vram_char(offset + 2, (data >> 16) & 0xff);
552: write_text_vram_attr(offset + 3, (data >> 24) & 0xff);
1.1.1.8 root 553: }
1.1.1.35 root 554: #ifdef USE_VRAM_THREAD
1.1.1.14 root 555: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35 root 556: #endif
1.1.1.8 root 557: }
558:
1.1 root 559: void write_byte(offs_t byteaddress, UINT8 data)
1.1.1.33 root 560: #ifdef USE_DEBUGGER
561: {
562: if(now_debugging) {
563: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
564: if(wr_break_point.table[i].status == 1) {
565: if(byteaddress == wr_break_point.table[i].addr) {
566: wr_break_point.hit = i + 1;
567: now_suspended = true;
568: break;
569: }
570: }
571: }
572: }
573: debugger_write_byte(byteaddress, data);
574: }
575: void debugger_write_byte(offs_t byteaddress, UINT8 data)
576: #endif
1.1 root 577: {
1.1.1.8 root 578: if(byteaddress < MEMORY_END) {
1.1.1.3 root 579: mem[byteaddress] = data;
1.1.1.8 root 580: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 581: if(!restore_console_on_exit) {
582: change_console_size(scr_width, scr_height);
1.1.1.12 root 583: }
1.1.1.8 root 584: write_text_vram_byte(byteaddress - text_vram_top_address, data);
585: mem[byteaddress] = data;
586: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
587: if(int_10h_feh_called && !int_10h_ffh_called) {
588: write_text_vram_byte(byteaddress - shadow_buffer_top_address, data);
1.1 root 589: }
590: mem[byteaddress] = data;
1.1.1.4 root 591: #if defined(HAS_I386)
1.1.1.3 root 592: } else if(byteaddress < MAX_MEM) {
1.1.1.4 root 593: #else
594: } else {
595: #endif
1.1.1.3 root 596: mem[byteaddress] = data;
1.1 root 597: }
598: }
599:
600: void write_word(offs_t byteaddress, UINT16 data)
1.1.1.33 root 601: #ifdef USE_DEBUGGER
602: {
603: if(now_debugging) {
604: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
605: if(wr_break_point.table[i].status == 1) {
606: if(byteaddress >= wr_break_point.table[i].addr && byteaddress < wr_break_point.table[i].addr + 2) {
607: wr_break_point.hit = i + 1;
608: now_suspended = true;
609: break;
610: }
611: }
612: }
613: }
614: debugger_write_word(byteaddress, data);
615: }
616: void debugger_write_word(offs_t byteaddress, UINT16 data)
617: #endif
1.1 root 618: {
1.1.1.8 root 619: if(byteaddress < MEMORY_END) {
1.1.1.14 root 620: if(byteaddress == 0x450 + mem[0x462] * 2) {
621: COORD co;
622: co.X = data & 0xff;
623: co.Y = (data >> 8) + scr_top;
1.1.1.23 root 624: SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), co);
1.1.1.14 root 625: }
1.1.1.3 root 626: *(UINT16 *)(mem + byteaddress) = data;
1.1.1.8 root 627: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 628: if(!restore_console_on_exit) {
629: change_console_size(scr_width, scr_height);
1.1.1.12 root 630: }
1.1.1.8 root 631: write_text_vram_word(byteaddress - text_vram_top_address, data);
632: *(UINT16 *)(mem + byteaddress) = data;
633: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
634: if(int_10h_feh_called && !int_10h_ffh_called) {
635: write_text_vram_word(byteaddress - shadow_buffer_top_address, data);
1.1 root 636: }
637: *(UINT16 *)(mem + byteaddress) = data;
1.1.1.4 root 638: #if defined(HAS_I386)
1.1.1.3 root 639: } else if(byteaddress < MAX_MEM - 1) {
1.1.1.4 root 640: #else
641: } else {
642: #endif
1.1.1.3 root 643: *(UINT16 *)(mem + byteaddress) = data;
1.1 root 644: }
645: }
646:
647: void write_dword(offs_t byteaddress, UINT32 data)
1.1.1.33 root 648: #ifdef USE_DEBUGGER
649: {
650: if(now_debugging) {
651: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
652: if(wr_break_point.table[i].status == 1) {
653: if(byteaddress >= wr_break_point.table[i].addr && byteaddress < wr_break_point.table[i].addr + 4) {
654: wr_break_point.hit = i + 1;
655: now_suspended = true;
656: break;
657: }
658: }
659: }
660: }
661: debugger_write_dword(byteaddress, data);
662: }
663: void debugger_write_dword(offs_t byteaddress, UINT32 data)
664: #endif
1.1 root 665: {
1.1.1.8 root 666: if(byteaddress < MEMORY_END) {
1.1.1.3 root 667: *(UINT32 *)(mem + byteaddress) = data;
1.1.1.8 root 668: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 669: if(!restore_console_on_exit) {
670: change_console_size(scr_width, scr_height);
1.1.1.12 root 671: }
1.1.1.8 root 672: write_text_vram_dword(byteaddress - text_vram_top_address, data);
673: *(UINT32 *)(mem + byteaddress) = data;
674: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
675: if(int_10h_feh_called && !int_10h_ffh_called) {
676: write_text_vram_dword(byteaddress - shadow_buffer_top_address, data);
1.1 root 677: }
678: *(UINT32 *)(mem + byteaddress) = data;
1.1.1.4 root 679: #if defined(HAS_I386)
1.1.1.3 root 680: } else if(byteaddress < MAX_MEM - 3) {
1.1.1.4 root 681: #else
682: } else {
683: #endif
1.1.1.3 root 684: *(UINT32 *)(mem + byteaddress) = data;
1.1 root 685: }
686: }
687:
688: #define read_decrypted_byte read_byte
689: #define read_decrypted_word read_word
690: #define read_decrypted_dword read_dword
691:
1.1.1.3 root 692: #define read_raw_byte read_byte
693: #define write_raw_byte write_byte
694:
695: #define read_word_unaligned read_word
696: #define write_word_unaligned write_word
697:
698: #define read_io_word_unaligned read_io_word
699: #define write_io_word_unaligned write_io_word
700:
1.1 root 701: UINT8 read_io_byte(offs_t byteaddress);
702: UINT16 read_io_word(offs_t byteaddress);
703: UINT32 read_io_dword(offs_t byteaddress);
704:
705: void write_io_byte(offs_t byteaddress, UINT8 data);
706: void write_io_word(offs_t byteaddress, UINT16 data);
707: void write_io_dword(offs_t byteaddress, UINT32 data);
708:
709: /*****************************************************************************/
710: /* src/osd/osdcomm.h */
711:
712: /* Highly useful macro for compile-time knowledge of an array size */
713: #define ARRAY_LENGTH(x) (sizeof(x) / sizeof(x[0]))
714:
1.1.1.3 root 715: #if defined(HAS_I386)
1.1.1.10 root 716: static CPU_TRANSLATE(i386);
717: #include "mame/lib/softfloat/softfloat.c"
718: #include "mame/emu/cpu/i386/i386.c"
1.1.1.12 root 719: #include "mame/emu/cpu/vtlb.c"
1.1.1.3 root 720: #elif defined(HAS_I286)
1.1.1.10 root 721: #include "mame/emu/cpu/i86/i286.c"
1.1.1.3 root 722: #else
1.1.1.10 root 723: #include "mame/emu/cpu/i86/i86.c"
1.1.1.3 root 724: #endif
1.1.1.33 root 725: #ifdef USE_DEBUGGER
1.1.1.10 root 726: #include "mame/emu/cpu/i386/i386dasm.c"
1.1 root 727: #endif
728:
1.1.1.3 root 729: #if defined(HAS_I386)
730: #define SREG(x) m_sreg[x].selector
731: #define SREG_BASE(x) m_sreg[x].base
732: int cpu_type, cpu_step;
733: #else
734: #define REG8(x) m_regs.b[x]
735: #define REG16(x) m_regs.w[x]
736: #define SREG(x) m_sregs[x]
737: #define SREG_BASE(x) m_base[x]
1.1.1.33 root 738: #define m_eip (m_pc - m_base[CS])
1.1.1.3 root 739: #define m_CF m_CarryVal
740: #define m_a20_mask AMASK
741: #define i386_load_segment_descriptor(x) m_base[x] = SegBase(x)
742: #if defined(HAS_I286)
743: #define i386_set_a20_line(x) i80286_set_a20_line(x)
744: #else
745: #define i386_set_a20_line(x)
746: #endif
747: #define i386_set_irq_line(x, y) set_irq_line(x, y)
748: #endif
1.1 root 749:
750: void i386_jmp_far(UINT16 selector, UINT32 address)
751: {
1.1.1.3 root 752: #if defined(HAS_I386)
1.1 root 753: if(PROTECTED_MODE && !V8086_MODE) {
1.1.1.3 root 754: i386_protected_mode_jump(selector, address, 1, m_operand_size);
1.1 root 755: } else {
1.1.1.3 root 756: SREG(CS) = selector;
757: m_performed_intersegment_jump = 1;
758: i386_load_segment_descriptor(CS);
759: m_eip = address;
760: CHANGE_PC(m_eip);
1.1 root 761: }
1.1.1.3 root 762: #elif defined(HAS_I286)
763: i80286_code_descriptor(selector, address, 1);
764: #else
765: SREG(CS) = selector;
766: i386_load_segment_descriptor(CS);
767: m_pc = (SREG_BASE(CS) + address) & m_a20_mask;
768: #endif
1.1 root 769: }
770:
1.1.1.35 root 771: #ifdef USE_SERVICE_THREAD
1.1.1.24 root 772: void i386_call_far(UINT16 selector, UINT32 address)
773: {
774: #if defined(HAS_I386)
775: if(PROTECTED_MODE && !V8086_MODE) {
776: i386_protected_mode_call(selector, address, 1, m_operand_size);
777: } else {
778: PUSH16(SREG(CS));
779: PUSH16(m_eip);
780: SREG(CS) = selector;
781: m_performed_intersegment_jump = 1;
782: i386_load_segment_descriptor(CS);
783: m_eip = address;
784: CHANGE_PC(m_eip);
785: }
786: #else
787: UINT16 ip = m_pc - SREG_BASE(CS);
788: UINT16 cs = SREG(CS);
789: #if defined(HAS_I286)
790: i80286_code_descriptor(selector, address, 2);
791: #else
792: SREG(CS) = selector;
793: i386_load_segment_descriptor(CS);
794: m_pc = (SREG_BASE(CS) + address) & m_a20_mask;
795: #endif
796: PUSH(cs);
797: PUSH(ip);
798: CHANGE_PC(m_pc);
799: #endif
800: }
1.1.1.35 root 801: #endif
1.1.1.24 root 802:
1.1.1.29 root 803: UINT16 i386_read_stack()
804: {
805: #if defined(HAS_I386)
806: UINT32 ea, new_esp;
807: if( STACK_32BIT ) {
808: new_esp = REG32(ESP) + 2;
809: ea = i386_translate(SS, new_esp - 2, 0);
810: } else {
811: new_esp = REG16(SP) + 2;
812: ea = i386_translate(SS, (new_esp - 2) & 0xffff, 0);
813: }
814: return READ16(ea);
815: #else
816: UINT16 sp = m_regs.w[SP] + 2;
817: return ReadWord(((m_base[SS] + ((sp - 2) & 0xffff)) & AMASK));
818: #endif
819: }
820:
1.1 root 821: /* ----------------------------------------------------------------------------
1.1.1.33 root 822: debugger
823: ---------------------------------------------------------------------------- */
824:
825: #ifdef USE_DEBUGGER
826: #define TELNET_BLUE 0x0004 // text color contains blue.
827: #define TELNET_GREEN 0x0002 // text color contains green.
828: #define TELNET_RED 0x0001 // text color contains red.
829: #define TELNET_INTENSITY 0x0008 // text color is intensified.
830:
831: int svr_socket = 0;
832: int cli_socket = 0;
833:
834: process_t *msdos_process_info_get(UINT16 psp_seg, bool show_error);
835:
836: void debugger_init()
837: {
838: now_debugging = false;
839: now_going = false;
840: now_suspended = false;
841: force_suspend = false;
842:
843: memset(&break_point, 0, sizeof(break_point_t));
844: memset(&rd_break_point, 0, sizeof(break_point_t));
845: memset(&wr_break_point, 0, sizeof(break_point_t));
846: memset(&in_break_point, 0, sizeof(break_point_t));
847: memset(&out_break_point, 0, sizeof(break_point_t));
848: memset(&int_break_point, 0, sizeof(int_break_point_t));
849: }
850:
851: void telnet_send(char *string)
852: {
853: char buffer[8192], *ptr;
854: strcpy(buffer, string);
855: while((ptr = strstr(buffer, "\n")) != NULL) {
856: char tmp[8192];
857: *ptr = '\0';
858: sprintf(tmp, "%s\033E%s", buffer, ptr + 1);
859: strcpy(buffer, tmp);
860: }
861:
862: int len = strlen(buffer), res;
863: ptr = buffer;
864: while(len > 0) {
865: if((res = send(cli_socket, ptr, len, 0)) > 0) {
866: len -= res;
867: ptr += res;
868: }
869: }
870: }
871:
872: void telnet_command(const char *format, ...)
873: {
874: char buffer[1024];
875: va_list ap;
876: va_start(ap, format);
877: vsprintf(buffer, format, ap);
878: va_end(ap);
879:
880: telnet_send(buffer);
881: }
882:
883: void telnet_printf(const char *format, ...)
884: {
885: char buffer[1024];
886: va_list ap;
887: va_start(ap, format);
888: vsprintf(buffer, format, ap);
889: va_end(ap);
890:
891: if(fp_debugger != NULL) {
892: fprintf(fp_debugger, "%s", buffer);
893: }
894: telnet_send(buffer);
895: }
896:
897: bool telnet_gets(char *str, int n)
898: {
899: char buffer[1024];
900: int ptr = 0;
901:
902: telnet_command("\033[12l"); // local echo on
903: telnet_command("\033[2l"); // key unlock
904:
905: while(!m_halted) {
906: int len = recv(cli_socket, buffer, sizeof(buffer), 0);
907:
908: if(len > 0 && buffer[0] != 0xff) {
909: for(int i = 0; i < len; i++) {
910: if(buffer[i] == 0x0d || buffer[i] == 0x0a) {
911: str[ptr] = 0;
912: telnet_command("\033[2h"); // key lock
913: telnet_command("\033[12h"); // local echo off
914: return(!m_halted);
915: } else if(buffer[i] == 0x08) {
916: if(ptr > 0) {
917: telnet_command("\033[0K"); // erase from cursor position
918: ptr--;
919: } else {
920: telnet_command("\033[1C"); // move cursor forward
921: }
922: } else if(ptr < n - 1) {
1.1.1.37 root 923: if(buffer[i] >= 0x20 && buffer[i] <= 0x7e) {
1.1.1.33 root 924: str[ptr++] = buffer[i];
925: }
926: } else {
927: telnet_command("\033[1D\033[0K"); // move cursor backward and erase from cursor position
928: }
929: }
930: } else if(len == -1) {
931: if(WSAGetLastError() != WSAEWOULDBLOCK) {
932: return(false);
933: }
934: } else if(len == 0) {
935: return(false);
936: }
937: Sleep(10);
938: }
939: return(!m_halted);
940: }
941:
942: bool telnet_kbhit()
943: {
944: char buffer[1024];
945:
946: if(!m_halted) {
947: int len = recv(cli_socket, buffer, sizeof(buffer), 0);
948:
949: if(len > 0) {
950: for(int i = 0; i < len; i++) {
951: if(buffer[i] == 0x0d || buffer[i] == 0x0a) {
952: return(true);
953: }
954: }
955: } else if(len == 0) {
956: return(true); // disconnected
957: }
958: }
959: return(false);
960: }
961:
962: bool telnet_disconnected()
963: {
964: char buffer[1024];
965: int len = recv(cli_socket, buffer, sizeof(buffer), 0);
966:
967: if(len == 0) {
968: return(true);
969: } else if(len == -1) {
970: if(WSAGetLastError() != WSAEWOULDBLOCK) {
971: return(true);
972: }
973: }
974: return(false);
975: }
976:
977: void telnet_set_color(int color)
978: {
979: telnet_command("\033[%dm\033[3%dm", (color >> 3) & 1, (color & 7));
980: }
981:
982: int debugger_dasm(char *buffer, UINT32 cs, UINT32 eip)
983: {
984: // UINT8 *oprom = mem + (((cs << 4) + eip) & (MAX_MEM - 1));
985: UINT8 ops[16];
986: for(int i = 0; i < 16; i++) {
987: ops[i] = debugger_read_byte(((cs << 4) + (eip + i)) & ADDR_MASK);
988: }
989: UINT8 *oprom = ops;
990:
991: #if defined(HAS_I386)
992: if(m_operand_size) {
993: return(CPU_DISASSEMBLE_CALL(x86_32) & DASMFLAG_LENGTHMASK);
994: } else
995: #endif
996: return(CPU_DISASSEMBLE_CALL(x86_16) & DASMFLAG_LENGTHMASK);
997: }
998:
999: void debugger_regs_info(char *buffer)
1000: {
1001: #if defined(HAS_I386)
1002: UINT32 flags = get_flags();
1003: #else
1004: UINT32 flags = CompressFlags();
1005: #endif
1006: #if defined(HAS_I386)
1007: if(m_operand_size) {
1008: 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",
1009: 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),
1010: PROTECTED_MODE ? "PE" : "--",
1011: (flags & 0x40000) ? 'A' : '-',
1012: (flags & 0x20000) ? 'V' : '-',
1013: (flags & 0x10000) ? 'R' : '-',
1014: (flags & 0x04000) ? 'N' : '-',
1015: (flags & 0x02000) ? '1' : '0',
1016: (flags & 0x01000) ? '1' : '0',
1017: (flags & 0x00800) ? 'O' : '-',
1018: (flags & 0x00400) ? 'D' : '-',
1019: (flags & 0x00200) ? 'I' : '-',
1020: (flags & 0x00100) ? 'T' : '-',
1021: (flags & 0x00080) ? 'S' : '-',
1022: (flags & 0x00040) ? 'Z' : '-',
1023: (flags & 0x00010) ? 'A' : '-',
1024: (flags & 0x00004) ? 'P' : '-',
1025: (flags & 0x00001) ? 'C' : '-');
1026: } else {
1027: #endif
1028: 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",
1029: 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),
1030: #if defined(HAS_I386)
1031: PROTECTED_MODE ? "PE" : "--",
1032: #else
1033: "--",
1034: #endif
1035: (flags & 0x40000) ? 'A' : '-',
1036: (flags & 0x20000) ? 'V' : '-',
1037: (flags & 0x10000) ? 'R' : '-',
1038: (flags & 0x04000) ? 'N' : '-',
1039: (flags & 0x02000) ? '1' : '0',
1040: (flags & 0x01000) ? '1' : '0',
1041: (flags & 0x00800) ? 'O' : '-',
1042: (flags & 0x00400) ? 'D' : '-',
1043: (flags & 0x00200) ? 'I' : '-',
1044: (flags & 0x00100) ? 'T' : '-',
1045: (flags & 0x00080) ? 'S' : '-',
1046: (flags & 0x00040) ? 'Z' : '-',
1047: (flags & 0x00010) ? 'A' : '-',
1048: (flags & 0x00004) ? 'P' : '-',
1049: (flags & 0x00001) ? 'C' : '-');
1050: #if defined(HAS_I386)
1051: }
1052: #endif
1053: }
1054:
1055: void debugger_process_info(char *buffer)
1056: {
1057: UINT16 psp_seg = current_psp;
1058: process_t *process;
1059: bool check[0x10000] = {0};
1060:
1061: buffer[0] = '\0';
1062:
1063: while(!check[psp_seg] && (process = msdos_process_info_get(psp_seg, false)) != NULL) {
1064: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
1065: char *file = process->module_path, *s;
1066: char tmp[8192];
1067:
1068: while((s = strstr(file, "\\")) != NULL) {
1069: file = s + 1;
1070: }
1071: 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));
1072: strcat(tmp, buffer);
1073: strcpy(buffer, tmp);
1074:
1075: check[psp_seg] = true;
1076: psp_seg = psp->parent_psp;
1077: }
1078: }
1079:
1080: UINT32 debugger_get_val(const char *str)
1081: {
1082: char tmp[1024];
1083:
1084: if(str == NULL || strlen(str) == 0) {
1085: return(0);
1086: }
1087: strcpy(tmp, str);
1088:
1089: if(strlen(tmp) == 3 && tmp[0] == '\'' && tmp[2] == '\'') {
1090: // ank
1091: return(tmp[1] & 0xff);
1092: } else if(tmp[0] == '%') {
1093: // decimal
1094: return(strtoul(tmp + 1, NULL, 10));
1095: }
1096: return(strtoul(tmp, NULL, 16));
1097: }
1098:
1099: UINT32 debugger_get_seg(const char *str, UINT32 val)
1100: {
1101: char tmp[1024], *s;
1102:
1103: if(str == NULL || strlen(str) == 0) {
1104: return(val);
1105: }
1106: strcpy(tmp, str);
1107:
1108: if((s = strstr(tmp, ":")) != NULL) {
1109: // 0000:0000
1110: *s = '\0';
1111: return(debugger_get_val(tmp));
1112: }
1113: return(val);
1114: }
1115:
1116: UINT32 debugger_get_ofs(const char *str)
1117: {
1118: char tmp[1024], *s;
1119:
1120: if(str == NULL || strlen(str) == 0) {
1121: return(0);
1122: }
1123: strcpy(tmp, str);
1124:
1125: if((s = strstr(tmp, ":")) != NULL) {
1126: // 0000:0000
1127: return(debugger_get_val(s + 1));
1128: }
1129: return(debugger_get_val(tmp));
1130: }
1131:
1132: void debugger_main()
1133: {
1134: telnet_command("\033[20h"); // cr-lf
1135:
1136: force_suspend = true;
1137: now_going = false;
1138: now_debugging = true;
1139: Sleep(100);
1140:
1141: if(!m_halted && !now_suspended) {
1142: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1143: telnet_printf("waiting until cpu is suspended...\n");
1144: }
1145: while(!m_halted && !now_suspended) {
1146: if(telnet_disconnected()) {
1147: break;
1148: }
1149: Sleep(10);
1150: }
1151:
1152: char buffer[8192];
1153:
1154: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1155: debugger_process_info(buffer);
1156: telnet_printf("%s", buffer);
1157: debugger_regs_info(buffer);
1158: telnet_printf("%s", buffer);
1159: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1160: telnet_printf("breaked at %04X:%04X\n", SREG(CS), m_eip);
1161: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1162: debugger_dasm(buffer, SREG(CS), m_eip);
1163: telnet_printf("next\t%04X:%04X %s\n", SREG(CS), m_eip, buffer);
1164: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1165:
1166: #define MAX_COMMAND_LEN 64
1167:
1168: char command[MAX_COMMAND_LEN + 1];
1169: char prev_command[MAX_COMMAND_LEN + 1] = {0};
1170:
1171: UINT32 data_seg = SREG(DS);
1172: UINT32 data_ofs = 0;
1173: UINT32 dasm_seg = SREG(CS);
1174: UINT32 dasm_ofs = m_eip;
1175:
1176: while(!m_halted) {
1177: telnet_printf("- ");
1178: command[0] = '\0';
1179:
1180: if(fi_debugger != NULL) {
1181: while(command[0] == '\0') {
1182: if(fgets(command, sizeof(command), fi_debugger) == NULL) {
1183: break;
1184: }
1185: while(strlen(command) > 0 && (command[strlen(command) - 1] == 0x0d || command[strlen(command) - 1] == 0x0a)) {
1186: command[strlen(command) - 1] = '\0';
1187: }
1188: }
1189: if(command[0] != '\0') {
1190: telnet_command("%s\n", command);
1191: }
1192: }
1193: if(command[0] == '\0') {
1194: if(!telnet_gets(command, sizeof(command))) {
1195: break;
1196: }
1197: }
1198: if(command[0] == '\0') {
1199: strcpy(command, prev_command);
1200: } else {
1201: strcpy(prev_command, command);
1202: }
1203: if(fp_debugger != NULL) {
1204: fprintf(fp_debugger, "%s\n", command);
1205: }
1206:
1207: if(!m_halted && command[0] != 0) {
1208: char *params[32], *token = NULL;
1209: int num = 0;
1210:
1211: if((token = strtok(command, " ")) != NULL) {
1212: params[num++] = token;
1213: while(num < 32 && (token = strtok(NULL, " ")) != NULL) {
1214: params[num++] = token;
1215: }
1216: }
1217: if(stricmp(params[0], "D") == 0) {
1218: if(num <= 3) {
1219: if(num >= 2) {
1220: data_seg = debugger_get_seg(params[1], data_seg);
1221: data_ofs = debugger_get_ofs(params[1]);
1222: }
1223: UINT32 end_seg = data_seg;
1224: UINT32 end_ofs = data_ofs + 8 * 16 - 1;
1225: if(num == 3) {
1226: end_seg = debugger_get_seg(params[2], data_seg);
1227: end_ofs = debugger_get_ofs(params[2]);
1228: }
1229: UINT64 start_addr = (data_seg << 4) + data_ofs;
1230: UINT64 end_addr = (end_seg << 4) + end_ofs;
1.1.1.37 root 1231: // bool is_sjis = false;
1.1.1.33 root 1232:
1233: for(UINT64 addr = (start_addr & ~0x0f); addr <= (end_addr | 0x0f); addr++) {
1234: if((addr & 0x0f) == 0) {
1235: if((data_ofs = addr - (data_seg << 4)) > 0xffff) {
1236: data_seg += 0x1000;
1237: data_ofs -= 0x10000;
1238: }
1239: telnet_printf("%06X:%04X ", data_seg, data_ofs);
1240: memset(buffer, 0, sizeof(buffer));
1241: }
1242: if(addr < start_addr || addr > end_addr) {
1243: telnet_printf(" ");
1244: buffer[addr & 0x0f] = ' ';
1245: } else {
1246: UINT8 data = debugger_read_byte(addr & ADDR_MASK);
1247: telnet_printf(" %02X", data);
1.1.1.37 root 1248: // if(is_sjis) {
1.1.1.33 root 1249: // buffer[addr & 0x0f] = data;
1.1.1.37 root 1250: // is_sjis = false;
1.1.1.33 root 1251: // } else if(((data >= 0x81 && data <= 0x9f) || (data >= 0xe0 && data <= 0xef)) && (addr & 0x0f) < 0x0f) {
1252: // buffer[addr & 0x0f] = data;
1.1.1.37 root 1253: // is_sjis = true;
1.1.1.33 root 1254: // } else
1255: if((data >= 0x20 && data <= 0x7e)/* || (data >= 0xa1 && data <= 0xdf)*/) {
1256: buffer[addr & 0x0f] = data;
1257: } else {
1258: buffer[addr & 0x0f] = '.';
1259: }
1260: }
1261: if((addr & 0x0f) == 0x0f) {
1262: telnet_printf(" %s\n", buffer);
1263: }
1264: }
1265: if((data_ofs = (end_addr + 1) - (data_seg << 4)) > 0xffff) {
1266: data_seg += 0x1000;
1267: data_ofs -= 0x10000;
1268: }
1269: prev_command[1] = '\0'; // remove parameters to dump continuously
1270: } else {
1271: telnet_printf("invalid parameter number\n");
1272: }
1273: } else if(stricmp(params[0], "E") == 0 || stricmp(params[0], "EB") == 0) {
1274: if(num >= 3) {
1275: UINT32 seg = debugger_get_seg(params[1], data_seg);
1276: UINT32 ofs = debugger_get_ofs(params[1]);
1277: for(int i = 2, j = 0; i < num; i++, j++) {
1278: debugger_write_byte(((seg << 4) + (ofs + j)) & ADDR_MASK, debugger_get_val(params[i]) & 0xff);
1279: }
1280: } else {
1281: telnet_printf("invalid parameter number\n");
1282: }
1283: } else if(stricmp(params[0], "EW") == 0) {
1284: if(num >= 3) {
1285: UINT32 seg = debugger_get_seg(params[1], data_seg);
1286: UINT32 ofs = debugger_get_ofs(params[1]);
1287: for(int i = 2, j = 0; i < num; i++, j += 2) {
1288: debugger_write_word(((seg << 4) + (ofs + j)) & ADDR_MASK, debugger_get_val(params[i]) & 0xffff);
1289: }
1290: } else {
1291: telnet_printf("invalid parameter number\n");
1292: }
1293: } else if(stricmp(params[0], "ED") == 0) {
1294: if(num >= 3) {
1295: UINT32 seg = debugger_get_seg(params[1], data_seg);
1296: UINT32 ofs = debugger_get_ofs(params[1]);
1297: for(int i = 2, j = 0; i < num; i++, j += 4) {
1298: debugger_write_dword(((seg << 4) + (ofs + j)) & ADDR_MASK, debugger_get_val(params[i]));
1299: }
1300: } else {
1301: telnet_printf("invalid parameter number\n");
1302: }
1303: } else if(stricmp(params[0], "EA") == 0) {
1304: if(num >= 3) {
1305: UINT32 seg = debugger_get_seg(params[1], data_seg);
1306: UINT32 ofs = debugger_get_ofs(params[1]);
1307: strcpy(buffer, prev_command);
1308: if((token = strtok(buffer, "\"")) != NULL && (token = strtok(NULL, "\"")) != NULL) {
1309: int len = strlen(token);
1310: for(int i = 0; i < len; i++) {
1311: debugger_write_byte(((seg << 4) + (ofs + i)) & ADDR_MASK, token[i] & 0xff);
1312: }
1313: } else {
1314: telnet_printf("invalid parameter\n");
1315: }
1316: } else {
1317: telnet_printf("invalid parameter number\n");
1318: }
1319: } else if(stricmp(params[0], "I") == 0 || stricmp(params[0], "IB") == 0) {
1320: if(num == 2) {
1321: telnet_printf("%02X\n", debugger_read_io_byte(debugger_get_val(params[1])) & 0xff);
1322: } else {
1323: telnet_printf("invalid parameter number\n");
1324: }
1325: } else if(stricmp(params[0], "IW") == 0) {
1326: if(num == 2) {
1327: telnet_printf("%04X\n", debugger_read_io_word(debugger_get_val(params[1])) & 0xffff);
1328: } else {
1329: telnet_printf("invalid parameter number\n");
1330: }
1331: } else if(stricmp(params[0], "ID") == 0) {
1332: if(num == 2) {
1333: telnet_printf("%08X\n", debugger_read_io_dword(debugger_get_val(params[1])));
1334: } else {
1335: telnet_printf("invalid parameter number\n");
1336: }
1337: } else if(stricmp(params[0], "O") == 0 || stricmp(params[0], "OB") == 0) {
1338: if(num == 3) {
1339: debugger_write_io_byte(debugger_get_val(params[1]), debugger_get_val(params[2]) & 0xff);
1340: } else {
1341: telnet_printf("invalid parameter number\n");
1342: }
1343: } else if(stricmp(params[0], "OW") == 0) {
1344: if(num == 3) {
1345: debugger_write_io_word(debugger_get_val(params[1]), debugger_get_val(params[2]) & 0xffff);
1346: } else {
1347: telnet_printf("invalid parameter number\n");
1348: }
1349: } else if(stricmp(params[0], "OD") == 0) {
1350: if(num == 3) {
1351: debugger_write_io_dword(debugger_get_val(params[1]), debugger_get_val(params[2]));
1352: } else {
1353: telnet_printf("invalid parameter number\n");
1354: }
1355: } else if(stricmp(params[0], "R") == 0) {
1356: if(num == 1) {
1357: debugger_regs_info(buffer);
1358: telnet_printf("%s", buffer);
1359: } else if(num == 3) {
1360: #if defined(HAS_I386)
1361: if(stricmp(params[1], "EAX") == 0) {
1362: REG32(EAX) = debugger_get_val(params[2]);
1363: } else if(stricmp(params[1], "EBX") == 0) {
1364: REG32(EBX) = debugger_get_val(params[2]);
1365: } else if(stricmp(params[1], "ECX") == 0) {
1366: REG32(ECX) = debugger_get_val(params[2]);
1367: } else if(stricmp(params[1], "EDX") == 0) {
1368: REG32(EDX) = debugger_get_val(params[2]);
1369: } else if(stricmp(params[1], "ESP") == 0) {
1370: REG32(ESP) = debugger_get_val(params[2]);
1371: } else if(stricmp(params[1], "EBP") == 0) {
1372: REG32(EBP) = debugger_get_val(params[2]);
1373: } else if(stricmp(params[1], "ESI") == 0) {
1374: REG32(ESI) = debugger_get_val(params[2]);
1375: } else if(stricmp(params[1], "EDI") == 0) {
1376: REG32(EDI) = debugger_get_val(params[2]);
1377: } else
1378: #endif
1379: if(stricmp(params[1], "AX") == 0) {
1380: REG16(AX) = debugger_get_val(params[2]);
1381: } else if(stricmp(params[1], "BX") == 0) {
1382: REG16(BX) = debugger_get_val(params[2]);
1383: } else if(stricmp(params[1], "CX") == 0) {
1384: REG16(CX) = debugger_get_val(params[2]);
1385: } else if(stricmp(params[1], "DX") == 0) {
1386: REG16(DX) = debugger_get_val(params[2]);
1387: } else if(stricmp(params[1], "SP") == 0) {
1388: REG16(SP) = debugger_get_val(params[2]);
1389: } else if(stricmp(params[1], "BP") == 0) {
1390: REG16(BP) = debugger_get_val(params[2]);
1391: } else if(stricmp(params[1], "SI") == 0) {
1392: REG16(SI) = debugger_get_val(params[2]);
1393: } else if(stricmp(params[1], "DI") == 0) {
1394: REG16(DI) = debugger_get_val(params[2]);
1395: } else if(stricmp(params[1], "IP") == 0 || stricmp(params[1], "EIP") == 0) {
1396: #if defined(HAS_I386)
1397: if(m_operand_size) {
1398: m_eip = debugger_get_val(params[2]);
1399: } else {
1400: m_eip = debugger_get_val(params[2]) & 0xffff;
1401: }
1402: CHANGE_PC(m_eip);
1403: #else
1404: m_pc = (SREG_BASE(CS) + (debugger_get_val(params[2]) & 0xffff)) & ADDR_MASK;
1405: CHANGE_PC(m_pc);
1406: #endif
1407: } else if(stricmp(params[1], "AL") == 0) {
1408: REG8(AL) = debugger_get_val(params[2]);
1409: } else if(stricmp(params[1], "AH") == 0) {
1410: REG8(AH) = debugger_get_val(params[2]);
1411: } else if(stricmp(params[1], "BL") == 0) {
1412: REG8(BL) = debugger_get_val(params[2]);
1413: } else if(stricmp(params[1], "BH") == 0) {
1414: REG8(BH) = debugger_get_val(params[2]);
1415: } else if(stricmp(params[1], "CL") == 0) {
1416: REG8(CL) = debugger_get_val(params[2]);
1417: } else if(stricmp(params[1], "CH") == 0) {
1418: REG8(CH) = debugger_get_val(params[2]);
1419: } else if(stricmp(params[1], "DL") == 0) {
1420: REG8(DL) = debugger_get_val(params[2]);
1421: } else if(stricmp(params[1], "DH") == 0) {
1422: REG8(DH) = debugger_get_val(params[2]);
1423: } else {
1424: telnet_printf("unknown register %s\n", params[1]);
1425: }
1426: } else {
1427: telnet_printf("invalid parameter number\n");
1428: }
1429: } else if(_tcsicmp(params[0], "S") == 0) {
1430: if(num >= 4) {
1431: UINT32 cur_seg = debugger_get_seg(params[1], data_seg);
1432: UINT32 cur_ofs = debugger_get_ofs(params[1]);
1433: UINT32 end_seg = debugger_get_seg(params[2], cur_seg);
1434: UINT32 end_ofs = debugger_get_ofs(params[2]);
1435: UINT8 list[32];
1436:
1437: for(int i = 3, j = 0; i < num && j < 32; i++, j++) {
1438: list[j] = debugger_get_val(params[i]);
1439: }
1440: while((cur_seg << 4) + cur_ofs <= (end_seg << 4) + end_ofs) {
1441: bool found = true;
1442: for(int i = 3, j = 0; i < num && j < 32; i++, j++) {
1443: if(debugger_read_byte(((cur_seg << 4) + (cur_ofs + j)) & ADDR_MASK) != list[j]) {
1444: found = false;
1445: break;
1446: }
1447: }
1448: if(found) {
1449: telnet_printf("%04X:%04X\n", cur_seg, cur_ofs);
1450: }
1451: if((cur_ofs += 1) > 0xffff) {
1452: cur_seg += 0x1000;
1453: cur_ofs -= 0x10000;
1454: }
1455: }
1456: } else {
1457: telnet_printf("invalid parameter number\n");
1458: }
1459: } else if(stricmp(params[0], "U") == 0) {
1460: if(num <= 3) {
1461: if(num >= 2) {
1462: dasm_seg = debugger_get_seg(params[1], dasm_seg);
1463: dasm_ofs = debugger_get_ofs(params[1]);
1464: }
1465: if(num == 3) {
1466: UINT32 end_seg = debugger_get_seg(params[2], dasm_seg);
1467: UINT32 end_ofs = debugger_get_ofs(params[2]);
1468:
1469: while((dasm_seg << 4) + dasm_ofs <= (end_seg << 4) + end_ofs) {
1470: int len = debugger_dasm(buffer, dasm_seg, dasm_ofs);
1471: telnet_printf("%04X:%04X ", dasm_seg, dasm_ofs);
1472: for(int i = 0; i < len; i++) {
1473: telnet_printf("%02X", debugger_read_byte(((dasm_seg << 4) + (dasm_ofs + i)) & ADDR_MASK));
1474: }
1475: for(int i = len; i < 8; i++) {
1476: telnet_printf(" ");
1477: }
1478: telnet_printf(" %s\n", buffer);
1479: if((dasm_ofs += len) > 0xffff) {
1480: dasm_seg += 0x1000;
1481: dasm_ofs -= 0x10000;
1482: }
1483: }
1484: } else {
1485: for(int i = 0; i < 16; i++) {
1486: int len = debugger_dasm(buffer, dasm_seg, dasm_ofs);
1487: telnet_printf("%04X:%04X ", dasm_seg, dasm_ofs);
1488: for(int i = 0; i < len; i++) {
1489: telnet_printf("%02X", debugger_read_byte(((dasm_seg << 4) + (dasm_ofs + i)) & ADDR_MASK));
1490: }
1491: for(int i = len; i < 8; i++) {
1492: telnet_printf(" ");
1493: }
1494: telnet_printf(" %s\n", buffer);
1495: if((dasm_ofs += len) > 0xffff) {
1496: dasm_seg += 0x1000;
1497: dasm_ofs -= 0x10000;
1498: }
1499: }
1500: }
1501: prev_command[1] = '\0'; // remove parameters to disassemble continuously
1502: } else {
1503: telnet_printf("invalid parameter number\n");
1504: }
1505: } else if(stricmp(params[0], "H") == 0) {
1506: if(num == 3) {
1507: UINT32 l = debugger_get_val(params[1]);
1508: UINT32 r = debugger_get_val(params[2]);
1509: telnet_printf("%08X %08X\n", l + r, l - r);
1510: } else {
1511: telnet_printf("invalid parameter number\n");
1512: }
1513: } else if(stricmp(params[0], "BP") == 0 || stricmp(params[0], "RBP") == 0 || stricmp(params[0], "WBP") == 0) {
1514: break_point_t *break_point_ptr;
1515: #define GET_BREAK_POINT_PTR() { \
1516: if(params[0][0] == 'R') { \
1517: break_point_ptr = &rd_break_point; \
1518: } else if(params[0][0] == 'W') { \
1519: break_point_ptr = &wr_break_point; \
1520: } else if(params[0][0] == 'I') { \
1521: break_point_ptr = &in_break_point; \
1522: } else if(params[0][0] == 'O') { \
1523: break_point_ptr = &out_break_point; \
1524: } else { \
1525: break_point_ptr = &break_point; \
1526: } \
1527: }
1528: GET_BREAK_POINT_PTR();
1529: if(num == 2) {
1530: UINT32 seg = debugger_get_seg(params[1], SREG(CS));
1531: UINT32 ofs = debugger_get_ofs(params[1]);
1532: bool found = false;
1533: for(int i = 0; i < MAX_BREAK_POINTS && !found; i++) {
1534: if(break_point_ptr->table[i].status == 0 || break_point_ptr->table[i].addr == ((seg << 4) + ofs)) {
1535: break_point_ptr->table[i].addr = (seg << 4) + ofs;
1536: break_point_ptr->table[i].seg = seg;
1537: break_point_ptr->table[i].ofs = ofs;
1538: break_point_ptr->table[i].status = 1;
1539: found = true;
1540: }
1541: }
1542: if(!found) {
1543: telnet_printf("too many break points\n");
1544: }
1545: } else {
1546: telnet_printf("invalid parameter number\n");
1547: }
1548: } else if(stricmp(params[0], "IBP") == 0 || stricmp(params[0], "OBP") == 0) {
1549: break_point_t *break_point_ptr;
1550: GET_BREAK_POINT_PTR();
1551: if(num == 2) {
1552: UINT32 addr = debugger_get_val(params[1]);
1553: bool found = false;
1554: for(int i = 0; i < MAX_BREAK_POINTS && !found; i++) {
1555: if(break_point_ptr->table[i].status == 0 || break_point_ptr->table[i].addr == addr) {
1556: break_point_ptr->table[i].addr = addr;
1557: break_point_ptr->table[i].status = 1;
1558: found = true;
1559: }
1560: }
1561: if(!found) {
1562: telnet_printf("too many break points\n");
1563: }
1564: } else {
1565: telnet_printf("invalid parameter number\n");
1566: }
1567: } 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) {
1568: break_point_t *break_point_ptr;
1569: GET_BREAK_POINT_PTR();
1570: if(num == 2 && (stricmp(params[1], "*") == 0 || stricmp(params[1], "ALL") == 0)) {
1571: memset(break_point_ptr, 0, sizeof(break_point_t));
1572: } else if(num >= 2) {
1573: for(int i = 1; i < num; i++) {
1574: int index = debugger_get_val(params[i]);
1575: if(!(index >= 1 && index <= MAX_BREAK_POINTS)) {
1576: telnet_printf("invalid index %x\n", index);
1577: } else {
1578: break_point_ptr->table[index - 1].addr = 0;
1579: break_point_ptr->table[index - 1].seg = 0;
1580: break_point_ptr->table[index - 1].ofs = 0;
1581: break_point_ptr->table[index - 1].status = 0;
1582: }
1583: }
1584: } else {
1585: telnet_printf("invalid parameter number\n");
1586: }
1587: } 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 ||
1588: 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) {
1589: break_point_t *break_point_ptr;
1590: GET_BREAK_POINT_PTR();
1591: bool enabled = (params[0][strlen(params[0]) - 1] == 'E' || params[0][strlen(params[0]) - 1] == 'e');
1592: if(num == 2 && (stricmp(params[1], "*") == 0 || stricmp(params[1], "ALL") == 0)) {
1593: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
1594: if(break_point_ptr->table[i].status != 0) {
1595: break_point_ptr->table[i].status = enabled ? 1 : -1;
1596: }
1597: }
1598: } else if(num >= 2) {
1599: for(int i = 1; i < num; i++) {
1600: int index = debugger_get_val(params[i]);
1601: if(!(index >= 1 && index <= MAX_BREAK_POINTS)) {
1602: telnet_printf("invalid index %x\n", index);
1603: } else if(break_point_ptr->table[index - 1].status == 0) {
1604: telnet_printf("break point %x is null\n", index);
1605: } else {
1606: break_point_ptr->table[index - 1].status = enabled ? 1 : -1;
1607: }
1608: }
1609: } else {
1610: telnet_printf("invalid parameter number\n");
1611: }
1612: } else if(stricmp(params[0], "BL") == 0 || stricmp(params[0], "RBL") == 0 || stricmp(params[0], "WBL") == 0) {
1613: break_point_t *break_point_ptr;
1614: GET_BREAK_POINT_PTR();
1615: if(num == 1) {
1616: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
1617: if(break_point_ptr->table[i].status) {
1618: 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);
1619: }
1620: }
1621: } else {
1622: telnet_printf("invalid parameter number\n");
1623: }
1624: } else if(stricmp(params[0], "IBL") == 0 || stricmp(params[0], "OBL") == 0) {
1625: break_point_t *break_point_ptr;
1626: GET_BREAK_POINT_PTR();
1627: if(num == 1) {
1628: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
1629: if(break_point_ptr->table[i].status) {
1630: telnet_printf("%d %c %04X\n", i + 1, break_point_ptr->table[i].status == 1 ? 'e' : 'd', break_point_ptr->table[i].addr);
1631: }
1632: }
1633: } else {
1634: telnet_printf("invalid parameter number\n");
1635: }
1636: } else if(stricmp(params[0], "INTBP") == 0) {
1637: if(num >= 2 && num <= 4) {
1638: int int_num = debugger_get_val(params[1]);
1639: UINT8 ah = 0, ah_registered = 0;
1640: UINT8 al = 0, al_registered = 0;
1641: if(num >= 3) {
1642: ah = debugger_get_val(params[2]);
1643: ah_registered = 1;
1644: }
1645: if(num == 4) {
1646: al = debugger_get_val(params[3]);
1647: al_registered = 1;
1648: }
1649: bool found = false;
1650: for(int i = 0; i < MAX_BREAK_POINTS && !found; i++) {
1651: if(int_break_point.table[i].status == 0 || (
1652: int_break_point.table[i].int_num == int_num &&
1653: int_break_point.table[i].ah == ah && int_break_point.table[i].ah_registered == ah_registered &&
1654: int_break_point.table[i].al == al && int_break_point.table[i].al_registered == al_registered)) {
1655: int_break_point.table[i].int_num = int_num;
1656: int_break_point.table[i].ah = ah;
1657: int_break_point.table[i].ah_registered = ah_registered;
1658: int_break_point.table[i].al = al;
1659: int_break_point.table[i].al_registered = al_registered;
1660: int_break_point.table[i].status = 1;
1661: found = true;
1662: }
1663: }
1664: if(!found) {
1665: telnet_printf("too many break points\n");
1666: }
1667: } else {
1668: telnet_printf("invalid parameter number\n");
1669: }
1670: } else if(stricmp(params[0], "INTBC") == 0) {
1671: if(num == 2 && (stricmp(params[1], "*") == 0 || stricmp(params[1], "ALL") == 0)) {
1672: memset(&int_break_point, 0, sizeof(int_break_point_t));
1673: } else if(num >= 2) {
1674: for(int i = 1; i < num; i++) {
1675: int index = debugger_get_val(params[i]);
1676: if(!(index >= 1 && index <= MAX_BREAK_POINTS)) {
1677: telnet_printf("invalid index %x\n", index);
1678: } else {
1679: int_break_point.table[index - 1].int_num = 0;
1680: int_break_point.table[index - 1].ah = 0;
1681: int_break_point.table[index - 1].ah_registered = 0;
1682: int_break_point.table[index - 1].al = 0;
1683: int_break_point.table[index - 1].al_registered = 0;
1684: int_break_point.table[index - 1].status = 0;
1685: }
1686: }
1687: } else {
1688: telnet_printf("invalid parameter number\n");
1689: }
1690: } else if(stricmp(params[0], "INTBD") == 0 || stricmp(params[0], "INTBE") == 0) {
1691: bool enabled = (params[0][strlen(params[0]) - 1] == 'E' || params[0][strlen(params[0]) - 1] == 'e');
1692: if(num == 2 && (stricmp(params[1], "*") == 0 || stricmp(params[1], "ALL") == 0)) {
1693: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
1694: if(int_break_point.table[i].status != 0) {
1695: int_break_point.table[i].status = enabled ? 1 : -1;
1696: }
1697: }
1698: } else if(num >= 2) {
1699: for(int i = 1; i < num; i++) {
1700: int index = debugger_get_val(params[i]);
1701: if(!(index >= 1 && index <= MAX_BREAK_POINTS)) {
1702: telnet_printf("invalid index %x\n", index);
1703: } else if(int_break_point.table[index - 1].status == 0) {
1704: telnet_printf("break point %x is null\n", index);
1705: } else {
1706: int_break_point.table[index - 1].status = enabled ? 1 : -1;
1707: }
1708: }
1709: } else {
1710: telnet_printf("invalid parameter number\n");
1711: }
1712: } else if(stricmp(params[0], "INTBL") == 0) {
1713: if(num == 1) {
1714: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
1715: if(int_break_point.table[i].status) {
1716: telnet_printf("%d %c %02X", i + 1, int_break_point.table[i].status == 1 ? 'e' : 'd', int_break_point.table[i].int_num);
1717: if(int_break_point.table[i].ah_registered) {
1718: telnet_printf(" %02X", int_break_point.table[i].ah);
1719: }
1720: if(int_break_point.table[i].al_registered) {
1721: telnet_printf(" %02X", int_break_point.table[i].al);
1722: }
1723: telnet_printf("\n");
1724: }
1725: }
1726: } else {
1727: telnet_printf("invalid parameter number\n");
1728: }
1729: } else if(stricmp(params[0], "G") == 0 || stricmp(params[0], "P") == 0) {
1730: if(num == 1 || num == 2) {
1731: break_point_t break_point_stored;
1732: bool break_points_stored = false;
1733:
1734: if(stricmp(params[0], "P") == 0) {
1735: memcpy(&break_point_stored, &break_point, sizeof(break_point_t));
1736: memset(&break_point, 0, sizeof(break_point_t));
1737: break_points_stored = true;
1738:
1739: break_point.table[0].addr = (SREG(CS) << 4) + m_eip + debugger_dasm(buffer, SREG(CS), m_eip);
1740: break_point.table[0].status = 1;
1741: } else if(num >= 2) {
1742: memcpy(&break_point_stored, &break_point, sizeof(break_point_t));
1743: memset(&break_point, 0, sizeof(break_point_t));
1744: break_points_stored = true;
1745:
1746: UINT32 seg = debugger_get_seg(params[1], SREG(CS));
1747: UINT32 ofs = debugger_get_ofs(params[1]);
1748: break_point.table[0].addr = (seg << 4) + ofs;
1749: break_point.table[0].seg = seg;
1750: break_point.table[0].ofs = ofs;
1751: break_point.table[0].status = 1;
1752: }
1753: break_point.hit = rd_break_point.hit = wr_break_point.hit = in_break_point.hit = out_break_point.hit = int_break_point.hit = 0;
1754: now_going = true;
1755: now_suspended = false;
1756:
1757: telnet_command("\033[2l"); // key unlock
1758: while(!m_halted && !now_suspended) {
1759: if(telnet_kbhit()) {
1760: break;
1761: }
1762: Sleep(10);
1763: }
1764: now_going = false;
1765: telnet_command("\033[2h"); // key lock
1766:
1767: if(!(break_point.hit || rd_break_point.hit || wr_break_point.hit || in_break_point.hit || out_break_point.hit || int_break_point.hit)) {
1768: Sleep(100);
1769: if(!m_halted && !now_suspended) {
1770: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1771: telnet_printf("waiting until cpu is suspended...\n");
1772: }
1773: }
1774: while(!m_halted && !now_suspended) {
1775: if(telnet_disconnected()) {
1776: break;
1777: }
1778: Sleep(10);
1779: }
1780: dasm_seg = SREG(CS);
1781: dasm_ofs = m_eip;
1782:
1783: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1784: debugger_dasm(buffer, m_prev_cs, m_prev_eip);
1785: telnet_printf("done\t%04X:%04X %s\n", m_prev_cs, m_prev_eip, buffer);
1786:
1787: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1788: debugger_regs_info(buffer);
1789: telnet_printf("%s", buffer);
1790:
1791: if(break_point.hit) {
1792: if(stricmp(params[0], "G") == 0 && num == 1) {
1793: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1794: telnet_printf("breaked at %04X:%04X: break point is hit\n", SREG(CS), m_eip);
1795: }
1796: } else if(rd_break_point.hit) {
1797: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1798: telnet_printf("breaked at %04X:%04X: memory %04X:%04X was read at %04X:%04X\n", SREG(CS), m_eip,
1799: rd_break_point.table[rd_break_point.hit - 1].seg, rd_break_point.table[rd_break_point.hit - 1].ofs,
1800: m_prev_cs, m_prev_eip);
1801: } else if(wr_break_point.hit) {
1802: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1803: telnet_printf("breaked at %04X:%04X: memory %04X:%04X was written at %04X:%04X\n", SREG(CS), m_eip,
1804: wr_break_point.table[wr_break_point.hit - 1].seg, wr_break_point.table[wr_break_point.hit - 1].ofs,
1805: m_prev_cs, m_prev_eip);
1806: } else if(in_break_point.hit) {
1807: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1808: telnet_printf("breaked at %04X:%04X: port %04X was read at %04X:%04X\n", SREG(CS), m_eip,
1809: in_break_point.table[in_break_point.hit - 1].addr,
1810: m_prev_cs, m_prev_eip);
1811: } else if(out_break_point.hit) {
1812: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1813: telnet_printf("breaked at %04X:%04X: port %04X was written at %04X:%04X\n", SREG(CS), m_eip,
1814: out_break_point.table[out_break_point.hit - 1].addr,
1815: m_prev_cs, m_prev_eip);
1816: } else if(int_break_point.hit) {
1817: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1818: telnet_printf("breaked at %04X:%04X: INT %02x", SREG(CS), m_eip, int_break_point.table[int_break_point.hit - 1].int_num);
1819: if(int_break_point.table[int_break_point.hit - 1].ah_registered) {
1820: telnet_printf(" AH=%02x", int_break_point.table[int_break_point.hit - 1].ah);
1821: }
1822: if(int_break_point.table[int_break_point.hit - 1].al_registered) {
1823: telnet_printf(" AL=%02x", int_break_point.table[int_break_point.hit - 1].al);
1824: }
1825: telnet_printf(" is raised at %04X:%04X\n", m_prev_cs, m_prev_eip);
1826: } else {
1827: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1828: telnet_printf("breaked at %04X:%04X: enter key was pressed\n", SREG(CS), m_eip);
1829: }
1830: if(break_points_stored) {
1831: memcpy(&break_point, &break_point_stored, sizeof(break_point_t));
1832: }
1833: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1834: debugger_dasm(buffer, SREG(CS), m_eip);
1835: telnet_printf("next\t%04X:%04X %s\n", SREG(CS), m_eip, buffer);
1836: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1837: } else {
1838: telnet_printf("invalid parameter number\n");
1839: }
1840: } else if(stricmp(params[0], "T") == 0) {
1841: if(num == 1 || num == 2) {
1842: int steps = 1;
1843: if(num >= 2) {
1844: steps = debugger_get_val(params[1]);
1845: }
1846:
1847: telnet_command("\033[2l"); // key unlock
1848: while(steps-- > 0) {
1849: break_point.hit = rd_break_point.hit = wr_break_point.hit = in_break_point.hit = out_break_point.hit = int_break_point.hit = 0;
1850: now_going = false;
1851: now_suspended = false;
1852:
1853: while(!m_halted && !now_suspended) {
1854: if(telnet_disconnected()) {
1855: break;
1856: }
1857: Sleep(10);
1858: }
1859: dasm_seg = SREG(CS);
1860: dasm_ofs = m_eip;
1861:
1862: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1863: debugger_dasm(buffer, m_prev_cs, m_prev_eip);
1864: telnet_printf("done\t%04X:%04X %s\n", m_prev_cs, m_prev_eip, buffer);
1865:
1866: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1867: debugger_regs_info(buffer);
1868: telnet_printf("%s", buffer);
1869:
1870: 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()) {
1871: break;
1872: }
1873: }
1874: telnet_command("\033[2h"); // key lock
1875:
1876: if(!(break_point.hit || rd_break_point.hit || wr_break_point.hit || in_break_point.hit || out_break_point.hit || int_break_point.hit)) {
1877: Sleep(100);
1878: if(!m_halted && !now_suspended) {
1879: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1880: telnet_printf("waiting until cpu is suspended...\n");
1881: }
1882: }
1883: while(!m_halted && !now_suspended) {
1884: if(telnet_disconnected()) {
1885: break;
1886: }
1887: Sleep(10);
1888: }
1889: if(break_point.hit) {
1890: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1891: telnet_printf("breaked at %04X:%04X: break point is hit\n", SREG(CS), m_eip);
1892: } else if(rd_break_point.hit) {
1893: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1894: telnet_printf("breaked at %04X:%04X: memory %04X:%04X was read at %04X:%04X\n", SREG(CS), m_eip,
1895: rd_break_point.table[rd_break_point.hit - 1].seg, rd_break_point.table[rd_break_point.hit - 1].ofs,
1896: m_prev_cs, m_prev_eip);
1897: } else if(wr_break_point.hit) {
1898: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1899: telnet_printf("breaked at %04X:%04X: memory %04X:%04X was written at %04X:%04X\n", SREG(CS), m_eip,
1900: wr_break_point.table[wr_break_point.hit - 1].seg, wr_break_point.table[wr_break_point.hit - 1].ofs,
1901: m_prev_cs, m_prev_eip);
1902: } else if(in_break_point.hit) {
1903: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1904: telnet_printf("breaked at %04X:%04X: port %04X was read at %04X:%04X\n", SREG(CS), m_eip,
1905: in_break_point.table[in_break_point.hit - 1].addr,
1906: m_prev_cs, m_prev_eip);
1907: } else if(out_break_point.hit) {
1908: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1909: telnet_printf("breaked at %04X:%04X: port %04X was written at %04X:%04X\n", SREG(CS), m_eip,
1910: out_break_point.table[out_break_point.hit - 1].addr,
1911: m_prev_cs, m_prev_eip);
1912: } else if(int_break_point.hit) {
1913: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1914: telnet_printf("breaked at %04X:%04X: INT %02x", SREG(CS), m_eip, int_break_point.table[int_break_point.hit - 1].int_num);
1915: if(int_break_point.table[int_break_point.hit - 1].ah_registered) {
1916: telnet_printf(" AH=%02x", int_break_point.table[int_break_point.hit - 1].ah);
1917: }
1918: if(int_break_point.table[int_break_point.hit - 1].al_registered) {
1919: telnet_printf(" AL=%02x", int_break_point.table[int_break_point.hit - 1].al);
1920: }
1921: telnet_printf(" is raised at %04X:%04X\n", m_prev_cs, m_prev_eip);
1922: } else if(steps > 0) {
1923: telnet_set_color(TELNET_RED | TELNET_INTENSITY);
1924: telnet_printf("breaked at %04X:%04X: enter key was pressed\n", SREG(CS), m_eip);
1925: }
1926: telnet_set_color(TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1927: debugger_dasm(buffer, SREG(CS), m_eip);
1928: telnet_printf("next\t%04X:%04X %s\n", SREG(CS), m_eip, buffer);
1929: telnet_set_color(TELNET_RED | TELNET_GREEN | TELNET_BLUE | TELNET_INTENSITY);
1930: } else {
1931: telnet_printf("invalid parameter number\n");
1932: }
1933: } else if(stricmp(params[0], "Q") == 0) {
1934: break;
1935: } else if(stricmp(params[0], "X") == 0) {
1936: debugger_process_info(buffer);
1937: telnet_printf("%s", buffer);
1938: } else if(stricmp(params[0], ">") == 0) {
1939: if(num == 2) {
1940: if(fp_debugger != NULL) {
1941: fclose(fp_debugger);
1942: fp_debugger = NULL;
1943: }
1944: fp_debugger = fopen(params[1], "w");
1945: } else {
1946: telnet_printf("invalid parameter number\n");
1947: }
1948: } else if(stricmp(params[0], "<") == 0) {
1949: if(num == 2) {
1950: if(fi_debugger != NULL) {
1951: fclose(fi_debugger);
1952: fi_debugger = NULL;
1953: }
1954: fi_debugger = fopen(params[1], "r");
1955: } else {
1956: telnet_printf("invalid parameter number\n");
1957: }
1958: } else if(stricmp(params[0], "?") == 0) {
1959: telnet_printf("D [<start> [<end>]] - dump memory\n");
1960: telnet_printf("E[{B,W,D}] <address> <list> - edit memory (byte,word,dword)\n");
1961: telnet_printf("EA <address> \"<value>\" - edit memory (ascii)\n");
1962: telnet_printf("I[{B,W,D}] <port> - input port (byte,word,dword)\n");
1963: telnet_printf("O[{B,W,D}] <port> <value> - output port (byte,word,dword)\n");
1964:
1965: telnet_printf("R - show registers\n");
1966: telnet_printf("R <reg> <value> - edit register\n");
1967: telnet_printf("S <start> <end> <list> - search\n");
1968: telnet_printf("U [<start> [<end>]] - unassemble\n");
1969:
1970: telnet_printf("H <value> <value> - hexadd\n");
1971:
1972: telnet_printf("BP <address> - set breakpoint\n");
1973: telnet_printf("{R,W}BP <address> - set breakpoint (break at memory access)\n");
1974: telnet_printf("{I,O}BP <port> - set breakpoint (break at i/o access)\n");
1975: telnet_printf("INTBP <num> [<ah> [<al>]]- set breakpoint (break at interrupt)\n");
1976: telnet_printf("[{R,W,I,O,INT}]B{C,D,E} {*,<list>} - clear/disable/enable breakpoint(s)\n");
1977: telnet_printf("[{R,W,I,O,INT}]BL - list breakpoint(s)\n");
1978:
1979: telnet_printf("G - go (press enter key to break)\n");
1980: telnet_printf("G <address> - go and break at address\n");
1981: telnet_printf("P - trace one opcode (step over)\n");
1982: telnet_printf("T [<count>] - trace (step in)\n");
1983: telnet_printf("Q - quit\n");
1984: telnet_printf("X - show dos process info\n");
1985:
1986: telnet_printf("> <filename> - output logfile\n");
1987: telnet_printf("< <filename> - input commands from file\n");
1988:
1989: telnet_printf("<value> - hexa, decimal(%%d), ascii('a')\n");
1990: telnet_printf("<list> - <value> [<value> [<value> [...]]]\n");
1991: } else {
1992: telnet_printf("unknown command %s\n", params[0]);
1993: }
1994: }
1995: }
1996: if(fp_debugger != NULL) {
1997: fclose(fp_debugger);
1998: fp_debugger = NULL;
1999: }
2000: if(fi_debugger != NULL) {
2001: fclose(fi_debugger);
2002: fi_debugger = NULL;
2003: }
2004: now_debugging = now_going = now_suspended = force_suspend = false;
2005: closesocket(cli_socket);
2006: }
2007:
2008: const char *debugger_get_ttermpro_path()
2009: {
2010: static char path[MAX_PATH] = {0};
2011:
2012: if(getenv("ProgramFiles")) {
2013: sprintf(path, "%s\\teraterm\\ttermpro.exe", getenv("ProgramFiles"));
2014: }
2015: return(path);
2016: }
2017:
2018: const char *debugger_get_ttermpro_x86_path()
2019: {
2020: static char path[MAX_PATH] = {0};
2021:
2022: if(getenv("ProgramFiles(x86)")) {
2023: sprintf(path, "%s\\teraterm\\ttermpro.exe", getenv("ProgramFiles(x86)"));
2024: }
2025: return(path);
2026: }
2027:
2028: const char *debugger_get_putty_path()
2029: {
2030: static char path[MAX_PATH] = {0};
2031:
2032: if(getenv("ProgramFiles")) {
2033: sprintf(path, "%s\\PuTTY\\putty.exe", getenv("ProgramFiles"));
2034: }
2035: return(path);
2036: }
2037:
2038: const char *debugger_get_putty_x86_path()
2039: {
2040: static char path[MAX_PATH] = {0};
2041:
2042: if(getenv("ProgramFiles(x86)")) {
2043: sprintf(path, "%s\\PuTTY\\putty.exe", getenv("ProgramFiles(x86)"));
2044: }
2045: return(path);
2046: }
2047:
2048: const char *debugger_get_telnet_path()
2049: {
2050: // NOTE: When you run 32bit version of msdos.exe on Windows x64,
2051: // C:\Windows\System32\telnet.exe is redirected to telnet.exe in SysWOW64.
2052: // But 32bit version of telnet.exe will not be installed in SysWOW64
2053: // and 64bit version of telnet.exe will be installed in System32.
2054: static char path[MAX_PATH] = {0};
2055:
2056: if(getenv("windir") != NULL) {
2057: sprintf(path, "%s\\System32\\telnet.exe", getenv("windir"));
2058: }
2059: return(path);
2060: }
2061:
2062: DWORD WINAPI debugger_thread(LPVOID)
2063: {
2064: WSADATA was_data;
2065: struct sockaddr_in svr_addr;
2066: struct sockaddr_in cli_addr;
2067: int cli_addr_len = sizeof(cli_addr);
2068: int port = 23;
2069: int bind_stat = SOCKET_ERROR;
2070: struct timeval timeout;
2071:
2072: WSAStartup(MAKEWORD(2,0), &was_data);
2073:
2074: if((svr_socket = socket(AF_INET, SOCK_STREAM, 0)) != INVALID_SOCKET) {
2075: memset(&svr_addr, 0, sizeof(svr_addr));
2076: svr_addr.sin_family = AF_INET;
2077: svr_addr.sin_addr.s_addr = htonl(INADDR_ANY);
2078:
2079: while(!m_halted && port < 10000) {
2080: svr_addr.sin_port = htons(port);
2081: if((bind_stat = bind(svr_socket, (struct sockaddr *)&svr_addr, sizeof(svr_addr))) == 0) {
2082: break;
2083: } else {
2084: port = (port == 23) ? 9000 : (port + 1);
2085: }
2086: }
2087: if(bind_stat == 0) {
2088: timeout.tv_sec = 1;
2089: timeout.tv_usec = 0;
2090: setsockopt(svr_socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
2091:
2092: listen(svr_socket, 1);
2093:
2094: char command[MAX_PATH] = {0};
2095: STARTUPINFO si;
2096: PROCESS_INFORMATION pi;
2097:
2098: if(_access(debugger_get_ttermpro_path(), 0) == 0) {
2099: sprintf(command, "%s localhost:%d /T=1", debugger_get_ttermpro_path(), port);
2100: } else if(_access(debugger_get_ttermpro_x86_path(), 0) == 0) {
2101: sprintf(command, "%s localhost:%d /T=1", debugger_get_ttermpro_x86_path(), port);
2102: } else if(_access(debugger_get_putty_path(), 0) == 0) {
2103: sprintf(command, "%s -telnet localhost %d", debugger_get_putty_path(), port);
2104: } else if(_access(debugger_get_putty_x86_path(), 0) == 0) {
2105: sprintf(command, "%s -telnet localhost %d", debugger_get_putty_x86_path(), port);
2106: } else if(_access(debugger_get_telnet_path(), 0) == 0) {
2107: sprintf(command, "%s -t vt100 localhost %d", debugger_get_telnet_path(), port);
2108: }
2109: if(command[0] != '\0') {
2110: memset(&si, 0, sizeof(STARTUPINFO));
2111: memset(&pi, 0, sizeof(PROCESS_INFORMATION));
2112: CreateProcess(NULL, command, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
2113: }
2114:
2115: while(!m_halted) {
2116: if((cli_socket = accept(svr_socket, (struct sockaddr *) &cli_addr, &cli_addr_len)) != INVALID_SOCKET) {
2117: u_long val = 1;
2118: ioctlsocket(cli_socket, FIONBIO, &val);
2119: debugger_main();
2120: }
2121: }
2122: }
2123: }
2124: WSACleanup();
2125: return(0);
2126: }
2127: #endif
2128:
2129: /* ----------------------------------------------------------------------------
1.1 root 2130: main
2131: ---------------------------------------------------------------------------- */
2132:
1.1.1.28 root 2133: BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
2134: {
2135: if(dwCtrlType == CTRL_BREAK_EVENT) {
1.1.1.33 root 2136: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 2137: #ifdef USE_SERVICE_THREAD
2138: EnterCriticalSection(&key_buf_crit_sect);
2139: #endif
1.1.1.33 root 2140: key_buf_char->clear();
2141: key_buf_scan->clear();
1.1.1.35 root 2142: #ifdef USE_SERVICE_THREAD
2143: LeaveCriticalSection(&key_buf_crit_sect);
2144: #endif
1.1.1.33 root 2145: }
2146: // key_code = key_recv = 0;
1.1.1.28 root 2147: return TRUE;
2148: } else if(dwCtrlType == CTRL_C_EVENT) {
2149: return TRUE;
2150: } else if(dwCtrlType == CTRL_CLOSE_EVENT) {
2151: // this program will be terminated abnormally, do minimum end process
2152: exit_handler();
2153: exit(1);
2154: }
2155: return FALSE;
2156: }
2157:
2158: void exit_handler()
2159: {
2160: if(temp_file_created) {
2161: DeleteFile(temp_file_path);
2162: temp_file_created = false;
2163: }
2164: if(key_buf_char != NULL) {
2165: key_buf_char->release();
2166: delete key_buf_char;
2167: key_buf_char = NULL;
2168: }
2169: if(key_buf_scan != NULL) {
2170: key_buf_scan->release();
2171: delete key_buf_scan;
2172: key_buf_scan = NULL;
2173: }
1.1.1.32 root 2174: #ifdef SUPPORT_XMS
2175: msdos_xms_release();
2176: #endif
1.1.1.28 root 2177: hardware_release();
2178: }
2179:
1.1.1.35 root 2180: #ifdef USE_VRAM_THREAD
1.1.1.28 root 2181: DWORD WINAPI vram_thread(LPVOID)
2182: {
2183: while(!m_halted) {
2184: EnterCriticalSection(&vram_crit_sect);
2185: if(vram_length_char != 0 && vram_length_char == vram_last_length_char) {
2186: vram_flush_char();
2187: }
2188: if(vram_length_attr != 0 && vram_length_attr == vram_last_length_attr) {
2189: vram_flush_attr();
2190: }
2191: vram_last_length_char = vram_length_char;
2192: vram_last_length_attr = vram_length_attr;
2193: LeaveCriticalSection(&vram_crit_sect);
2194: // this is about half the maximum keyboard repeat rate - any
2195: // lower tends to be jerky, any higher misses updates
2196: Sleep(15);
2197: }
2198: return 0;
2199: }
2200: #endif
2201:
2202: long get_section_in_exec_file(FILE *fp, char *name)
2203: {
2204: UINT8 header[0x400];
2205:
2206: long position = ftell(fp);
2207: fseek(fp, 0, SEEK_SET);
2208: fread(header, sizeof(header), 1, fp);
2209: fseek(fp, position, SEEK_SET);
2210:
2211: try {
2212: _IMAGE_DOS_HEADER *dosHeader = (_IMAGE_DOS_HEADER *)(header + 0);
2213: DWORD dwTopOfSignature = dosHeader->e_lfanew;
2214: DWORD dwTopOfCoffHeader = dwTopOfSignature + 4;
2215: _IMAGE_FILE_HEADER *coffHeader = (_IMAGE_FILE_HEADER *)(header + dwTopOfCoffHeader);
2216: DWORD dwTopOfOptionalHeader = dwTopOfCoffHeader + sizeof(_IMAGE_FILE_HEADER);
2217: DWORD dwTopOfFirstSectionHeader = dwTopOfOptionalHeader + coffHeader->SizeOfOptionalHeader;
2218:
2219: for(int i = 0; i < coffHeader->NumberOfSections; i++) {
2220: _IMAGE_SECTION_HEADER *sectionHeader = (_IMAGE_SECTION_HEADER *)(header + dwTopOfFirstSectionHeader + IMAGE_SIZEOF_SECTION_HEADER * i);
2221: if(memcmp(sectionHeader->Name, name, strlen(name)) == 0) {
2222: return(sectionHeader->PointerToRawData);
2223: }
2224: }
2225: } catch(...) {
2226: }
2227: return(0);
2228: }
2229:
1.1.1.10 root 2230: bool is_started_from_command_prompt()
2231: {
1.1.1.18 root 2232: bool ret = false;
2233:
2234: HMODULE hLibrary = LoadLibrary(_T("Kernel32.dll"));
2235: if(hLibrary) {
2236: typedef DWORD (WINAPI *GetConsoleProcessListFunction)(__out LPDWORD lpdwProcessList, __in DWORD dwProcessCount);
2237: GetConsoleProcessListFunction lpfnGetConsoleProcessList;
2238: lpfnGetConsoleProcessList = reinterpret_cast<GetConsoleProcessListFunction>(::GetProcAddress(hLibrary, "GetConsoleProcessList"));
2239: if(lpfnGetConsoleProcessList) {
2240: DWORD pl;
2241: ret = (lpfnGetConsoleProcessList(&pl, 1) > 1);
2242: FreeLibrary(hLibrary);
2243: return(ret);
2244: }
2245: FreeLibrary(hLibrary);
2246: }
2247:
2248: HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
2249: if(hSnapshot != INVALID_HANDLE_VALUE) {
2250: DWORD dwParentProcessID = 0;
2251: PROCESSENTRY32 pe32;
2252: pe32.dwSize = sizeof(PROCESSENTRY32);
2253: if(Process32First(hSnapshot, &pe32)) {
2254: do {
2255: if(pe32.th32ProcessID == GetCurrentProcessId()) {
2256: dwParentProcessID = pe32.th32ParentProcessID;
2257: break;
2258: }
2259: } while(Process32Next(hSnapshot, &pe32));
2260: }
2261: CloseHandle(hSnapshot);
2262: if(dwParentProcessID != 0) {
2263: HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwParentProcessID);
2264: if(hProcess != NULL) {
2265: HMODULE hMod;
2266: DWORD cbNeeded;
2267: if(EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) {
2268: char module_name[MAX_PATH];
2269: if(GetModuleBaseName(hProcess, hMod, module_name, sizeof(module_name))) {
2270: ret = (_strnicmp(module_name, "cmd.exe", 7) == 0);
2271: }
2272: }
2273: CloseHandle(hProcess);
2274: }
2275: }
2276: }
2277: return(ret);
1.1.1.14 root 2278: }
2279:
2280: BOOL is_greater_windows_version(DWORD dwMajorVersion, DWORD dwMinorVersion, WORD wServicePackMajor, WORD wServicePackMinor)
2281: {
1.1.1.24 root 2282: // https://msdn.microsoft.com/en-us/library/windows/desktop/ms725491(v=vs.85).aspx
1.1.1.14 root 2283: OSVERSIONINFOEX osvi;
2284: DWORDLONG dwlConditionMask = 0;
2285: int op = VER_GREATER_EQUAL;
2286:
2287: // Initialize the OSVERSIONINFOEX structure.
2288: ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
2289: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
2290: osvi.dwMajorVersion = dwMajorVersion;
2291: osvi.dwMinorVersion = dwMinorVersion;
2292: osvi.wServicePackMajor = wServicePackMajor;
2293: osvi.wServicePackMinor = wServicePackMinor;
2294:
2295: // Initialize the condition mask.
2296: VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, op );
2297: VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, op );
2298: VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMAJOR, op );
2299: VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMINOR, op );
2300:
2301: // Perform the test.
2302: return VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, dwlConditionMask);
2303: }
2304:
1.1.1.27 root 2305: void get_sio_port_numbers()
2306: {
2307: SP_DEVINFO_DATA DeviceInfoData = {sizeof(SP_DEVINFO_DATA)};
2308: HDEVINFO hDevInfo = 0;
2309: HKEY hKey = 0;
2310: if((hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_COMPORT, NULL, NULL, (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE))) != 0) {
2311: for(int i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData); i++) {
2312: if((hKey = SetupDiOpenDevRegKey(hDevInfo, &DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE)) != INVALID_HANDLE_VALUE) {
2313: char chData[256];
2314: DWORD dwType = 0;
2315: DWORD dwSize = sizeof(chData);
2316: int port_number = 0;
2317:
2318: if(RegQueryValueEx(hKey, _T("PortName"), NULL, &dwType, (BYTE *)chData, &dwSize) == ERROR_SUCCESS) {
2319: if(_strnicmp(chData, "COM", 3) == 0) {
2320: port_number = atoi(chData + 3);
2321: }
2322: }
2323: RegCloseKey(hKey);
2324:
1.1.1.29 root 2325: 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 2326: continue;
2327: }
2328: if(sio_port_number[0] == 0) {
2329: sio_port_number[0] = port_number;
2330: } else if(sio_port_number[1] == 0) {
2331: sio_port_number[1] = port_number;
1.1.1.29 root 2332: } else if(sio_port_number[2] == 0) {
2333: sio_port_number[2] = port_number;
2334: } else if(sio_port_number[3] == 0) {
2335: sio_port_number[3] = port_number;
1.1.1.27 root 2336: }
1.1.1.29 root 2337: 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 2338: break;
2339: }
2340: }
2341: }
2342: }
2343: }
2344:
1.1.1.28 root 2345: #define IS_NUMERIC(c) ((c) >= '0' && (c) <= '9')
2346:
1.1 root 2347: int main(int argc, char *argv[], char *envp[])
2348: {
1.1.1.9 root 2349: int arg_offset = 0;
2350: int standard_env = 0;
1.1.1.14 root 2351: int buf_width = 0, buf_height = 0;
1.1.1.28 root 2352: bool get_console_info_success = false;
2353: bool screen_size_changed = false;
2354:
2355: _TCHAR path[MAX_PATH], full[MAX_PATH], *name = NULL;
2356: GetModuleFileName(NULL, path, MAX_PATH);
2357: GetFullPathName(path, MAX_PATH, full, &name);
1.1 root 2358:
1.1.1.27 root 2359: char dummy_argv_0[] = "msdos.exe";
2360: char dummy_argv_1[MAX_PATH];
2361: char *dummy_argv[256] = {dummy_argv_0, dummy_argv_1, 0};
2362: char new_exec_file[MAX_PATH];
2363: bool convert_cmd_file = false;
1.1.1.28 root 2364: unsigned int code_page = 0;
1.1.1.27 root 2365:
2366: if(name != NULL && stricmp(name, "msdos.exe") != 0) {
1.1.1.28 root 2367: // check if command file is embedded to this execution file
2368: // if this execution file name is msdos.exe, don't check
1.1.1.27 root 2369: FILE* fp = fopen(full, "rb");
1.1.1.28 root 2370: long offset = get_section_in_exec_file(fp, ".msdos");
2371: if(offset != 0) {
1.1.1.30 root 2372: UINT8 buffer[16];
1.1.1.28 root 2373: fseek(fp, offset, SEEK_SET);
2374: fread(buffer, sizeof(buffer), 1, fp);
2375:
2376: // restore flags
2377: stay_busy = ((buffer[0] & 0x01) != 0);
2378: no_windows = ((buffer[0] & 0x02) != 0);
2379: standard_env = ((buffer[0] & 0x04) != 0);
2380: ignore_illegal_insn = ((buffer[0] & 0x08) != 0);
2381: limit_max_memory = ((buffer[0] & 0x10) != 0);
2382: if((buffer[0] & 0x20) != 0) {
2383: get_sio_port_numbers();
2384: }
2385: if((buffer[0] & 0x40) != 0) {
2386: UMB_TOP = EMS_TOP + EMS_SIZE;
2387: support_ems = true;
1.1.1.30 root 2388: }
1.1.1.27 root 2389: #ifdef SUPPORT_XMS
1.1.1.30 root 2390: if((buffer[0] & 0x80) != 0) {
1.1.1.28 root 2391: support_xms = true;
2392: }
1.1.1.30 root 2393: #endif
1.1.1.28 root 2394: if((buffer[1] != 0 || buffer[2] != 0) && (buffer[3] != 0 || buffer[4] != 0)) {
2395: buf_width = buffer[1] | (buffer[2] << 8);
2396: buf_height = buffer[3] | (buffer[4] << 8);
2397: }
2398: if(buffer[5] != 0) {
1.1.1.30 root 2399: dos_major_version = buffer[5];
2400: dos_minor_version = buffer[6];
2401: }
2402: if(buffer[7] != 0) {
2403: win_major_version = buffer[7];
2404: win_minor_version = buffer[8];
1.1.1.28 root 2405: }
1.1.1.30 root 2406: if((code_page = buffer[9] | (buffer[10] << 8)) != 0) {
1.1.1.28 root 2407: SetConsoleCP(code_page);
2408: SetConsoleOutputCP(code_page);
2409: }
1.1.1.30 root 2410: int name_len = buffer[11];
2411: int file_len = buffer[12] | (buffer[13] << 8) | (buffer[14] << 16) | (buffer[15] << 24);
1.1.1.28 root 2412:
2413: // restore command file name
2414: memset(dummy_argv_1, 0, sizeof(dummy_argv_1));
2415: fread(dummy_argv_1, name_len, 1, fp);
2416:
2417: if(name_len != 0 && _access(dummy_argv_1, 0) == 0) {
2418: // if original command file exists, create a temporary file name
2419: if(GetTempFileName(_T("."), _T("DOS"), 0, dummy_argv_1) != 0) {
2420: // create a temporary command file in the current director
2421: DeleteFile(dummy_argv_1);
1.1.1.27 root 2422: } else {
1.1.1.28 root 2423: // create a temporary command file in the temporary folder
2424: GetTempPath(MAX_PATH, path);
2425: if(GetTempFileName(path, _T("DOS"), 0, dummy_argv_1) != 0) {
2426: DeleteFile(dummy_argv_1);
2427: } else {
2428: sprintf(dummy_argv_1, "%s$DOSPRG$.TMP", path);
2429: }
1.1.1.27 root 2430: }
1.1.1.28 root 2431: // check the command file type
2432: fread(buffer, 2, 1, fp);
2433: fseek(fp, -2, SEEK_CUR);
2434: if(memcmp(buffer, "MZ", 2) != 0) {
2435: memcpy(dummy_argv_1 + strlen(dummy_argv_1) - 4, ".COM", 4);
2436: } else {
2437: memcpy(dummy_argv_1 + strlen(dummy_argv_1) - 4, ".EXE", 4);
1.1.1.27 root 2438: }
2439: }
1.1.1.28 root 2440:
2441: // restore command file
2442: FILE* fo = fopen(dummy_argv_1, "wb");
2443: for(int i = 0; i < file_len; i++) {
2444: fputc(fgetc(fp), fo);
2445: }
2446: fclose(fo);
2447:
2448: GetFullPathName(dummy_argv_1, MAX_PATH, temp_file_path, NULL);
2449: temp_file_created = true;
2450: SetFileAttributes(temp_file_path, FILE_ATTRIBUTE_HIDDEN);
2451:
2452: // adjust argc/argv
2453: for(int i = 1; i < argc && (i + 1) < 256; i++) {
2454: dummy_argv[i + 1] = argv[i];
2455: }
2456: argc++;
2457: argv = dummy_argv;
1.1.1.27 root 2458: }
2459: fclose(fp);
2460: }
1.1.1.9 root 2461: for(int i = 1; i < argc; i++) {
1.1.1.25 root 2462: if(_strnicmp(argv[i], "-b", 2) == 0) {
2463: stay_busy = true;
2464: arg_offset++;
1.1.1.27 root 2465: } else if(_strnicmp(argv[i], "-c", 2) == 0) {
2466: if(argv[i][2] != '\0') {
2467: strcpy(new_exec_file, &argv[i][2]);
2468: } else {
2469: strcpy(new_exec_file, "new_exec_file.exe");
2470: }
2471: convert_cmd_file = true;
2472: arg_offset++;
1.1.1.28 root 2473: } else if(_strnicmp(argv[i], "-p", 2) == 0) {
2474: if(IS_NUMERIC(argv[i][2])) {
2475: code_page = atoi(&argv[i][2]);
2476: } else {
2477: code_page = GetConsoleCP();
2478: }
2479: arg_offset++;
1.1.1.25 root 2480: } else if(_strnicmp(argv[i], "-d", 2) == 0) {
2481: no_windows = true;
2482: arg_offset++;
2483: } else if(_strnicmp(argv[i], "-e", 2) == 0) {
1.1.1.9 root 2484: standard_env = 1;
2485: arg_offset++;
1.1.1.14 root 2486: } else if(_strnicmp(argv[i], "-i", 2) == 0) {
2487: ignore_illegal_insn = true;
2488: arg_offset++;
2489: } else if(_strnicmp(argv[i], "-m", 2) == 0) {
2490: limit_max_memory = true;
2491: arg_offset++;
2492: } else if(_strnicmp(argv[i], "-n", 2) == 0) {
1.1.1.17 root 2493: if(sscanf(argv[1] + 2, "%d,%d", &buf_height, &buf_width) != 2) {
2494: buf_width = buf_height = 0;
2495: }
2496: if(buf_width <= 0 || buf_width > 0x7fff) {
2497: buf_width = 80;
2498: }
2499: if(buf_height <= 0 || buf_height > 0x7fff) {
2500: buf_height = 25;
2501: }
1.1.1.14 root 2502: arg_offset++;
1.1.1.25 root 2503: } else if(_strnicmp(argv[i], "-s", 2) == 0) {
1.1.1.28 root 2504: if(IS_NUMERIC(argv[i][2])) {
1.1.1.29 root 2505: char *p0 = &argv[i][2], *p1, *p2, *p3;
2506: if((p1 = strchr(p0, ',')) != NULL && IS_NUMERIC(p1[1])) {
2507: sio_port_number[1] = atoi(p1 + 1);
2508: if((p2 = strchr(p1, ',')) != NULL && IS_NUMERIC(p2[1])) {
2509: sio_port_number[2] = atoi(p2 + 1);
2510: if((p3 = strchr(p2, ',')) != NULL && IS_NUMERIC(p3[1])) {
2511: sio_port_number[3] = atoi(p3 + 1);
2512: }
2513: }
1.1.1.25 root 2514: }
1.1.1.29 root 2515: sio_port_number[0] = atoi(p0);
1.1.1.25 root 2516: }
1.1.1.29 root 2517: 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 2518: get_sio_port_numbers();
1.1.1.25 root 2519: }
2520: arg_offset++;
1.1.1.9 root 2521: } else if(_strnicmp(argv[i], "-v", 2) == 0) {
1.1.1.17 root 2522: 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 2523: dos_major_version = argv[i][2] - '0';
2524: dos_minor_version = (argv[i][4] - '0') * 10 + (argv[i][5] ? (argv[i][5] - '0') : 0);
2525: }
2526: arg_offset++;
2527: } else if(_strnicmp(argv[i], "-w", 2) == 0) {
2528: 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]))) {
2529: win_major_version = argv[i][2] - '0';
2530: win_minor_version = (argv[i][4] - '0') * 10 + (argv[i][5] ? (argv[i][5] - '0') : 0);
1.1.1.9 root 2531: }
2532: arg_offset++;
1.1.1.25 root 2533: } else if(_strnicmp(argv[i], "-x", 2) == 0) {
2534: UMB_TOP = EMS_TOP + EMS_SIZE;
2535: support_ems = true;
2536: #ifdef SUPPORT_XMS
2537: support_xms = true;
2538: #endif
2539: arg_offset++;
1.1.1.9 root 2540: } else {
2541: break;
2542: }
2543: }
2544: if(argc < 2 + arg_offset) {
1.1 root 2545: #ifdef _WIN64
1.1.1.14 root 2546: fprintf(stderr, "MS-DOS Player (" CPU_MODEL_NAME(CPU_MODEL) ") for Win32-x64 console\n\n");
1.1 root 2547: #else
1.1.1.14 root 2548: fprintf(stderr, "MS-DOS Player (" CPU_MODEL_NAME(CPU_MODEL) ") for Win32 console\n\n");
1.1 root 2549: #endif
1.1.1.25 root 2550: fprintf(stderr,
1.1.1.28 root 2551: "Usage: MSDOS [-b] [-c[(new exec file)] [-p[P]]] [-d] [-e] [-i] [-m] [-n[L[,C]]]\n"
1.1.1.30 root 2552: " [-s[P1[,P2[,P3[,P4]]]]] [-vX.XX] [-wX.XX] [-x] (command) [options]\n"
1.1.1.25 root 2553: "\n"
2554: "\t-b\tstay busy during keyboard polling\n"
1.1.1.28 root 2555: #ifdef _WIN64
1.1.1.27 root 2556: "\t-c\tconvert command file to 64bit execution file\n"
1.1.1.28 root 2557: #else
1.1.1.27 root 2558: "\t-c\tconvert command file to 32bit execution file\n"
2559: #endif
1.1.1.28 root 2560: "\t-p\trecord current code page when convert command file\n"
1.1.1.25 root 2561: "\t-d\tpretend running under straight DOS, not Windows\n"
2562: "\t-e\tuse a reduced environment block\n"
2563: "\t-i\tignore invalid instructions\n"
2564: "\t-m\trestrict free memory to 0x7FFF paragraphs\n"
2565: "\t-n\tcreate a new buffer (25 lines, 80 columns by default)\n"
2566: "\t-s\tenable serial I/O and set host's COM port numbers\n"
2567: "\t-v\tset the DOS version\n"
1.1.1.30 root 2568: "\t-w\tset the Windows version\n"
1.1.1.19 root 2569: #ifdef SUPPORT_XMS
1.1.1.28 root 2570: "\t-x\tenable XMS and LIM EMS\n"
1.1.1.19 root 2571: #else
1.1.1.28 root 2572: "\t-x\tenable LIM EMS\n"
1.1.1.19 root 2573: #endif
2574: );
1.1.1.10 root 2575:
2576: if(!is_started_from_command_prompt()) {
2577: fprintf(stderr, "\nStart this program from a command prompt!\n\nHit any key to quit...");
2578: while(!_kbhit()) {
2579: Sleep(10);
2580: }
2581: }
1.1.1.20 root 2582: #ifdef _DEBUG
2583: _CrtDumpMemoryLeaks();
2584: #endif
1.1 root 2585: return(EXIT_FAILURE);
2586: }
1.1.1.27 root 2587: if(convert_cmd_file) {
2588: retval = EXIT_FAILURE;
1.1.1.28 root 2589: if(name != NULL/* && stricmp(name, "msdos.exe") == 0*/) {
1.1.1.27 root 2590: FILE *fp = NULL, *fs = NULL, *fo = NULL;
1.1.1.28 root 2591: int len = strlen(argv[arg_offset + 1]), data;
1.1.1.27 root 2592:
1.1.1.28 root 2593: if(!(len > 4 && (stricmp(argv[arg_offset + 1] + len - 4, ".COM") == 0 || stricmp(argv[arg_offset + 1] + len - 4, ".EXE") == 0))) {
2594: fprintf(stderr, "Specify command file with extenstion (.COM or .EXE)\n");
2595: } else if((fp = fopen(full, "rb")) == NULL) {
2596: fprintf(stderr, "Can't open '%s'\n", name);
1.1.1.27 root 2597: } else {
1.1.1.28 root 2598: long offset = get_section_in_exec_file(fp, ".msdos");
2599: if(offset != 0) {
2600: UINT8 buffer[14];
2601: fseek(fp, offset, SEEK_SET);
2602: fread(buffer, sizeof(buffer), 1, fp);
2603: memset(path, 0, sizeof(path));
2604: fread(path, buffer[9], 1, fp);
2605: fprintf(stderr, "Command file '%s' was already embedded to '%s'\n", path, name);
2606: } else if((fs = fopen(argv[arg_offset + 1], "rb")) == NULL) {
2607: fprintf(stderr, "Can't open '%s'\n", argv[arg_offset + 1]);
2608: } else if((fo = fopen(new_exec_file, "wb")) == NULL) {
2609: fprintf(stderr, "Can't open '%s'\n", new_exec_file);
2610: } else {
2611: // read pe header of msdos.exe
2612: UINT8 header[0x400];
2613: fseek(fp, 0, SEEK_SET);
2614: fread(header, sizeof(header), 1, fp);
2615:
2616: _IMAGE_DOS_HEADER *dosHeader = (_IMAGE_DOS_HEADER *)(header + 0);
2617: DWORD dwTopOfSignature = dosHeader->e_lfanew;
2618: DWORD dwTopOfCoffHeader = dwTopOfSignature + 4;
2619: _IMAGE_FILE_HEADER *coffHeader = (_IMAGE_FILE_HEADER *)(header + dwTopOfCoffHeader);
2620: DWORD dwTopOfOptionalHeader = dwTopOfCoffHeader + sizeof(_IMAGE_FILE_HEADER);
2621: _IMAGE_OPTIONAL_HEADER *optionalHeader = (_IMAGE_OPTIONAL_HEADER *)(header + dwTopOfOptionalHeader);
2622: DWORD dwTopOfFirstSectionHeader = dwTopOfOptionalHeader + coffHeader->SizeOfOptionalHeader;
2623:
2624: _IMAGE_SECTION_HEADER *lastSectionHeader = (_IMAGE_SECTION_HEADER *)(header + dwTopOfFirstSectionHeader + IMAGE_SIZEOF_SECTION_HEADER * (coffHeader->NumberOfSections - 1));
2625: DWORD dwEndOfFile = lastSectionHeader->PointerToRawData + lastSectionHeader->SizeOfRawData;
2626: DWORD dwLastSectionSize = lastSectionHeader->SizeOfRawData;
2627: DWORD dwExtraLastSectionBytes = dwLastSectionSize % optionalHeader->SectionAlignment;
2628: if(dwExtraLastSectionBytes != 0) {
2629: DWORD dwRemain = optionalHeader->SectionAlignment - dwExtraLastSectionBytes;
2630: dwLastSectionSize += dwRemain;
2631: }
2632: DWORD dwVirtualAddress = lastSectionHeader->VirtualAddress + dwLastSectionSize;
2633:
2634: // store msdos.exe
2635: fseek(fp, 0, SEEK_SET);
2636: for(int i = 0; i < dwEndOfFile; i++) {
2637: if((data = fgetc(fp)) != EOF) {
2638: fputc(data, fo);
2639: } else {
2640: // we should not reach here :-(
2641: fputc(0, fo);
2642: }
2643: }
2644:
2645: // store options
2646: UINT8 flags = 0;
2647: if(stay_busy) {
2648: flags |= 0x01;
2649: }
2650: if(no_windows) {
2651: flags |= 0x02;
2652: }
2653: if(standard_env) {
2654: flags |= 0x04;
2655: }
2656: if(ignore_illegal_insn) {
2657: flags |= 0x08;
2658: }
2659: if(limit_max_memory) {
2660: flags |= 0x10;
2661: }
1.1.1.29 root 2662: 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 2663: flags |= 0x20;
2664: }
2665: if(support_ems) {
2666: flags |= 0x40;
2667: }
1.1.1.30 root 2668: #ifdef SUPPORT_XMS
2669: if(support_xms) {
2670: flags |= 0x80;
2671: }
2672: #endif
1.1.1.28 root 2673:
2674: fputc(flags, fo);
2675: fputc((buf_width >> 0) & 0xff, fo);
2676: fputc((buf_width >> 8) & 0xff, fo);
2677: fputc((buf_height >> 0) & 0xff, fo);
2678: fputc((buf_height >> 8) & 0xff, fo);
1.1.1.30 root 2679: fputc(dos_major_version, fo);
2680: fputc(dos_minor_version, fo);
2681: fputc(win_major_version, fo);
2682: fputc(win_minor_version, fo);
1.1.1.28 root 2683: fputc((code_page >> 0) & 0xff, fo);
2684: fputc((code_page >> 8) & 0xff, fo);
2685:
2686: // store command file info
2687: GetFullPathName(argv[arg_offset + 1], MAX_PATH, full, &name);
2688: int name_len = strlen(name);
2689: fseek(fs, 0, SEEK_END);
2690: long file_size = ftell(fs);
2691:
2692: fputc(name_len, fo);
2693: fputc((file_size >> 0) & 0xff, fo);
2694: fputc((file_size >> 8) & 0xff, fo);
2695: fputc((file_size >> 16) & 0xff, fo);
2696: fputc((file_size >> 24) & 0xff, fo);
2697: fwrite(name, name_len, 1, fo);
2698:
2699: // store command file
2700: fseek(fs, 0, SEEK_SET);
2701: for(int i = 0; i < file_size; i++) {
2702: if((data = fgetc(fs)) != EOF) {
2703: fputc(data, fo);
2704: } else {
2705: // we should not reach here :-(
2706: fputc(0, fo);
2707: }
2708: }
2709:
2710: // store padding data and update pe header
1.1.1.29 root 2711: _IMAGE_SECTION_HEADER *newSectionHeader = (_IMAGE_SECTION_HEADER *)(header + dwTopOfFirstSectionHeader + IMAGE_SIZEOF_SECTION_HEADER * coffHeader->NumberOfSections);
2712: coffHeader->NumberOfSections++;
2713: memset(newSectionHeader, 0, IMAGE_SIZEOF_SECTION_HEADER);
2714: memcpy(newSectionHeader->Name, ".msdos", 6);
2715: newSectionHeader->VirtualAddress = dwVirtualAddress;
2716: newSectionHeader->PointerToRawData = dwEndOfFile;
2717: newSectionHeader->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_DISCARDABLE;
1.1.1.28 root 2718: newSectionHeader->SizeOfRawData = 14 + name_len + file_size;
2719: DWORD dwExtraRawBytes = newSectionHeader->SizeOfRawData % optionalHeader->FileAlignment;
2720: if(dwExtraRawBytes != 0) {
1.1.1.29 root 2721: static const char padding[] = "PADDINGXXPADDING";
1.1.1.28 root 2722: DWORD dwRemain = optionalHeader->FileAlignment - dwExtraRawBytes;
2723: for(int i = 0; i < dwRemain; i++) {
1.1.1.29 root 2724: if(i < 2) {
2725: fputc(padding[i & 15], fo);
2726: } else {
2727: fputc(padding[(i - 2) & 15], fo);
2728: }
1.1.1.28 root 2729: }
2730: newSectionHeader->SizeOfRawData += dwRemain;
2731: }
2732: newSectionHeader->Misc.VirtualSize = newSectionHeader->SizeOfRawData;
2733:
2734: DWORD dwNewSectionSize = newSectionHeader->SizeOfRawData;
2735: DWORD dwExtraNewSectionBytes = dwNewSectionSize % optionalHeader->SectionAlignment;
2736: if(dwExtraNewSectionBytes != 0) {
2737: DWORD dwRemain = optionalHeader->SectionAlignment - dwExtraNewSectionBytes;
2738: dwNewSectionSize += dwRemain;
2739: }
2740: optionalHeader->SizeOfImage += dwNewSectionSize;
2741:
2742: fseek(fo, 0, SEEK_SET);
2743: fwrite(header, sizeof(header), 1, fo);
2744:
2745: fprintf(stderr, "'%s' is successfully created\n", new_exec_file);
2746: retval = EXIT_SUCCESS;
1.1.1.27 root 2747: }
2748: }
2749: if(fp != NULL) {
2750: fclose(fp);
2751: }
2752: if(fs != NULL) {
2753: fclose(fs);
2754: }
2755: if(fo != NULL) {
2756: fclose(fo);
2757: }
2758: }
2759: #ifdef _DEBUG
2760: _CrtDumpMemoryLeaks();
2761: #endif
2762: return(retval);
2763: }
1.1 root 2764:
1.1.1.14 root 2765: is_vista_or_later = is_greater_windows_version(6, 0, 0, 0);
2766:
1.1.1.23 root 2767: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 2768: CONSOLE_SCREEN_BUFFER_INFO csbi;
1.1.1.14 root 2769: CONSOLE_CURSOR_INFO ci;
1.1.1.23 root 2770:
1.1.1.28 root 2771: get_console_info_success = (GetConsoleScreenBufferInfo(hStdout, &csbi) != 0);
1.1.1.14 root 2772: GetConsoleCursorInfo(hStdout, &ci);
1.1.1.24 root 2773: GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &dwConsoleMode);
1.1 root 2774:
1.1.1.14 root 2775: for(int y = 0; y < SCR_BUF_WIDTH; y++) {
2776: for(int x = 0; x < SCR_BUF_HEIGHT; x++) {
2777: SCR_BUF(y,x).Char.AsciiChar = ' ';
2778: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
1.1 root 2779: }
2780: }
1.1.1.28 root 2781: if(get_console_info_success) {
1.1.1.12 root 2782: scr_width = csbi.dwSize.X;
1.1.1.14 root 2783: scr_height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
2784:
1.1.1.28 root 2785: // v-text shadow buffer size must be lesser than 0x7fd0
2786: if((scr_width > SCR_BUF_WIDTH) || (scr_height > SCR_BUF_HEIGHT) || (scr_width * scr_height * 2 > 0x7fd0) ||
1.1.1.14 root 2787: (buf_width != 0 && buf_width != scr_width) || (buf_height != 0 && buf_height != scr_height)) {
2788: scr_width = min(buf_width != 0 ? buf_width : scr_width, SCR_BUF_WIDTH);
2789: scr_height = min(buf_height != 0 ? buf_height : scr_height, SCR_BUF_HEIGHT);
1.1.1.28 root 2790: if(scr_width * scr_height * 2 > 0x7fd0) {
1.1.1.14 root 2791: scr_width = 80;
2792: scr_height = 25;
2793: }
1.1.1.28 root 2794: screen_size_changed = true;
1.1.1.14 root 2795: }
1.1.1.12 root 2796: } else {
2797: // for a proof (not a console)
2798: scr_width = 80;
2799: scr_height = 25;
2800: }
1.1.1.14 root 2801: scr_buf_size.X = scr_width;
2802: scr_buf_size.Y = scr_height;
2803: scr_buf_pos.X = scr_buf_pos.Y = 0;
2804: scr_top = csbi.srWindow.Top;
1.1 root 2805: cursor_moved = false;
2806:
1.1.1.35 root 2807: #ifdef USE_SERVICE_THREAD
2808: InitializeCriticalSection(&input_crit_sect);
2809: InitializeCriticalSection(&key_buf_crit_sect);
2810: InitializeCriticalSection(&putch_crit_sect);
2811: #endif
1.1.1.25 root 2812: key_buf_char = new FIFO(256);
2813: key_buf_scan = new FIFO(256);
1.1 root 2814:
2815: hardware_init();
2816:
1.1.1.33 root 2817: #ifdef USE_DEBUGGER
2818: debugger_init();
2819: #endif
2820:
1.1.1.9 root 2821: if(msdos_init(argc - (arg_offset + 1), argv + (arg_offset + 1), envp, standard_env)) {
1.1 root 2822: retval = EXIT_FAILURE;
2823: } else {
1.1.1.27 root 2824: #if defined(_MSC_VER) && (_MSC_VER >= 1400)
1.1.1.14 root 2825: _set_invalid_parameter_handler((_invalid_parameter_handler)ignore_invalid_parameters);
2826: #endif
2827: SetConsoleCtrlHandler(ctrl_handler, TRUE);
2828:
1.1.1.28 root 2829: if(screen_size_changed) {
1.1.1.24 root 2830: change_console_size(scr_width, scr_height);
2831: }
1.1.1.8 root 2832: TIMECAPS caps;
2833: timeGetDevCaps(&caps, sizeof(TIMECAPS));
2834: timeBeginPeriod(caps.wPeriodMin);
1.1.1.35 root 2835: #ifdef USE_VRAM_THREAD
1.1.1.14 root 2836: InitializeCriticalSection(&vram_crit_sect);
2837: CloseHandle(CreateThread(NULL, 4096, vram_thread, NULL, 0, NULL));
2838: #endif
1.1.1.33 root 2839: #ifdef USE_DEBUGGER
2840: CloseHandle(CreateThread(NULL, 0, debugger_thread, NULL, 0, NULL));
2841: // wait until telnet client starts and connects to me
2842: if(_access(debugger_get_ttermpro_path(), 0) == 0 ||
2843: _access(debugger_get_ttermpro_x86_path(), 0) == 0 ||
2844: _access(debugger_get_putty_path(), 0) == 0 ||
2845: _access(debugger_get_putty_x86_path(), 0) == 0 ||
2846: _access(debugger_get_telnet_path(), 0) == 0) {
2847: for(int i = 0; i < 100 && cli_socket == 0; i++) {
2848: Sleep(100);
2849: }
2850: }
2851: #endif
1.1 root 2852: hardware_run();
1.1.1.35 root 2853: #ifdef USE_VRAM_THREAD
1.1.1.14 root 2854: vram_flush();
2855: DeleteCriticalSection(&vram_crit_sect);
2856: #endif
1.1.1.24 root 2857: timeEndPeriod(caps.wPeriodMin);
1.1.1.14 root 2858:
1.1.1.24 root 2859: // hStdin/hStdout (and all handles) will be closed in msdos_finish()...
1.1.1.28 root 2860: if(get_console_info_success) {
1.1.1.23 root 2861: hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.12 root 2862: if(restore_console_on_exit) {
1.1.1.14 root 2863: // window can't be bigger than buffer,
2864: // buffer can't be smaller than window,
2865: // so make a tiny window,
2866: // set the required buffer,
2867: // then set the required window
2868: SMALL_RECT rect;
2869: SET_RECT(rect, 0, csbi.srWindow.Top, 0, csbi.srWindow.Top);
2870: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1.1.1.12 root 2871: SetConsoleScreenBufferSize(hStdout, csbi.dwSize);
1.1.1.14 root 2872: SET_RECT(rect, 0, 0, csbi.srWindow.Right - csbi.srWindow.Left, csbi.srWindow.Bottom - csbi.srWindow.Top);
1.1.1.12 root 2873: SetConsoleWindowInfo(hStdout, TRUE, &rect);
2874: }
1.1.1.14 root 2875: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
2876: SetConsoleCursorInfo(hStdout, &ci);
1.1.1.12 root 2877: }
1.1.1.24 root 2878: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode);
2879:
1.1 root 2880: msdos_finish();
1.1.1.14 root 2881:
2882: SetConsoleCtrlHandler(ctrl_handler, FALSE);
1.1 root 2883: }
1.1.1.35 root 2884: if(temp_file_created) {
2885: DeleteFile(temp_file_path);
2886: temp_file_created = false;
2887: }
1.1.1.10 root 2888: hardware_finish();
2889:
1.1.1.28 root 2890: if(key_buf_char != NULL) {
2891: key_buf_char->release();
2892: delete key_buf_char;
2893: key_buf_char = NULL;
2894: }
2895: if(key_buf_scan != NULL) {
2896: key_buf_scan->release();
2897: delete key_buf_scan;
2898: key_buf_scan = NULL;
2899: }
1.1.1.35 root 2900: #ifdef USE_SERVICE_THREAD
2901: DeleteCriticalSection(&input_crit_sect);
2902: DeleteCriticalSection(&key_buf_crit_sect);
2903: DeleteCriticalSection(&putch_crit_sect);
2904: #endif
1.1.1.20 root 2905: #ifdef _DEBUG
2906: _CrtDumpMemoryLeaks();
2907: #endif
1.1 root 2908: return(retval);
2909: }
2910:
1.1.1.20 root 2911: /* ----------------------------------------------------------------------------
2912: console
2913: ---------------------------------------------------------------------------- */
2914:
1.1.1.14 root 2915: void change_console_size(int width, int height)
1.1.1.12 root 2916: {
1.1.1.23 root 2917: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.12 root 2918: CONSOLE_SCREEN_BUFFER_INFO csbi;
2919: SMALL_RECT rect;
2920: COORD co;
2921:
2922: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 2923: if(csbi.srWindow.Top != 0 || csbi.dwCursorPosition.Y > height - 1) {
2924: if(csbi.srWindow.Right - csbi.srWindow.Left + 1 == width && csbi.srWindow.Bottom - csbi.srWindow.Top + 1 == height) {
2925: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &csbi.srWindow);
2926: SET_RECT(rect, 0, 0, width - 1, height - 1);
2927: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2928: } else if(csbi.dwCursorPosition.Y > height - 1) {
2929: SET_RECT(rect, 0, csbi.dwCursorPosition.Y - (height - 1), width - 1, csbi.dwCursorPosition.Y);
2930: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2931: SET_RECT(rect, 0, 0, width - 1, height - 1);
2932: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1.1.12 root 2933: }
2934: }
1.1.1.14 root 2935: if(csbi.dwCursorPosition.Y > height - 1) {
1.1.1.12 root 2936: co.X = csbi.dwCursorPosition.X;
1.1.1.14 root 2937: co.Y = min(height - 1, csbi.dwCursorPosition.Y - csbi.srWindow.Top);
1.1.1.12 root 2938: SetConsoleCursorPosition(hStdout, co);
2939: cursor_moved = true;
2940: }
1.1.1.14 root 2941:
2942: // window can't be bigger than buffer,
2943: // buffer can't be smaller than window,
2944: // so make a tiny window,
2945: // set the required buffer,
2946: // then set the required window
2947: SET_RECT(rect, 0, csbi.srWindow.Top, 0, csbi.srWindow.Top);
1.1.1.12 root 2948: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1.1.1.14 root 2949: co.X = width;
2950: co.Y = height;
1.1.1.12 root 2951: SetConsoleScreenBufferSize(hStdout, co);
1.1.1.14 root 2952: SET_RECT(rect, 0, 0, width - 1, height - 1);
2953: SetConsoleWindowInfo(hStdout, TRUE, &rect);
2954:
2955: scr_width = scr_buf_size.X = width;
2956: scr_height = scr_buf_size.Y = height;
2957: scr_top = 0;
2958:
2959: clear_scr_buffer(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
2960:
2961: int regen = min(scr_width * scr_height * 2, 0x8000);
1.1.1.15 root 2962: text_vram_end_address = text_vram_top_address + regen;
2963: shadow_buffer_end_address = shadow_buffer_top_address + regen;
2964:
1.1.1.14 root 2965: if(regen > 0x4000) {
2966: regen = 0x8000;
2967: vram_pages = 1;
2968: } else if(regen > 0x2000) {
2969: regen = 0x4000;
2970: vram_pages = 2;
2971: } else if(regen > 0x1000) {
2972: regen = 0x2000;
2973: vram_pages = 4;
2974: } else {
2975: regen = 0x1000;
2976: vram_pages = 8;
2977: }
1.1.1.15 root 2978: *(UINT16 *)(mem + 0x44a) = scr_width;
2979: *(UINT16 *)(mem + 0x44c) = regen;
2980: *(UINT8 *)(mem + 0x484) = scr_height - 1;
2981:
1.1.1.24 root 2982: mouse.min_position.x = 0;
2983: mouse.min_position.y = 0;
1.1.1.34 root 2984: mouse.max_position.x = 8 * (scr_width - 1);
2985: mouse.max_position.y = 8 * (scr_height - 1);
1.1.1.24 root 2986:
1.1.1.15 root 2987: restore_console_on_exit = true;
1.1.1.14 root 2988: }
2989:
2990: void clear_scr_buffer(WORD attr)
2991: {
2992: for(int y = 0; y < scr_height; y++) {
2993: for(int x = 0; x < scr_width; x++) {
2994: SCR_BUF(y,x).Char.AsciiChar = ' ';
2995: SCR_BUF(y,x).Attributes = attr;
2996: }
2997: }
1.1.1.12 root 2998: }
2999:
1.1.1.24 root 3000: bool update_console_input()
1.1 root 3001: {
1.1.1.35 root 3002: #ifdef USE_SERVICE_THREAD
3003: EnterCriticalSection(&input_crit_sect);
3004: #endif
1.1.1.23 root 3005: HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
1.1.1.8 root 3006: DWORD dwNumberOfEvents = 0;
1.1 root 3007: DWORD dwRead;
3008: INPUT_RECORD ir[16];
1.1.1.24 root 3009: CONSOLE_SCREEN_BUFFER_INFO csbi = {0};
3010: bool result = false;
1.1 root 3011:
1.1.1.8 root 3012: if(GetNumberOfConsoleInputEvents(hStdin, &dwNumberOfEvents) && dwNumberOfEvents != 0) {
3013: if(ReadConsoleInputA(hStdin, ir, 16, &dwRead)) {
3014: for(int i = 0; i < dwRead; i++) {
1.1.1.24 root 3015: if(ir[i].EventType & MOUSE_EVENT) {
1.1.1.34 root 3016: if(mouse.hidden == 0) {
3017: // NOTE: if restore_console_on_exit, console is not scrolled
3018: if(!restore_console_on_exit && csbi.srWindow.Bottom == 0) {
3019: GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
3020: }
3021: // FIXME: character size is always 8x8 ???
3022: int x = 8 * (ir[i].Event.MouseEvent.dwMousePosition.X);
3023: int y = 8 * (ir[i].Event.MouseEvent.dwMousePosition.Y - csbi.srWindow.Top);
3024:
3025: if(mouse.position.x != x || mouse.position.y != y) {
3026: mouse.position.x = x;
3027: mouse.position.y = y;
3028: mouse.status |= 1;
3029: }
3030: }
3031: if(ir[i].Event.MouseEvent.dwEventFlags == 0) {
3032: for(int i = 0; i < MAX_MOUSE_BUTTONS; i++) {
3033: static const DWORD bits[] = {
3034: FROM_LEFT_1ST_BUTTON_PRESSED, // left
3035: RIGHTMOST_BUTTON_PRESSED, // right
3036: FROM_LEFT_2ND_BUTTON_PRESSED, // middle
3037: };
3038: bool prev_status = mouse.buttons[i].status;
3039: mouse.buttons[i].status = ((ir[i].Event.MouseEvent.dwButtonState & bits[i]) != 0);
3040:
3041: if(!prev_status && mouse.buttons[i].status) {
3042: mouse.buttons[i].pressed_times++;
3043: mouse.buttons[i].pressed_position.x = mouse.position.x;
3044: mouse.buttons[i].pressed_position.y = mouse.position.x;
3045: mouse.status |= 2 << (i * 2);
3046: } else if(prev_status && !mouse.buttons[i].status) {
3047: mouse.buttons[i].released_times++;
3048: mouse.buttons[i].released_position.x = mouse.position.x;
3049: mouse.buttons[i].released_position.y = mouse.position.x;
3050: mouse.status |= 4 << (i * 2);
1.1.1.14 root 3051: }
3052: }
3053: }
1.1.1.24 root 3054: } else if(ir[i].EventType & KEY_EVENT) {
1.1.1.33 root 3055: // update keyboard flags in bios data area
1.1.1.35 root 3056: if(ir[i].Event.KeyEvent.dwControlKeyState & CAPSLOCK_ON) {
3057: mem[0x417] |= 0x40;
1.1.1.33 root 3058: } else {
1.1.1.35 root 3059: mem[0x417] &= ~0x40;
1.1.1.33 root 3060: }
1.1.1.35 root 3061: if(ir[i].Event.KeyEvent.dwControlKeyState & NUMLOCK_ON) {
3062: mem[0x417] |= 0x20;
1.1.1.33 root 3063: } else {
1.1.1.35 root 3064: mem[0x417] &= ~0x20;
3065: }
3066: if(ir[i].Event.KeyEvent.dwControlKeyState & SCROLLLOCK_ON) {
3067: mem[0x417] |= 0x10;
3068: } else {
3069: mem[0x417] &= ~0x10;
1.1.1.33 root 3070: }
3071: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
3072: mem[0x417] |= 0x08;
3073: } else {
3074: mem[0x417] &= ~0x08;
3075: }
1.1.1.35 root 3076: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
3077: mem[0x417] |= 0x04;
1.1.1.33 root 3078: } else {
1.1.1.35 root 3079: mem[0x417] &= ~0x04;
1.1.1.33 root 3080: }
3081: if(ir[i].Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
3082: if(!(mem[0x417] & 0x03)) {
3083: mem[0x417] |= 0x02; // left shift
3084: }
3085: } else {
3086: mem[0x417] &= ~0x03;
3087: }
1.1.1.35 root 3088: if(ir[i].Event.KeyEvent.dwControlKeyState & LEFT_ALT_PRESSED) {
3089: mem[0x418] |= 0x02;
3090: } else {
3091: mem[0x418] &= ~0x02;
3092: }
3093: if(ir[i].Event.KeyEvent.dwControlKeyState & LEFT_CTRL_PRESSED) {
3094: mem[0x418] |= 0x01;
3095: } else {
3096: mem[0x418] &= ~0x01;
3097: }
1.1.1.33 root 3098:
1.1.1.28 root 3099: // set scan code of last pressed/release key to kbd_data (in-port 60h)
1.1.1.24 root 3100: kbd_data = ir[i].Event.KeyEvent.wVirtualScanCode;
1.1.1.33 root 3101: kbd_status |= 1;
3102:
3103: // update dos key buffer
3104: UINT8 chr = ir[i].Event.KeyEvent.uChar.AsciiChar;
3105: UINT8 scn = ir[i].Event.KeyEvent.wVirtualScanCode & 0xff;
3106:
3107: if(ir[i].Event.KeyEvent.bKeyDown) {
1.1.1.28 root 3108: // make
1.1.1.24 root 3109: kbd_data &= 0x7f;
3110:
1.1.1.33 root 3111: if(chr == 0x00) {
1.1.1.24 root 3112: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
3113: if(scn >= 0x3b && scn <= 0x44) {
3114: scn += 0x68 - 0x3b; // F1 to F10
3115: } else if(scn == 0x57 || scn == 0x58) {
3116: scn += 0x8b - 0x57; // F11 & F12
3117: } else if(scn >= 0x47 && scn <= 0x53) {
3118: scn += 0x97 - 0x47; // edit/arrow clusters
3119: } else if(scn == 0x35) {
3120: scn = 0xa4; // keypad /
3121: }
3122: } else if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
3123: if(scn == 0x07) {
3124: chr = 0x1e; // Ctrl+^
3125: } else if(scn == 0x0c) {
3126: chr = 0x1f; // Ctrl+_
3127: } else if(scn >= 0x35 && scn <= 0x58) {
3128: static const UINT8 ctrl_map[] = {
3129: 0x95, // keypad /
3130: 0,
3131: 0x96, // keypad *
3132: 0, 0, 0,
3133: 0x5e, // F1
3134: 0x5f, // F2
3135: 0x60, // F3
3136: 0x61, // F4
3137: 0x62, // F5
3138: 0x63, // F6
3139: 0x64, // F7
3140: 0x65, // F8
3141: 0x66, // F9
3142: 0x67, // F10
3143: 0,
3144: 0,
3145: 0x77, // Home
3146: 0x8d, // Up
3147: 0x84, // PgUp
3148: 0x8e, // keypad -
3149: 0x73, // Left
3150: 0x8f, // keypad center
3151: 0x74, // Right
3152: 0x90, // keyapd +
3153: 0x75, // End
3154: 0x91, // Down
3155: 0x76, // PgDn
3156: 0x92, // Insert
3157: 0x93, // Delete
3158: 0, 0, 0,
3159: 0x89, // F11
3160: 0x8a, // F12
3161: };
3162: scn = ctrl_map[scn - 0x35];
3163: }
3164: } else if(ir[i].Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
3165: if(scn >= 0x3b && scn <= 0x44) {
3166: scn += 0x54 - 0x3b; // F1 to F10
3167: } else if(scn == 0x57 || scn == 0x58) {
3168: scn += 0x87 - 0x57; // F11 & F12
3169: }
3170: } else if(scn == 0x57 || scn == 0x58) {
3171: scn += 0x85 - 0x57;
3172: }
3173: // ignore shift, ctrl, alt, win and menu keys
3174: if(scn != 0x1d && scn != 0x2a && scn != 0x36 && scn != 0x38 && (scn < 0x5b || scn > 0x5e)) {
1.1.1.32 root 3175: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 3176: #ifdef USE_SERVICE_THREAD
3177: EnterCriticalSection(&key_buf_crit_sect);
3178: #endif
1.1.1.32 root 3179: if(chr == 0) {
3180: key_buf_char->write(0x00);
3181: key_buf_scan->write(ir[i].Event.KeyEvent.dwControlKeyState & ENHANCED_KEY ? 0xe0 : 0x00);
3182: }
3183: key_buf_char->write(chr);
3184: key_buf_scan->write(scn);
1.1.1.35 root 3185: #ifdef USE_SERVICE_THREAD
3186: LeaveCriticalSection(&key_buf_crit_sect);
3187: #endif
1.1.1.24 root 3188: }
3189: }
3190: } else {
3191: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
3192: chr = 0;
3193: if(scn >= 0x02 && scn <= 0x0e) {
3194: scn += 0x78 - 0x02; // 1 to 0 - =
3195: }
3196: }
1.1.1.32 root 3197: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 3198: #ifdef USE_SERVICE_THREAD
3199: EnterCriticalSection(&key_buf_crit_sect);
3200: #endif
1.1.1.32 root 3201: key_buf_char->write(chr);
3202: key_buf_scan->write(scn);
1.1.1.35 root 3203: #ifdef USE_SERVICE_THREAD
3204: LeaveCriticalSection(&key_buf_crit_sect);
3205: #endif
1.1.1.32 root 3206: }
1.1.1.24 root 3207: }
1.1.1.33 root 3208: } else if(chr == 0x03 && (ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))) {
3209: // ctrl-break, ctrl-c
3210: if(scn == 0x46) {
3211: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 3212: #ifdef USE_SERVICE_THREAD
3213: EnterCriticalSection(&key_buf_crit_sect);
3214: #endif
1.1.1.33 root 3215: key_buf_char->write(0x00);
3216: key_buf_scan->write(0x00);
1.1.1.35 root 3217: #ifdef USE_SERVICE_THREAD
3218: LeaveCriticalSection(&key_buf_crit_sect);
3219: #endif
1.1.1.33 root 3220: }
3221: ctrl_break_pressed = true;
3222: mem[0x471] = 0x80;
3223: raise_int_1bh = true;
3224: } else {
3225: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 3226: #ifdef USE_SERVICE_THREAD
3227: EnterCriticalSection(&key_buf_crit_sect);
3228: #endif
1.1.1.33 root 3229: key_buf_char->write(chr);
3230: key_buf_scan->write(scn);
1.1.1.35 root 3231: #ifdef USE_SERVICE_THREAD
3232: LeaveCriticalSection(&key_buf_crit_sect);
3233: #endif
1.1.1.33 root 3234: }
3235: ctrl_c_pressed = (scn == 0x2e);
3236: }
3237: } else {
3238: // break
3239: kbd_data |= 0x80;
1.1 root 3240: }
1.1.1.24 root 3241: result = key_changed = true;
1.1.1.36 root 3242: // IME may be on and it may causes screen scroll up and cursor position change
3243: cursor_moved = true;
1.1 root 3244: }
3245: }
3246: }
3247: }
1.1.1.35 root 3248: #ifdef USE_SERVICE_THREAD
3249: LeaveCriticalSection(&input_crit_sect);
3250: #endif
1.1.1.24 root 3251: return(result);
1.1.1.8 root 3252: }
3253:
1.1.1.14 root 3254: bool update_key_buffer()
1.1.1.8 root 3255: {
1.1.1.35 root 3256: if(update_console_input()) {
3257: return(true);
3258: }
3259: if(key_buf_char != NULL && key_buf_scan != NULL) {
3260: #ifdef USE_SERVICE_THREAD
3261: EnterCriticalSection(&key_buf_crit_sect);
3262: #endif
3263: bool empty = key_buf_char->empty();
3264: #ifdef USE_SERVICE_THREAD
3265: LeaveCriticalSection(&key_buf_crit_sect);
3266: #endif
3267: if(!empty) return(true);
3268: }
3269: return(false);
1.1.1.8 root 3270: }
3271:
1.1.1.20 root 3272: /* ----------------------------------------------------------------------------
3273: MS-DOS virtual machine
3274: ---------------------------------------------------------------------------- */
3275:
1.1.1.32 root 3276: static const struct {
1.1.1.33 root 3277: char *name;
3278: DWORD lcid;
3279: char *std;
3280: char *dlt;
3281: } tz_table[] = {
3282: // https://science.ksc.nasa.gov/software/winvn/userguide/3_1_4.htm
3283: // 0 GMT Greenwich Mean Time GMT0
3284: {"GMT Standard Time", 0x0809, "GMT", "BST"}, // (UTC+00:00) GB London (en-gb)
3285: {"GMT Standard Time", 0x1809, "GMT", "IST"}, // (UTC+00:00) IE Dublin (en-ie)
3286: {"GMT Standard Time", 0x0000, "WET", "WES"}, // (UTC+00:00) PT Lisbon
3287: {"Greenwich Standard Time", 0x0000, "GMT", "GST"}, // (UTC+00:00) IS Reykjavik
3288: // 2 FST FDT Fernando De Noronha Std FST2FDT
3289: {"Mid-Atlantic Standard Time", 0x0416, "FST", "FDT"}, // (UTC-02:00) BR Noronha (pt-br)
3290: {"UTC-02", 0x0416, "FST", "FDT"}, // (UTC-02:00) BR Noronha (pt-br)
3291: // 3 BST Brazil Standard Time BST3
3292: {"Bahia Standard Time", 0x0000, "BST", "BDT"}, // (UTC-03:00) BR Bahia
3293: {"SA Eastern Standard Time", 0x0000, "BST", "BDT"}, // (UTC-03:00) BR Fortaleza
3294: {"Tocantins Standard Time", 0x0000, "BST", "BDT"}, // (UTC-03:00) BR Palmas
3295: // 3 EST EDT Eastern Standard (Brazil) EST3EDT
3296: {"E. South America Standard Time", 0x0000, "EST", "EDT"}, // (UTC-03:00) BR Sao Paulo
3297: // 3 GST Greenland Standard Time GST3
3298: {"Greenland Standard Time", 0x0000, "GST", "GDT"}, // (UTC-03:00) GL Godthab
3299: // 3:30 NST NDT Newfoundland Standard Time NST3:30NDT
3300: {"Newfoundland Standard Time", 0x0000, "NST", "NDT"}, // (UTC-03:30) CA St.Johns
3301: // 4 AST ADT Atlantic Standard Time AST4ADT
3302: {"Atlantic Standard Time", 0x0000, "AST", "ADT"}, // (UTC-04:00) CA Halifax
3303: // 4 WST WDT Western Standard (Brazil) WST4WDT
3304: {"Central Brazilian Standard Time", 0x0000, "WST", "WDT"}, // (UTC-04:00) BR Cuiaba
3305: {"SA Western Standard Time", 0x0000, "WST", "WDT"}, // (UTC-04:00) BR Manaus
3306: // 5 EST EDT Eastern Standard Time EST5EDT
3307: {"Eastern Standard Time", 0x0000, "EST", "EDT"}, // (UTC-05:00) US New York
3308: {"Eastern Standard Time (Mexico)", 0x0000, "EST", "EDT"}, // (UTC-05:00) MX Cancun
3309: {"US Eastern Standard Time", 0x0000, "EST", "EDT"}, // (UTC-05:00) US Indianapolis
3310: // 5 CST CDT Chile Standard Time CST5CDT
3311: {"Pacific SA Standard Time", 0x0000, "CST", "CDT"}, // (UTC-04:00) CL Santiago
3312: // 5 AST ADT Acre Standard Time AST5ADT
3313: {"SA Pacific Standard Time", 0x0000, "AST", "ADT"}, // (UTC-05:00) BR Rio Branco
3314: // 5 CST CDT Cuba Standard Time CST5CDT
3315: {"Cuba Standard Time", 0x0000, "CST", "CDT"}, // (UTC-05:00) CU Havana
3316: // 6 CST CDT Central Standard Time CST6CDT
3317: {"Canada Central Standard Time", 0x0000, "CST", "CDT"}, // (UTC-06:00) CA Regina
3318: {"Central Standard Time", 0x0000, "CST", "CDT"}, // (UTC-06:00) US Chicago
3319: {"Central Standard Time (Mexico)", 0x0000, "CST", "CDT"}, // (UTC-06:00) MX Mexico City
3320: // 6 EST EDT Easter Island Standard EST6EDT
3321: {"Easter Island Standard Time", 0x0000, "EST", "EDT"}, // (UTC-06:00) CL Easter
3322: // 7 MST MDT Mountain Standard Time MST7MDT
3323: {"Mountain Standard Time", 0x0000, "MST", "MDT"}, // (UTC-07:00) US Denver
3324: {"Mountain Standard Time (Mexico)", 0x0000, "MST", "MDT"}, // (UTC-07:00) MX Chihuahua
3325: {"US Mountain Standard Time", 0x0000, "MST", "MDT"}, // (UTC-07:00) US Phoenix
3326: // 8 PST PDT Pacific Standard Time PST8PDT
3327: {"Pacific Standard Time", 0x0000, "PST", "PDT"}, // (UTC-08:00) US Los Angeles
3328: {"Pacific Standard Time (Mexico)", 0x0000, "PST", "PDT"}, // (UTC-08:00) MX Tijuana
3329: // 9 AKS AKD Alaska Standard Time AKS9AKD
3330: // 9 YST YDT Yukon Standard Time YST9YST
3331: {"Alaskan Standard Time", 0x0000, "AKS", "AKD"}, // (UTC-09:00) US Anchorage
3332: // 10 HST HDT Hawaii Standard Time HST10HDT
3333: {"Aleutian Standard Time", 0x0000, "HST", "HDT"}, // (UTC-10:00) US Aleutian
3334: {"Hawaiian Standard Time", 0x0000, "HST", "HDT"}, // (UTC-10:00) US Honolulu
3335: // 11 SST Samoa Standard Time SST11
3336: {"Samoa Standard Time", 0x0000, "SST", "SDT"}, // (UTC-11:00) US Samoa
3337: // -12 NZS NZD New Zealand Standard Time NZS-12NZD
3338: {"New Zealand Standard Time", 0x0000, "NZS", "NZD"}, // (UTC+12:00) NZ Auckland
3339: // -10 GST Guam Standard Time GST-10
3340: {"West Pacific Standard Time", 0x0000, "GST", "GDT"}, // (UTC+10:00) GU Guam
3341: // -10 EAS EAD Eastern Australian Standard EAS-10EAD
3342: {"AUS Eastern Standard Time", 0x0000, "EAS", "EAD"}, // (UTC+10:00) AU Sydney
3343: {"E. Australia Standard Time", 0x0000, "EAS", "EAD"}, // (UTC+10:00) AU Brisbane
3344: {"Tasmania Standard Time", 0x0000, "EAS", "EAD"}, // (UTC+10:00) AU Hobart
3345: // -9:30 CAS CAD Central Australian Standard CAS-9:30CAD
3346: {"AUS Central Standard Time", 0x0000, "CAS", "CAD"}, // (UTC+09:30) AU Darwin
3347: {"Cen. Australia Standard Time", 0x0000, "CAS", "CAD"}, // (UTC+09:30) AU Adelaide
3348: // -9 JST Japan Standard Time JST-9
3349: {"Tokyo Standard Time", 0x0000, "JST", "JDT"}, // (UTC+09:00) JP Tokyo
3350: // -9 KST KDT Korean Standard Time KST-9KDT
3351: {"Korea Standard Time", 0x0000, "KST", "KDT"}, // (UTC+09:00) KR Seoul
3352: {"North Korea Standard Time", 0x0000, "KST", "KDT"}, // (UTC+08:30) KP Pyongyang
3353: // -8 HKT Hong Kong Time HKT-8
3354: {"China Standard Time", 0x0C04, "HKT", "HKS"}, // (UTC+08:00) HK Hong Kong (zh-hk)
3355: // -8 CCT China Coast Time CCT-8
3356: {"China Standard Time", 0x0000, "CCT", "CDT"}, // (UTC+08:00) CN Shanghai
3357: {"Taipei Standard Time", 0x0000, "CCT", "CDT"}, // (UTC+08:00) TW Taipei
3358: // -8 SST Singapore Standard Time SST-8
3359: {"Singapore Standard Time", 0x0000, "SST", "SDT"}, // (UTC+08:00) SG Singapore
3360: // -8 WAS WAD Western Australian Standard WAS-8WAD
3361: {"Aus Central W. Standard Time", 0x0000, "WAS", "WAD"}, // (UTC+08:45) AU Eucla
3362: {"W. Australia Standard Time", 0x0000, "WAS", "WAD"}, // (UTC+08:00) AU Perth
3363: // -7:30 JT Java Standard Time JST-7:30
3364: // -7 NST North Sumatra Time NST-7
3365: {"SE Asia Standard Time", 0x0000, "NST", "NDT"}, // (UTC+07:00) ID Jakarta
3366: // -5:30 IST Indian Standard Time IST-5:30
3367: {"India Standard Time", 0x0000, "IST", "IDT"}, // (UTC+05:30) IN Calcutta
3368: // -3:30 IST IDT Iran Standard Time IST-3:30IDT
3369: {"Iran Standard Time", 0x0000, "IST", "IDT"}, // (UTC+03:30) IR Tehran
3370: // -3 MSK MSD Moscow Winter Time MSK-3MSD
3371: {"Belarus Standard Time", 0x0000, "MSK", "MSD"}, // (UTC+03:00) BY Minsk
3372: {"Russian Standard Time", 0x0000, "MSK", "MSD"}, // (UTC+03:00) RU Moscow
3373: // -2 EET Eastern Europe Time EET-2
3374: {"E. Europe Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) MD Chisinau
3375: {"FLE Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) UA Kiev
3376: {"GTB Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) RO Bucharest
3377: {"Kaliningrad Standard Time", 0x0000, "EET", "EES"}, // (UTC+02:00) RU Kaliningrad
3378: // -2 IST IDT Israel Standard Time IST-2IDT
3379: {"Israel Standard Time", 0x0000, "IST", "IDT"}, // (UTC+02:00) IL Jerusalem
3380: // -1 MEZ MES Middle European Time MEZ-1MES
3381: // -1 SWT SST Swedish Winter Time SWT-1SST
3382: // -1 FWT FST French Winter Time FWT-1FST
3383: // -1 CET CES Central European Time CET-1CES
3384: {"Central Europe Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) HU Budapest
3385: {"Central European Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) PL Warsaw
3386: {"Romance Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) FR Paris
3387: {"W. Europe Standard Time", 0x0000, "CET", "CES"}, // (UTC+01:00) DE Berlin
3388: // -1 WAT West African Time WAT-1
3389: {"Namibia Standard Time", 0x0000, "WAT", "WAS"}, // (UTC+01:00) NA Windhoek
3390: {"W. Central Africa Standard Time", 0x0000, "WAT", "WAS"}, // (UTC+01:00) NG Lagos
3391: // 0 UTC Universal Coordinated Time UTC0
3392: {"UTC", 0x0000, "UTC", "" }, // (UTC+00:00) GMT+0
3393: {"UTC-02", 0x0000, "UTC", "" }, // (UTC-02:00) GMT+2
3394: {"UTC-08", 0x0000, "UTC", "" }, // (UTC-08:00) GMT+8
3395: {"UTC-09", 0x0000, "UTC", "" }, // (UTC-09:00) GMT+9
3396: {"UTC-11", 0x0000, "UTC", "" }, // (UTC-11:00) GMT+11
3397: {"UTC+12", 0x0000, "UTC", "" }, // (UTC+12:00) GMT-12
3398: };
3399:
3400: static const struct {
1.1.1.32 root 3401: UINT16 code;
3402: char *message_english;
3403: char *message_japanese;
3404: } standard_error_table[] = {
3405: {0x01, "Invalid function", "�����ȃt�@���N�V�����ł�."},
3406: {0x02, "File not found", "�t�@�C����������܂���."},
3407: {0x03, "Path not found", "�p�X��������܂���."},
3408: {0x04, "Too many open files", "�J����Ă���t�@�C�����������܂�."},
3409: {0x05, "Access denied", "�A�N�Z�X�͋��ۂ���܂���."},
3410: {0x06, "Invalid handle", "�����ȃn���h���ł�."},
3411: {0x07, "Memory control blocks destroyed", "����������u���b�N���j������܂���."},
3412: {0x08, "Insufficient memory", "������������܂���."},
3413: {0x09, "Invalid memory block address", "�����ȃ������u���b�N�̃A�h���X�ł�."},
3414: {0x0A, "Invalid Environment", "�����Ȋ��ł�."},
3415: {0x0B, "Invalid format", "�����ȃt�H�[�}�b�g�ł�."},
3416: {0x0C, "Invalid function parameter", "�����ȃt�@���N�V�����p�����[�^�ł�."},
3417: {0x0D, "Invalid data", "�����ȃf�[�^�ł�."},
3418: {0x0F, "Invalid drive specification", "�����ȃh���C�u�̎w��ł�."},
3419: {0x10, "Attempt to remove current directory", "���݂̃f�B���N�g�����폜���悤�Ƃ��܂���."},
3420: {0x11, "Not same device", "�����f�o�C�X�ł͂���܂���."},
3421: {0x12, "No more files", "�t�@�C���͂���ȏ゠��܂���."},
3422: {0x13, "Write protect error", "�������ݕی�G���[�ł�."},
3423: {0x14, "Invalid unit", "�����ȃ��j�b�g�ł�."},
3424: {0x15, "Not ready", "�������ł��Ă��܂���."},
3425: {0x16, "Invalid device request", "�����ȃf�o�C�X�v���ł�."},
3426: {0x17, "Data error", "�f�[�^�G���[�ł�."},
3427: {0x18, "Invalid device request parameters", "�����ȃf�o�C�X�v���̃p�����[�^�ł�."},
3428: {0x19, "Seek error", "�V�[�N�G���[�ł�."},
3429: {0x1A, "Invalid media type", "�����ȃ��f�B�A�̎�ނł�."},
3430: {0x1B, "Sector not found", "�Z�N�^��������܂���."},
3431: {0x1C, "Printer out of paper error", "�v�����^�̗p��������܂���."},
3432: {0x1D, "Write fault error", "�������݃G���[�ł�."},
3433: {0x1E, "Read fault error", "�ǂݎ��G���[�ł�."},
3434: {0x1F, "General failure", "�G���[�ł�."},
3435: {0x20, "Sharing violation", "���L�ᔽ�ł�."},
3436: {0x21, "Lock violation", "���b�N�ᔽ�ł�."},
3437: {0x22, "Invalid disk change", "�����ȃf�B�X�N�̌����ł�."},
3438: {0x23, "FCB unavailable", "FCB �͎g���܂���."},
3439: {0x24, "System resource exhausted", "�V�X�e�����\�[�X�͂����g���܂���."},
3440: {0x25, "Code page mismatch", "�R�[�h �y�[�W����v���܂���."},
3441: {0x26, "Out of input", "���͂��I���܂���."},
3442: {0x27, "Insufficient disk space", "�f�B�X�N�̋̈悪����܂���."},
3443: /*
3444: {0x32, "Network request not supported", NULL},
3445: {0x33, "Remote computer not listening", NULL},
3446: {0x34, "Duplicate name on network", NULL},
3447: {0x35, "Network name not found", NULL},
3448: {0x36, "Network busy", NULL},
3449: {0x37, "Network device no longer exists", NULL},
3450: {0x38, "Network BIOS command limit exceeded", NULL},
3451: {0x39, "Network adapter hardware error", NULL},
3452: {0x3A, "Incorrect response from network", NULL},
3453: {0x3B, "Unexpected network error", NULL},
3454: {0x3C, "Incompatible remote adapter", NULL},
3455: {0x3D, "Print queue full", NULL},
3456: {0x3E, "Queue not full", NULL},
3457: {0x3F, "Not enough space to print file", NULL},
3458: {0x40, "Network name was deleted", NULL},
3459: {0x41, "Network: Access denied", NULL},
3460: {0x42, "Network device type incorrect", NULL},
3461: {0x43, "Network name not found", NULL},
3462: {0x44, "Network name limit exceeded", NULL},
3463: {0x45, "Network BIOS session limit exceeded", NULL},
3464: {0x46, "Temporarily paused", NULL},
3465: {0x47, "Network request not accepted", NULL},
3466: {0x48, "Network print/disk redirection paused", NULL},
3467: {0x49, "Network software not installed", NULL},
3468: {0x4A, "Unexpected adapter close", NULL},
3469: */
3470: {0x50, "File exists", "�t�@�C���͑��݂��܂�."},
1.1.1.33 root 3471: {0x52, "Cannot make directory entry", "�f�B���N�g���G���g�����쐬�ł��܂���."},
1.1.1.32 root 3472: {0x53, "Fail on INT 24", "INT 24 �Ŏ��s���܂���."},
3473: {0x54, "Too many redirections", "���_�C���N�g���������܂�."},
3474: {0x55, "Duplicate redirection", "���_�C���N�g���d�����Ă��܂�."},
3475: {0x56, "Invalid password", "�p�X���[�h���Ⴂ�܂�."},
3476: {0x57, "Invalid parameter", "�p�����[�^�̎w�肪�Ⴂ�܂�."},
3477: {0x58, "Network data fault", "�l�b�g���[�N�f�[�^�̃G���[�ł�."},
3478: {0x59, "Function not supported by network", "�t�@���N�V�����̓l�b�g���[�N�ŃT�|�[�g����Ă��܂���."},
3479: {0x5A, "Required system component not installe", "�K�v�ȃV�X�e�� �R���|�[�l���g���g�ݍ��܂�Ă��܂���."},
3480: /*
3481: {0x64, "Unknown error", "�s���ȃG���[�ł�."},
3482: {0x65, "Not ready", "�������ł��Ă��܂���."},
3483: {0x66, "EMS memory no longer valid", "EMS �������͂����L���ł͂���܂���."},
3484: {0x67, "CDROM not High Sierra or ISO-9660 format", "CDROM �� High Sierra �܂��� ISO-9660 �t�H�[�}�b�g�ł͂���܂���."},
3485: {0x68, "Door open", "���o�[���܂��Ă��܂���."
3486: */
3487: {0xB0, "Volume is not locked", "�{�����[�������b�N����Ă��܂���."},
3488: {0xB1, "Volume is locked in drive", "�{�����[�������b�N����Ă��܂�."},
3489: {0xB2, "Volume is not removable", "�{�����[���͎��O���ł��܂���."},
3490: {0xB4, "Lock count has been exceeded", "�{�����[��������ȏネ�b�N�ł��܂���."},
3491: {0xB5, "A valid eject request failed", "���o���Ɏ��s���܂���."},
3492: {-1 , "Unknown error", "�s���ȃG���[�ł�."},
3493: };
3494:
3495: static const struct {
3496: UINT16 code;
3497: char *message_english;
3498: char *message_japanese;
3499: } param_error_table[] = {
3500: {0x01, "Too many parameters", "�p�����[�^���������܂�."},
3501: {0x02, "Required parameter missing", "�p�����[�^������܂���."},
3502: {0x03, "Invalid switch", "�����ȃX�C�b�`�ł�."},
3503: {0x04, "Invalid keyword", "�����ȃL�[���[�h�ł�."},
3504: {0x06, "Parameter value not in allowed range", "�p�����[�^�̒l���͈͂��Ă��܂�."},
3505: {0x07, "Parameter value not allowed", "���̃p�����[�^�̒l�͎g���܂���."},
3506: {0x08, "Parameter value not allowed", "���̃p�����[�^�̒l�͎g���܂���."},
3507: {0x09, "Parameter format not correct", "�p�����[�^�̏������Ⴂ�܂�."},
3508: {0x0A, "Invalid parameter", "�����ȃp�����[�^�ł�."},
3509: {0x0B, "Invalid parameter combination", "�����ȃp�����[�^�̑g�ݍ��킹�ł�."},
3510: {-1 , "Unknown error", "�s���ȃG���[�ł�."},
3511: };
3512:
3513: static const struct {
3514: UINT16 code;
3515: char *message_english;
3516: char *message_japanese;
3517: } critical_error_table[] = {
3518: {0x00, "Write protect error", "�������ݕی�G���[�ł�."},
3519: {0x01, "Invalid unit", "�����ȃ��j�b�g�ł�."},
3520: {0x02, "Not ready", "�������ł��Ă��܂���."},
3521: {0x03, "Invalid device request", "�����ȃf�o�C�X�v���ł�."},
3522: {0x04, "Data error", "�f�[�^�G���[�ł�."},
3523: {0x05, "Invalid device request parameters", "�����ȃf�o�C�X�v���̃p�����[�^�ł�."},
3524: {0x06, "Seek error", "�V�[�N�G���[�ł�."},
3525: {0x07, "Invalid media type", "�����ȃ��f�B�A�̎�ނł�."},
3526: {0x08, "Sector not found", "�Z�N�^��������܂���."},
3527: {0x09, "Printer out of paper error", "�v�����^�̗p��������܂���."},
3528: {0x0A, "Write fault error", "�������݃G���[�ł�."},
3529: {0x0B, "Read fault error", "�ǂݎ��G���[�ł�."},
3530: {0x0C, "General failure", "�G���[�ł�."},
3531: {0x0D, "Sharing violation", "���L�ᔽ�ł�."},
3532: {0x0E, "Lock violation", "���b�N�ᔽ�ł�."},
3533: {0x0F, "Invalid disk change", "�����ȃf�B�X�N�̌����ł�."},
3534: {0x10, "FCB unavailable", "FCB �͎g���܂���."},
3535: {0x11, "System resource exhausted", "�V�X�e�����\�[�X�͂����g���܂���."},
3536: {0x12, "Code page mismatch", "�R�[�h �y�[�W����v���܂���."},
3537: {0x13, "Out of input", "���͂��I���܂���."},
3538: {0x14, "Insufficient disk space", "�f�B�X�N�̋̈悪����܂���."},
3539: {-1 , "Critical error", "�v���I�ȃG���[�ł�."},
3540: };
3541:
1.1.1.20 root 3542: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg);
3543: int msdos_psp_get_file_table(int fd, int psp_seg);
3544: void msdos_putch(UINT8 data);
1.1.1.35 root 3545: #ifdef USE_SERVICE_THREAD
3546: void msdos_putch_tmp(UINT8 data);
3547: #endif
1.1.1.20 root 3548:
1.1 root 3549: // process info
3550:
3551: process_t *msdos_process_info_create(UINT16 psp_seg)
3552: {
3553: for(int i = 0; i < MAX_PROCESS; i++) {
3554: if(process[i].psp == 0 || process[i].psp == psp_seg) {
3555: memset(&process[i], 0, sizeof(process_t));
3556: process[i].psp = psp_seg;
3557: return(&process[i]);
3558: }
3559: }
3560: fatalerror("too many processes\n");
3561: return(NULL);
3562: }
3563:
1.1.1.33 root 3564: process_t *msdos_process_info_get(UINT16 psp_seg, bool show_error)
1.1 root 3565: {
3566: for(int i = 0; i < MAX_PROCESS; i++) {
3567: if(process[i].psp == psp_seg) {
3568: return(&process[i]);
3569: }
3570: }
1.1.1.33 root 3571: if(show_error) {
3572: fatalerror("invalid psp address\n");
3573: }
1.1 root 3574: return(NULL);
3575: }
3576:
1.1.1.33 root 3577: process_t *msdos_process_info_get(UINT16 psp_seg)
3578: {
3579: return(msdos_process_info_get(psp_seg, true));
3580: }
3581:
1.1.1.23 root 3582: void msdos_sda_update(int psp_seg)
3583: {
3584: sda_t *sda = (sda_t *)(mem + SDA_TOP);
3585:
3586: for(int i = 0; i < MAX_PROCESS; i++) {
3587: if(process[i].psp == psp_seg) {
3588: sda->switchar = process[i].switchar;
3589: sda->current_dta.w.l = process[i].dta.w.l;
3590: sda->current_dta.w.h = process[i].dta.w.h;
3591: sda->current_psp = process[i].psp;
3592: break;
3593: }
3594: }
3595: sda->malloc_strategy = malloc_strategy;
3596: sda->return_code = retval;
3597: sda->current_drive = _getdrive();
3598: }
3599:
1.1.1.13 root 3600: // dta info
3601:
3602: void msdos_dta_info_init()
3603: {
1.1.1.14 root 3604: for(int i = 0; i < MAX_DTAINFO; i++) {
1.1.1.13 root 3605: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
3606: }
3607: }
3608:
3609: dtainfo_t *msdos_dta_info_get(UINT16 psp_seg, UINT32 dta_laddr)
3610: {
3611: dtainfo_t *free_dta = NULL;
1.1.1.14 root 3612: for(int i = 0; i < MAX_DTAINFO; i++) {
3613: if(dtalist[i].find_handle == INVALID_HANDLE_VALUE) {
3614: if(free_dta == NULL) {
1.1.1.13 root 3615: free_dta = &dtalist[i];
3616: }
1.1.1.14 root 3617: } else if(dta_laddr < LFN_DTA_LADDR && dtalist[i].dta == dta_laddr) {
1.1.1.13 root 3618: return(&dtalist[i]);
3619: }
3620: }
1.1.1.14 root 3621: if(free_dta) {
1.1.1.13 root 3622: free_dta->psp = psp_seg;
3623: free_dta->dta = dta_laddr;
3624: return(free_dta);
3625: }
3626: fatalerror("too many dta\n");
3627: return(NULL);
3628: }
3629:
3630: void msdos_dta_info_free(UINT16 psp_seg)
3631: {
1.1.1.14 root 3632: for(int i = 0; i < MAX_DTAINFO; i++) {
3633: if(dtalist[i].psp == psp_seg && dtalist[i].find_handle != INVALID_HANDLE_VALUE) {
1.1.1.13 root 3634: FindClose(dtalist[i].find_handle);
3635: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
3636: }
3637: }
3638: }
3639:
1.1 root 3640: void msdos_cds_update(int drv)
3641: {
3642: cds_t *cds = (cds_t *)(mem + CDS_TOP);
3643:
3644: memset(mem + CDS_TOP, 0, CDS_SIZE);
3645: sprintf(cds->path_name, "%c:\\", 'A' + drv);
3646: cds->drive_attrib = 0x4000; // physical drive
3647: cds->physical_drive_number = drv;
3648: }
3649:
1.1.1.17 root 3650: // nls information tables
3651:
3652: // uppercase table (func 6502h)
3653: void msdos_upper_table_update()
3654: {
3655: *(UINT16 *)(mem + UPPERTABLE_TOP) = 0x80;
1.1.1.22 root 3656: for(unsigned i = 0; i < 0x80; ++i) {
1.1.1.17 root 3657: UINT8 c[4];
1.1.1.33 root 3658: *(UINT32 *)c = 0; // reset internal conversion state
3659: CharUpperBuffA((LPSTR)c, 4); // (workaround for MBCS codepage)
1.1.1.17 root 3660: c[0] = 0x80 + i;
3661: DWORD rc = CharUpperBuffA((LPSTR)c, 1);
3662: mem[UPPERTABLE_TOP + 2 + i] = (rc == 1 && c[0]) ? c[0] : 0x80 + i;
3663: }
3664: }
3665:
1.1.1.23 root 3666: // lowercase table (func 6503h)
3667: void msdos_lower_table_update()
3668: {
3669: *(UINT16 *)(mem + LOWERTABLE_TOP) = 0x80;
3670: for(unsigned i = 0; i < 0x80; ++i) {
3671: UINT8 c[4];
1.1.1.33 root 3672: *(UINT32 *)c = 0; // reset internal conversion state
3673: CharLowerBuffA((LPSTR)c, 4); // (workaround for MBCS codepage)
1.1.1.23 root 3674: c[0] = 0x80 + i;
3675: DWORD rc = CharLowerBuffA((LPSTR)c, 1);
3676: mem[LOWERTABLE_TOP + 2 + i] = (rc == 1 && c[0]) ? c[0] : 0x80 + i;
3677: }
3678: }
3679:
1.1.1.17 root 3680: // filename uppercase table (func 6504h)
3681: void msdos_filename_upper_table_init()
3682: {
3683: // depended on (file)system, not on active codepage
3684: // temporary solution: just filling data
3685: *(UINT16 *)(mem + FILENAME_UPPERTABLE_TOP) = 0x80;
1.1.1.22 root 3686: for(unsigned i = 0; i < 0x80; ++i) {
1.1.1.17 root 3687: mem[FILENAME_UPPERTABLE_TOP + 2 + i] = 0x80 + i;
3688: }
3689: }
3690:
3691: // filaname terminator table (func 6505h)
3692: void msdos_filename_terminator_table_init()
3693: {
3694: const char illegal_chars[] = ".\"/\\[]:|<>+=;,"; // for standard MS-DOS fs.
3695: UINT8 *data = mem + FILENAME_TERMINATOR_TOP;
3696:
3697: data[2] = 1; // marker? (permissible character value)
3698: data[3] = 0x00; // 00h...FFh
3699: data[4] = 0xff;
3700: data[5] = 0; // marker? (excluded character)
3701: data[6] = 0x00; // 00h...20h
3702: data[7] = 0x20;
3703: data[8] = 2; // marker? (illegal characters for filename)
3704: data[9] = (UINT8)strlen(illegal_chars);
3705: memcpy(data + 10, illegal_chars, data[9]);
3706:
3707: // total length
3708: *(UINT16 *)data = (10 - 2) + data[9];
3709: }
3710:
3711: // collating table (func 6506h)
3712: void msdos_collating_table_update()
3713: {
3714: // temporary solution: just filling data
3715: *(UINT16 *)(mem + COLLATING_TABLE_TOP) = 0x100;
1.1.1.22 root 3716: for(unsigned i = 0; i < 256; ++i) {
1.1.1.17 root 3717: mem[COLLATING_TABLE_TOP + 2 + i] = i;
3718: }
3719: }
3720:
1.1 root 3721: // dbcs
3722:
3723: void msdos_dbcs_table_update()
3724: {
3725: UINT8 dbcs_data[DBCS_SIZE];
3726: memset(dbcs_data, 0, sizeof(dbcs_data));
3727:
3728: CPINFO info;
3729: GetCPInfo(active_code_page, &info);
3730:
3731: if(info.MaxCharSize != 1) {
3732: for(int i = 0;; i += 2) {
3733: UINT8 lo = info.LeadByte[i + 0];
3734: UINT8 hi = info.LeadByte[i + 1];
3735: dbcs_data[2 + i + 0] = lo;
3736: dbcs_data[2 + i + 1] = hi;
3737: if(lo == 0 && hi == 0) {
3738: dbcs_data[0] = i + 2;
3739: break;
3740: }
3741: }
3742: } else {
3743: dbcs_data[0] = 2; // ???
3744: }
3745: memcpy(mem + DBCS_TOP, dbcs_data, sizeof(dbcs_data));
3746: }
3747:
1.1.1.17 root 3748: void msdos_dbcs_table_finish()
3749: {
1.1.1.32 root 3750: if(system_code_page != _getmbcp()) {
1.1.1.17 root 3751: _setmbcp(system_code_page);
3752: }
1.1.1.32 root 3753: if(console_code_page != GetConsoleCP()) {
3754: SetConsoleCP(console_code_page);
3755: SetConsoleOutputCP(console_code_page);
3756: }
1.1.1.17 root 3757: }
3758:
3759: void msdos_nls_tables_init()
1.1 root 3760: {
1.1.1.32 root 3761: active_code_page = console_code_page = GetConsoleCP();
3762: system_code_page = _getmbcp();
3763:
3764: if(active_code_page != system_code_page) {
3765: if(_setmbcp(active_code_page) != 0) {
3766: active_code_page = system_code_page;
3767: }
3768: }
3769:
1.1.1.17 root 3770: msdos_upper_table_update();
1.1.1.23 root 3771: msdos_lower_table_update();
1.1.1.17 root 3772: msdos_filename_terminator_table_init();
3773: msdos_filename_upper_table_init();
3774: msdos_collating_table_update();
1.1 root 3775: msdos_dbcs_table_update();
3776: }
3777:
1.1.1.17 root 3778: void msdos_nls_tables_update()
1.1 root 3779: {
1.1.1.17 root 3780: msdos_dbcs_table_update();
3781: msdos_upper_table_update();
1.1.1.23 root 3782: msdos_lower_table_update();
3783: // msdos_collating_table_update();
1.1 root 3784: }
3785:
3786: int msdos_lead_byte_check(UINT8 code)
3787: {
3788: UINT8 *dbcs_table = mem + DBCS_TABLE;
3789:
3790: for(int i = 0;; i += 2) {
3791: UINT8 lo = dbcs_table[i + 0];
3792: UINT8 hi = dbcs_table[i + 1];
3793: if(lo == 0 && hi == 0) {
3794: break;
3795: }
3796: if(lo <= code && code <= hi) {
3797: return(1);
3798: }
3799: }
3800: return(0);
3801: }
3802:
1.1.1.20 root 3803: int msdos_ctrl_code_check(UINT8 code)
3804: {
1.1.1.22 root 3805: return (code >= 0x01 && code <= 0x1a && code != 0x07 && code != 0x08 && code != 0x09 && code != 0x0a && code != 0x0d);
1.1.1.20 root 3806: }
3807:
1.1.1.36 root 3808: int msdos_kanji_2nd_byte_check(UINT8 *buf, int n)
3809: {
3810: int is_kanji_1st = 0;
3811: int is_kanji_2nd = 0;
3812:
3813: for(int p = 0;; p++) {
3814: if(is_kanji_1st) {
3815: is_kanji_1st = 0;
3816: is_kanji_2nd = 1;
3817: } else if(msdos_lead_byte_check(buf[p])) {
3818: is_kanji_1st = 1;
3819: }
3820: if(p == n) {
3821: return(is_kanji_2nd);
3822: }
3823: is_kanji_2nd = 0;
3824: }
3825: }
3826:
1.1 root 3827: // file control
3828:
1.1.1.14 root 3829: char *msdos_remove_double_quote(char *path)
3830: {
3831: static char tmp[MAX_PATH];
3832:
3833: memset(tmp, 0, sizeof(tmp));
3834: if(strlen(path) >= 2 && path[0] == '"' && path[strlen(path) - 1] == '"') {
3835: memcpy(tmp, path + 1, strlen(path) - 2);
3836: } else {
3837: strcpy(tmp, path);
3838: }
3839: return(tmp);
3840: }
3841:
1.1.1.32 root 3842: char *msdos_remove_end_separator(char *path)
3843: {
3844: static char tmp[MAX_PATH];
3845:
3846: strcpy(tmp, path);
3847: int len = strlen(tmp);
3848: if(len > 3 && tmp[len - 1] == '\\') {
3849: tmp[len - 1] = '\0';
3850: }
3851: return(tmp);
3852: }
3853:
1.1.1.14 root 3854: char *msdos_combine_path(char *dir, const char *file)
3855: {
3856: static char tmp[MAX_PATH];
3857: char *tmp_dir = msdos_remove_double_quote(dir);
3858:
3859: if(strlen(tmp_dir) == 0) {
3860: strcpy(tmp, file);
3861: } else if(tmp_dir[strlen(tmp_dir) - 1] == '\\') {
3862: sprintf(tmp, "%s%s", tmp_dir, file);
3863: } else {
3864: sprintf(tmp, "%s\\%s", tmp_dir, file);
3865: }
3866: return(tmp);
3867: }
3868:
1.1 root 3869: char *msdos_trimmed_path(char *path, int lfn)
3870: {
3871: static char tmp[MAX_PATH];
3872:
3873: if(lfn) {
3874: strcpy(tmp, path);
3875: } else {
3876: // remove space in the path
3877: char *src = path, *dst = tmp;
3878:
3879: while(*src != '\0') {
3880: if(msdos_lead_byte_check(*src)) {
3881: *dst++ = *src++;
3882: *dst++ = *src++;
3883: } else if(*src != ' ') {
3884: *dst++ = *src++;
3885: } else {
3886: src++; // skip space
3887: }
3888: }
3889: *dst = '\0';
3890: }
1.1.1.14 root 3891: if(_stricmp(tmp, "C:\\COMMAND.COM") == 0) {
3892: // redirect C:\COMMAND.COM to comspec_path
3893: strcpy(tmp, comspec_path);
3894: } else if(is_vista_or_later && _access(tmp, 0) != 0) {
3895: // redirect new files (without wildcards) in C:\ to %TEMP%, since C:\ is not usually writable
3896: static int root_drive_protected = -1;
3897: char temp[MAX_PATH], name[MAX_PATH], *name_temp = NULL;
3898: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
3899:
3900: if(GetFullPathName(tmp, MAX_PATH, temp, &name_temp) != 0 &&
3901: name_temp != NULL && strstr(name_temp, "?") == NULL && strstr(name_temp, "*") == NULL) {
3902: strcpy(name, name_temp);
3903: name_temp[0] = '\0';
3904:
3905: if((temp[0] == 'A' + dos_info->boot_drive - 1 || temp[0] == 'a' + dos_info->boot_drive - 1) &&
3906: (temp[1] == ':') && (temp[2] == '\\' || temp[2] == '/') && (temp[3] == '\0')) {
3907: if(root_drive_protected == -1) {
3908: FILE *fp = NULL;
3909:
3910: sprintf(temp, "%c:\\MS-DOS_Player.$$$", 'A' + dos_info->boot_drive - 1);
3911: root_drive_protected = 1;
3912: try {
3913: if((fp = fopen(temp, "w")) != NULL) {
3914: if(fprintf(fp, "TEST") == 4) {
3915: root_drive_protected = 0;
3916: }
3917: }
3918: } catch(...) {
3919: }
3920: if(fp != NULL) {
3921: fclose(fp);
3922: }
3923: if(_access(temp, 0) == 0) {
3924: remove(temp);
3925: }
3926: }
3927: if(root_drive_protected == 1) {
3928: if(GetEnvironmentVariable("TEMP", temp, MAX_PATH) != 0 ||
3929: GetEnvironmentVariable("TMP", temp, MAX_PATH) != 0) {
3930: strcpy(tmp, msdos_combine_path(temp, name));
3931: }
3932: }
3933: }
3934: }
3935: }
1.1 root 3936: return(tmp);
3937: }
3938:
1.1.1.28 root 3939: char *msdos_get_multiple_short_path(char *src)
3940: {
1.1.1.32 root 3941: // "LONGPATH\";"LONGPATH\";"LONGPATH\" to SHORTPATH;SHORTPATH;SHORTPATH
1.1.1.28 root 3942: static char env_path[ENV_SIZE];
3943: char tmp[ENV_SIZE], *token;
3944:
3945: memset(env_path, 0, sizeof(env_path));
3946: strcpy(tmp, src);
3947: token = my_strtok(tmp, ";");
3948:
3949: while(token != NULL) {
3950: if(token[0] != '\0') {
3951: char *path = msdos_remove_double_quote(token), short_path[MAX_PATH];
1.1.1.32 root 3952: if(path != NULL && strlen(path) != 0) {
3953: if(env_path[0] != '\0') {
3954: strcat(env_path, ";");
3955: }
1.1.1.28 root 3956: if(GetShortPathName(path, short_path, MAX_PATH) == 0) {
1.1.1.32 root 3957: strcat(env_path, msdos_remove_end_separator(path));
1.1.1.28 root 3958: } else {
3959: my_strupr(short_path);
1.1.1.32 root 3960: strcat(env_path, msdos_remove_end_separator(short_path));
1.1.1.28 root 3961: }
3962: }
3963: }
3964: token = my_strtok(NULL, ";");
3965: }
3966: return(env_path);
3967: }
3968:
1.1 root 3969: bool match(char *text, char *pattern)
3970: {
1.1.1.24 root 3971: // http://www.prefield.com/algorithm/string/wildcard.html
1.1.1.14 root 3972: switch(*pattern) {
1.1 root 3973: case '\0':
3974: return !*text;
3975: case '*':
1.1.1.14 root 3976: return match(text, pattern + 1) || (*text && match(text + 1, pattern));
1.1 root 3977: case '?':
3978: return *text && match(text + 1, pattern + 1);
3979: default:
3980: return (*text == *pattern) && match(text + 1, pattern + 1);
3981: }
3982: }
3983:
3984: bool msdos_match_volume_label(char *path, char *volume)
3985: {
3986: char *p;
3987:
1.1.1.14 root 3988: if(!*volume) {
3989: return false;
3990: } else if((p = my_strchr(path, ':')) != NULL) {
1.1 root 3991: return msdos_match_volume_label(p + 1, volume);
3992: } else if((p = my_strchr(path, '\\')) != NULL) {
3993: return msdos_match_volume_label(p + 1, volume);
3994: } else if((p = my_strchr(path, '.')) != NULL) {
1.1.1.14 root 3995: char tmp[MAX_PATH];
3996: sprintf(tmp, "%.*s%s", (int)(p - path), path, p + 1);
3997: return match(volume, tmp);
1.1 root 3998: } else {
3999: return match(volume, path);
4000: }
4001: }
4002:
4003: char *msdos_fcb_path(fcb_t *fcb)
4004: {
4005: static char tmp[MAX_PATH];
4006: char name[9], ext[4];
4007:
4008: memset(name, 0, sizeof(name));
4009: memcpy(name, fcb->file_name, 8);
4010: strcpy(name, msdos_trimmed_path(name, 0));
4011:
4012: memset(ext, 0, sizeof(ext));
4013: memcpy(ext, fcb->file_name + 8, 3);
4014: strcpy(ext, msdos_trimmed_path(ext, 0));
4015:
4016: if(name[0] == '\0' || strcmp(name, "????????") == 0) {
4017: strcpy(name, "*");
4018: }
4019: if(ext[0] == '\0') {
4020: strcpy(tmp, name);
4021: } else {
4022: if(strcmp(ext, "???") == 0) {
4023: strcpy(ext, "*");
4024: }
4025: sprintf(tmp, "%s.%s", name, ext);
4026: }
4027: return(tmp);
4028: }
4029:
4030: void msdos_set_fcb_path(fcb_t *fcb, char *path)
4031: {
4032: char *ext = my_strchr(path, '.');
4033:
4034: memset(fcb->file_name, 0x20, 8 + 3);
4035: if(ext != NULL && path[0] != '.') {
4036: *ext = '\0';
4037: memcpy(fcb->file_name + 8, ext + 1, strlen(ext + 1));
4038: }
4039: memcpy(fcb->file_name, path, strlen(path));
4040: }
4041:
4042: char *msdos_short_path(char *path)
4043: {
4044: static char tmp[MAX_PATH];
4045:
1.1.1.24 root 4046: if(GetShortPathName(path, tmp, MAX_PATH) == 0) {
4047: strcpy(tmp, path);
4048: }
1.1 root 4049: my_strupr(tmp);
4050: return(tmp);
4051: }
4052:
1.1.1.13 root 4053: char *msdos_short_name(WIN32_FIND_DATA *fd)
4054: {
4055: static char tmp[MAX_PATH];
4056:
1.1.1.14 root 4057: if(fd->cAlternateFileName[0]) {
1.1.1.13 root 4058: strcpy(tmp, fd->cAlternateFileName);
4059: } else {
4060: strcpy(tmp, fd->cFileName);
4061: }
4062: my_strupr(tmp);
4063: return(tmp);
4064: }
4065:
1.1 root 4066: char *msdos_short_full_path(char *path)
4067: {
4068: static char tmp[MAX_PATH];
4069: char full[MAX_PATH], *name;
4070:
1.1.1.14 root 4071: // Full works with non-existent files, but Short does not
1.1 root 4072: GetFullPathName(path, MAX_PATH, full, &name);
1.1.1.14 root 4073: *tmp = '\0';
4074: if(GetShortPathName(full, tmp, MAX_PATH) == 0 && name > path) {
4075: name[-1] = '\0';
4076: DWORD len = GetShortPathName(full, tmp, MAX_PATH);
4077: if(len == 0) {
4078: strcpy(tmp, full);
4079: } else {
4080: tmp[len++] = '\\';
4081: strcpy(tmp + len, name);
4082: }
4083: }
1.1 root 4084: my_strupr(tmp);
4085: return(tmp);
4086: }
4087:
4088: char *msdos_short_full_dir(char *path)
4089: {
4090: static char tmp[MAX_PATH];
4091: char full[MAX_PATH], *name;
4092:
4093: GetFullPathName(path, MAX_PATH, full, &name);
4094: name[-1] = '\0';
1.1.1.24 root 4095: if(GetShortPathName(full, tmp, MAX_PATH) == 0) {
4096: strcpy(tmp, full);
4097: }
1.1 root 4098: my_strupr(tmp);
4099: return(tmp);
4100: }
4101:
4102: char *msdos_local_file_path(char *path, int lfn)
4103: {
4104: char *trimmed = msdos_trimmed_path(path, lfn);
1.1.1.14 root 4105: #if 0
4106: // I have forgotten the reason of this routine... :-(
1.1 root 4107: if(_access(trimmed, 0) != 0) {
4108: process_t *process = msdos_process_info_get(current_psp);
4109: static char tmp[MAX_PATH];
4110:
4111: sprintf(tmp, "%s\\%s", process->module_dir, trimmed);
4112: if(_access(tmp, 0) == 0) {
4113: return(tmp);
4114: }
4115: }
1.1.1.14 root 4116: #endif
1.1 root 4117: return(trimmed);
4118: }
4119:
1.1.1.29 root 4120: bool msdos_is_device_path(char *path)
1.1.1.11 root 4121: {
4122: char full[MAX_PATH], *name;
4123:
1.1.1.24 root 4124: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1.1.1.29 root 4125: if(_stricmp(full, "\\\\.\\AUX" ) == 0 ||
4126: _stricmp(full, "\\\\.\\CON" ) == 0 ||
4127: _stricmp(full, "\\\\.\\NUL" ) == 0 ||
4128: _stricmp(full, "\\\\.\\PRN" ) == 0 ||
4129: _stricmp(full, "\\\\.\\COM1") == 0 ||
4130: _stricmp(full, "\\\\.\\COM2") == 0 ||
4131: _stricmp(full, "\\\\.\\COM3") == 0 ||
4132: _stricmp(full, "\\\\.\\COM4") == 0 ||
4133: _stricmp(full, "\\\\.\\COM5") == 0 ||
4134: _stricmp(full, "\\\\.\\COM6") == 0 ||
4135: _stricmp(full, "\\\\.\\COM7") == 0 ||
4136: _stricmp(full, "\\\\.\\COM8") == 0 ||
4137: _stricmp(full, "\\\\.\\COM9") == 0 ||
4138: _stricmp(full, "\\\\.\\LPT1") == 0 ||
4139: _stricmp(full, "\\\\.\\LPT2") == 0 ||
4140: _stricmp(full, "\\\\.\\LPT3") == 0 ||
4141: _stricmp(full, "\\\\.\\LPT4") == 0 ||
4142: _stricmp(full, "\\\\.\\LPT5") == 0 ||
4143: _stricmp(full, "\\\\.\\LPT6") == 0 ||
4144: _stricmp(full, "\\\\.\\LPT7") == 0 ||
4145: _stricmp(full, "\\\\.\\LPT8") == 0 ||
4146: _stricmp(full, "\\\\.\\LPT9") == 0) {
4147: return(true);
4148: } else if(name != NULL) {
4149: if(_stricmp(name, "CLOCK$" ) == 0 ||
4150: _stricmp(name, "CONFIG$" ) == 0 ||
1.1.1.30 root 4151: _stricmp(name, "EMMXXXX0") == 0 ||
4152: _stricmp(name, "$IBMAIAS") == 0) {
1.1.1.29 root 4153: return(true);
4154: }
4155: }
1.1.1.24 root 4156: }
4157: return(false);
1.1.1.11 root 4158: }
4159:
1.1.1.29 root 4160: bool msdos_is_con_path(char *path)
1.1.1.8 root 4161: {
1.1.1.14 root 4162: char full[MAX_PATH], *name;
1.1.1.8 root 4163:
1.1.1.24 root 4164: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1.1.1.29 root 4165: return(_stricmp(full, "\\\\.\\CON") == 0);
1.1.1.24 root 4166: }
4167: return(false);
4168: }
4169:
1.1.1.29 root 4170: int msdos_is_comm_path(char *path)
1.1.1.24 root 4171: {
4172: char full[MAX_PATH], *name;
4173:
4174: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1.1.1.29 root 4175: if(_stricmp(full, "\\\\.\\COM1") == 0) {
4176: return(1);
4177: } else if(_stricmp(full, "\\\\.\\COM2") == 0) {
4178: return(2);
4179: } else if(_stricmp(full, "\\\\.\\COM3") == 0) {
4180: return(3);
4181: } else if(_stricmp(full, "\\\\.\\COM4") == 0) {
4182: return(4);
1.1.1.24 root 4183: }
4184: }
1.1.1.29 root 4185: return(0);
4186: }
4187:
1.1.1.37 root 4188: void msdos_set_comm_params(int sio_port, char *path)
4189: {
4190: // COM1:{110,150,300,600,1200,2400,4800,9600},{N,O,E,M,S},{8,7,6,5},{1,1.5,2}
4191: char *p = NULL;
4192:
4193: if((p = strstr(path, ":")) != NULL) {
4194: UINT8 selector = sio_read(sio_port - 1, 3);
4195:
4196: // baud rate
4197: int baud = max(110, min(9600, atoi(p + 1)));
4198: UINT16 divisor = 115200 / baud;
4199:
4200: if((p = strstr(p + 1, ",")) != NULL) {
4201: // parity
4202: if(p[1] == 'N' || p[1] == 'n') {
4203: selector = (selector & ~0x38) | 0x00;
4204: } else if(p[1] == 'O' || p[1] == 'o') {
4205: selector = (selector & ~0x38) | 0x08;
4206: } else if(p[1] == 'E' || p[1] == 'e') {
4207: selector = (selector & ~0x38) | 0x18;
4208: } else if(p[1] == 'M' || p[1] == 'm') {
4209: selector = (selector & ~0x38) | 0x28;
4210: } else if(p[1] == 'S' || p[1] == 's') {
4211: selector = (selector & ~0x38) | 0x38;
4212: }
4213: if((p = strstr(p + 1, ",")) != NULL) {
4214: // word length
4215: if(p[1] == '8') {
4216: selector = (selector & ~0x03) | 0x03;
4217: } else if(p[1] == '7') {
4218: selector = (selector & ~0x03) | 0x02;
4219: } else if(p[1] == '6') {
4220: selector = (selector & ~0x03) | 0x01;
4221: } else if(p[1] == '5') {
4222: selector = (selector & ~0x03) | 0x00;
4223: }
4224: if((p = strstr(p + 1, ",")) != NULL) {
4225: // stop bits
4226: float bits = atof(p + 1);
4227: if(bits > 1.0F) {
4228: selector |= 0x04;
4229: } else {
4230: selector &= ~0x04;
4231: }
4232: }
4233: }
4234: }
4235: sio_write(sio_port - 1, 3, selector | 0x80);
4236: sio_write(sio_port - 1, 0, divisor & 0xff);
4237: sio_write(sio_port - 1, 1, divisor >> 8);
4238: sio_write(sio_port - 1, 3, selector);
4239: }
4240: }
4241:
1.1.1.30 root 4242: int msdos_is_prn_path(char *path)
4243: {
4244: char full[MAX_PATH], *name;
4245:
4246: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
4247: if(_stricmp(full, "\\\\.\\PRN") == 0) {
4248: return(1);
4249: } else if(_stricmp(full, "\\\\.\\LPT1") == 0) {
4250: return(1);
4251: } else if(_stricmp(full, "\\\\.\\LPT2") == 0) {
4252: return(2);
4253: } else if(_stricmp(full, "\\\\.\\LPT3") == 0) {
4254: return(3);
4255: }
4256: }
4257: return(0);
4258: }
4259:
1.1.1.24 root 4260: bool msdos_is_existing_file(char *path)
4261: {
4262: // http://d.hatena.ne.jp/yu-hr/20100317/1268826458
4263: WIN32_FIND_DATA FindData;
4264: HANDLE hFind;
4265:
4266: if((hFind = FindFirstFile(path, &FindData)) != INVALID_HANDLE_VALUE) {
4267: FindClose(hFind);
4268: return(!(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY));
4269: }
4270: return(false);
1.1.1.8 root 4271: }
4272:
1.1.1.9 root 4273: char *msdos_search_command_com(char *command_path, char *env_path)
4274: {
4275: static char tmp[MAX_PATH];
1.1.1.28 root 4276: char path[ENV_SIZE], *file_name;
1.1.1.9 root 4277:
1.1.1.28 root 4278: // check if COMMAND.COM is in the same directory as the target program file
1.1.1.9 root 4279: if(GetFullPathName(command_path, MAX_PATH, tmp, &file_name) != 0) {
4280: sprintf(file_name, "COMMAND.COM");
4281: if(_access(tmp, 0) == 0) {
4282: return(tmp);
4283: }
4284: }
1.1.1.28 root 4285:
4286: // check if COMMAND.COM is in the same directory as the running msdos.exe
1.1.1.9 root 4287: if(GetModuleFileName(NULL, path, MAX_PATH) != 0 && GetFullPathName(path, MAX_PATH, tmp, &file_name) != 0) {
4288: sprintf(file_name, "COMMAND.COM");
4289: if(_access(tmp, 0) == 0) {
4290: return(tmp);
4291: }
4292: }
1.1.1.28 root 4293:
4294: // check if COMMAND.COM is in the current directory
1.1.1.9 root 4295: if(GetFullPathName("COMMAND.COM", MAX_PATH, tmp, &file_name) != 0) {
4296: if(_access(tmp, 0) == 0) {
4297: return(tmp);
4298: }
4299: }
1.1.1.28 root 4300:
4301: // cehck if COMMAND.COM is in the directory that is in MSDOS_PATH and PATH environment variables
4302: strcpy(path, env_path);
4303: char *token = my_strtok(path, ";");
1.1.1.9 root 4304: while(token != NULL) {
1.1.1.14 root 4305: if(strlen(token) != 0 && token[0] != '%') {
1.1.1.9 root 4306: strcpy(tmp, msdos_combine_path(token, "COMMAND.COM"));
4307: if(_access(tmp, 0) == 0) {
4308: return(tmp);
4309: }
4310: }
4311: token = my_strtok(NULL, ";");
4312: }
4313: return(NULL);
4314: }
4315:
1.1.1.14 root 4316: int msdos_drive_number(const char *path)
1.1 root 4317: {
4318: char tmp[MAX_PATH], *name;
4319:
4320: GetFullPathName(path, MAX_PATH, tmp, &name);
4321: if(tmp[0] >= 'a' && tmp[0] <= 'z') {
4322: return(tmp[0] - 'a');
4323: } else {
4324: return(tmp[0] - 'A');
4325: }
4326: }
4327:
4328: char *msdos_volume_label(char *path)
4329: {
4330: static char tmp[MAX_PATH];
4331: char volume[] = "A:\\";
4332:
4333: if(path[1] == ':') {
4334: volume[0] = path[0];
4335: } else {
4336: volume[0] = 'A' + _getdrive() - 1;
4337: }
4338: if(!GetVolumeInformation(volume, tmp, MAX_PATH, NULL, NULL, NULL, NULL, 0)) {
4339: memset(tmp, 0, sizeof(tmp));
4340: }
4341: return(tmp);
4342: }
4343:
4344: char *msdos_short_volume_label(char *label)
4345: {
4346: static char tmp[(8 + 1 + 3) + 1];
4347: char *src = label;
4348: int remain = strlen(label);
4349: char *dst_n = tmp;
4350: char *dst_e = tmp + 9;
4351:
4352: strcpy(tmp, " . ");
4353: for(int i = 0; i < 8 && remain > 0; i++) {
4354: if(msdos_lead_byte_check(*src)) {
4355: if(++i == 8) {
4356: break;
4357: }
4358: *dst_n++ = *src++;
4359: remain--;
4360: }
4361: *dst_n++ = *src++;
4362: remain--;
4363: }
4364: if(remain > 0) {
4365: for(int i = 0; i < 3 && remain > 0; i++) {
4366: if(msdos_lead_byte_check(*src)) {
4367: if(++i == 3) {
4368: break;
4369: }
4370: *dst_e++ = *src++;
4371: remain--;
4372: }
4373: *dst_e++ = *src++;
4374: remain--;
4375: }
4376: *dst_e = '\0';
4377: } else {
4378: *dst_n = '\0';
4379: }
4380: my_strupr(tmp);
4381: return(tmp);
4382: }
4383:
1.1.1.13 root 4384: errno_t msdos_maperr(unsigned long oserrno)
4385: {
4386: _doserrno = oserrno;
1.1.1.14 root 4387: switch(oserrno) {
1.1.1.13 root 4388: case ERROR_FILE_NOT_FOUND: // 2
4389: case ERROR_PATH_NOT_FOUND: // 3
4390: case ERROR_INVALID_DRIVE: // 15
4391: case ERROR_NO_MORE_FILES: // 18
4392: case ERROR_BAD_NETPATH: // 53
4393: case ERROR_BAD_NET_NAME: // 67
4394: case ERROR_BAD_PATHNAME: // 161
4395: case ERROR_FILENAME_EXCED_RANGE: // 206
4396: return ENOENT;
4397: case ERROR_TOO_MANY_OPEN_FILES: // 4
4398: return EMFILE;
4399: case ERROR_ACCESS_DENIED: // 5
4400: case ERROR_CURRENT_DIRECTORY: // 16
4401: case ERROR_NETWORK_ACCESS_DENIED: // 65
4402: case ERROR_CANNOT_MAKE: // 82
4403: case ERROR_FAIL_I24: // 83
4404: case ERROR_DRIVE_LOCKED: // 108
4405: case ERROR_SEEK_ON_DEVICE: // 132
4406: case ERROR_NOT_LOCKED: // 158
4407: case ERROR_LOCK_FAILED: // 167
4408: return EACCES;
4409: case ERROR_INVALID_HANDLE: // 6
4410: case ERROR_INVALID_TARGET_HANDLE: // 114
4411: case ERROR_DIRECT_ACCESS_HANDLE: // 130
4412: return EBADF;
4413: case ERROR_ARENA_TRASHED: // 7
4414: case ERROR_NOT_ENOUGH_MEMORY: // 8
4415: case ERROR_INVALID_BLOCK: // 9
4416: case ERROR_NOT_ENOUGH_QUOTA: // 1816
4417: return ENOMEM;
4418: case ERROR_BAD_ENVIRONMENT: // 10
4419: return E2BIG;
4420: case ERROR_BAD_FORMAT: // 11
4421: return ENOEXEC;
4422: case ERROR_NOT_SAME_DEVICE: // 17
4423: return EXDEV;
4424: case ERROR_FILE_EXISTS: // 80
4425: case ERROR_ALREADY_EXISTS: // 183
4426: return EEXIST;
4427: case ERROR_NO_PROC_SLOTS: // 89
4428: case ERROR_MAX_THRDS_REACHED: // 164
4429: case ERROR_NESTING_NOT_ALLOWED: // 215
4430: return EAGAIN;
4431: case ERROR_BROKEN_PIPE: // 109
4432: return EPIPE;
4433: case ERROR_DISK_FULL: // 112
4434: return ENOSPC;
4435: case ERROR_WAIT_NO_CHILDREN: // 128
4436: case ERROR_CHILD_NOT_COMPLETE: // 129
4437: return ECHILD;
4438: case ERROR_DIR_NOT_EMPTY: // 145
4439: return ENOTEMPTY;
4440: }
1.1.1.14 root 4441: if(oserrno >= ERROR_WRITE_PROTECT /* 19 */ &&
1.1.1.13 root 4442: oserrno <= ERROR_SHARING_BUFFER_EXCEEDED /* 36 */) {
4443: return EACCES;
4444: }
1.1.1.14 root 4445: if(oserrno >= ERROR_INVALID_STARTING_CODESEG /* 188 */ &&
1.1.1.13 root 4446: oserrno <= ERROR_INFLOOP_IN_RELOC_CHAIN /* 202 */) {
4447: return ENOEXEC;
4448: }
4449: return EINVAL;
4450: }
4451:
4452: int msdos_open(const char *filename, int oflag)
4453: {
1.1.1.14 root 4454: if((oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) != _O_RDONLY) {
1.1.1.13 root 4455: return _open(filename, oflag);
4456: }
1.1.1.14 root 4457:
4458: SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, !(oflag & _O_NOINHERIT) };
1.1.1.13 root 4459: DWORD disposition;
1.1.1.14 root 4460: switch(oflag & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
4461: default:
1.1.1.13 root 4462: case _O_EXCL:
4463: disposition = OPEN_EXISTING;
4464: break;
4465: case _O_CREAT:
4466: disposition = OPEN_ALWAYS;
4467: break;
4468: case _O_CREAT | _O_EXCL:
4469: case _O_CREAT | _O_TRUNC | _O_EXCL:
4470: disposition = CREATE_NEW;
4471: break;
4472: case _O_TRUNC:
4473: case _O_TRUNC | _O_EXCL:
4474: disposition = TRUNCATE_EXISTING;
4475: break;
4476: case _O_CREAT | _O_TRUNC:
4477: disposition = CREATE_ALWAYS;
4478: break;
4479: }
1.1.1.14 root 4480:
1.1.1.13 root 4481: HANDLE h = CreateFile(filename, GENERIC_READ | FILE_WRITE_ATTRIBUTES,
4482: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
4483: FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.14 root 4484: if(h == INVALID_HANDLE_VALUE) {
1.1.1.13 root 4485: // FILE_WRITE_ATTRIBUTES may not be granted for standard users.
4486: // Retry without FILE_WRITE_ATTRIBUTES.
4487: h = CreateFile(filename, GENERIC_READ,
4488: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
4489: FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.14 root 4490: if(h == INVALID_HANDLE_VALUE) {
1.1.1.13 root 4491: errno = msdos_maperr(GetLastError());
4492: return -1;
4493: }
4494: }
1.1.1.14 root 4495:
1.1.1.13 root 4496: int fd = _open_osfhandle((intptr_t) h, oflag);
1.1.1.14 root 4497: if(fd == -1) {
1.1.1.13 root 4498: CloseHandle(h);
4499: }
4500: return fd;
4501: }
4502:
1.1.1.37 root 4503: 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 4504: {
4505: static int id = 0;
4506: char full[MAX_PATH], *name;
4507:
4508: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
4509: strcpy(file_handler[fd].path, full);
4510: } else {
4511: strcpy(file_handler[fd].path, path);
4512: }
1.1.1.14 root 4513: // isatty makes no distinction between CON & NUL
4514: // GetFileSize fails on CON, succeeds on NUL
4515: if(atty && (info != 0x80d3 || GetFileSize((HANDLE)_get_osfhandle(fd), NULL) == 0)) {
4516: info = 0x8084;
4517: atty = 0;
4518: } else if(!atty && info == 0x80d3) {
4519: info = msdos_drive_number(".");
4520: }
1.1 root 4521: file_handler[fd].valid = 1;
4522: file_handler[fd].id = id++; // dummy id for int 21h ax=71a6h
1.1.1.37 root 4523: file_handler[fd].atty = (sio_port == 0 && lpt_port == 0) ? atty : 0;
1.1 root 4524: file_handler[fd].mode = mode;
4525: file_handler[fd].info = info;
4526: file_handler[fd].psp = psp_seg;
1.1.1.37 root 4527: file_handler[fd].sio_port = sio_port;
4528: file_handler[fd].lpt_port = lpt_port;
1.1.1.21 root 4529:
4530: // init system file table
4531: if(fd < 20) {
4532: UINT8 *sft = mem + SFT_TOP + 6 + 0x3b * fd;
4533:
4534: memset(sft, 0, 0x3b);
4535:
4536: *(UINT16 *)(sft + 0x00) = 1;
4537: *(UINT16 *)(sft + 0x02) = file_handler[fd].mode;
4538: *(UINT8 *)(sft + 0x04) = GetFileAttributes(file_handler[fd].path) & 0xff;
4539: *(UINT16 *)(sft + 0x05) = file_handler[fd].info & 0xff;
4540:
4541: if(!(file_handler[fd].info & 0x80)) {
4542: *(UINT16 *)(sft + 0x07) = sizeof(dpb_t) * (file_handler[fd].info & 0x1f);
4543: *(UINT16 *)(sft + 0x09) = DPB_TOP >> 4;
4544:
4545: FILETIME time, local;
4546: HANDLE hHandle;
4547: WORD dos_date = 0, dos_time = 0;
4548: DWORD file_size = 0;
4549: if((hHandle = (HANDLE)_get_osfhandle(fd)) != INVALID_HANDLE_VALUE) {
4550: if(GetFileTime(hHandle, NULL, NULL, &time)) {
4551: FileTimeToLocalFileTime(&time, &local);
4552: FileTimeToDosDateTime(&local, &dos_date, &dos_time);
4553: }
4554: file_size = GetFileSize(hHandle, NULL);
4555: }
4556: *(UINT16 *)(sft + 0x0d) = dos_time;
4557: *(UINT16 *)(sft + 0x0f) = dos_date;
4558: *(UINT32 *)(sft + 0x11) = file_size;
4559: }
4560:
4561: char fname[MAX_PATH] = {0}, ext[MAX_PATH] = {0};
4562: _splitpath(file_handler[fd].path, NULL, NULL, fname, ext);
4563: my_strupr(fname);
4564: my_strupr(ext);
4565: memset(sft + 0x20, 0x20, 11);
4566: memcpy(sft + 0x20, fname, min(strlen(fname), 8));
4567: memcpy(sft + 0x28, ext + 1, min(strlen(ext + 1), 3));
4568:
4569: *(UINT16 *)(sft + 0x31) = psp_seg;
4570: }
1.1 root 4571: }
4572:
1.1.1.37 root 4573: void msdos_file_handler_open(int fd, const char *path, int atty, int mode, UINT16 info, UINT16 psp_seg)
4574: {
4575: msdos_file_handler_open(fd, path, atty, mode, info, psp_seg, 0, 0);
4576: }
4577:
1.1 root 4578: void msdos_file_handler_dup(int dst, int src, UINT16 psp_seg)
4579: {
4580: strcpy(file_handler[dst].path, file_handler[src].path);
4581: file_handler[dst].valid = 1;
4582: file_handler[dst].id = file_handler[src].id;
4583: file_handler[dst].atty = file_handler[src].atty;
4584: file_handler[dst].mode = file_handler[src].mode;
4585: file_handler[dst].info = file_handler[src].info;
4586: file_handler[dst].psp = psp_seg;
1.1.1.37 root 4587: file_handler[dst].sio_port = file_handler[src].sio_port;
4588: file_handler[dst].lpt_port = file_handler[src].lpt_port;
1.1 root 4589: }
4590:
1.1.1.20 root 4591: void msdos_file_handler_close(int fd)
1.1 root 4592: {
4593: file_handler[fd].valid = 0;
1.1.1.21 root 4594:
4595: if(fd < 20) {
4596: memset(mem + SFT_TOP + 6 + 0x3b * fd, 0, 0x3b);
4597: }
1.1 root 4598: }
4599:
1.1.1.14 root 4600: inline int msdos_file_attribute_create(UINT16 new_attr)
1.1 root 4601: {
1.1.1.14 root 4602: return(new_attr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
4603: FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE |
4604: FILE_ATTRIBUTE_DIRECTORY));
1.1 root 4605: }
4606:
4607: // find file
4608:
4609: int msdos_find_file_check_attribute(int attribute, int allowed_mask, int required_mask)
4610: {
4611: if((allowed_mask & 0x08) && !(attribute & FILE_ATTRIBUTE_DIRECTORY)) {
4612: return(0); // search directory only !!!
4613: } else if(!(allowed_mask & 0x02) && (attribute & FILE_ATTRIBUTE_HIDDEN)) {
4614: return(0);
4615: } else if(!(allowed_mask & 0x04) && (attribute & FILE_ATTRIBUTE_SYSTEM)) {
4616: return(0);
4617: } else if(!(allowed_mask & 0x10) && (attribute & FILE_ATTRIBUTE_DIRECTORY)) {
4618: return(0);
4619: } else if((attribute & required_mask) != required_mask) {
4620: return(0);
4621: } else {
4622: return(1);
4623: }
4624: }
4625:
1.1.1.13 root 4626: int msdos_find_file_has_8dot3name(WIN32_FIND_DATA *fd)
4627: {
1.1.1.14 root 4628: if(fd->cAlternateFileName[0]) {
1.1.1.13 root 4629: return 1;
4630: }
4631: size_t len = strlen(fd->cFileName);
1.1.1.14 root 4632: if(len > 12) {
1.1.1.13 root 4633: return 0;
4634: }
4635: const char *ext = strrchr(fd->cFileName, '.');
1.1.1.14 root 4636: if((ext ? ext - fd->cFileName : len) > 8) {
1.1.1.13 root 4637: return 0;
4638: }
4639: return 1;
4640: }
4641:
1.1 root 4642: void msdos_find_file_conv_local_time(WIN32_FIND_DATA *fd)
4643: {
4644: FILETIME local;
4645:
4646: FileTimeToLocalFileTime(&fd->ftCreationTime, &local);
4647: fd->ftCreationTime.dwLowDateTime = local.dwLowDateTime;
4648: fd->ftCreationTime.dwHighDateTime = local.dwHighDateTime;
4649:
4650: FileTimeToLocalFileTime(&fd->ftLastAccessTime, &local);
4651: fd->ftLastAccessTime.dwLowDateTime = local.dwLowDateTime;
4652: fd->ftLastAccessTime.dwHighDateTime = local.dwHighDateTime;
4653:
4654: FileTimeToLocalFileTime(&fd->ftLastWriteTime, &local);
4655: fd->ftLastWriteTime.dwLowDateTime = local.dwLowDateTime;
4656: fd->ftLastWriteTime.dwHighDateTime = local.dwHighDateTime;
4657: }
4658:
4659: // i/o
4660:
4661: void msdos_stdio_reopen()
4662: {
4663: if(!file_handler[0].valid) {
4664: _dup2(DUP_STDIN, 0);
4665: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
4666: }
4667: if(!file_handler[1].valid) {
4668: _dup2(DUP_STDOUT, 1);
4669: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
4670: }
4671: if(!file_handler[2].valid) {
4672: _dup2(DUP_STDERR, 2);
4673: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
4674: }
1.1.1.21 root 4675: if(!file_handler[3].valid) {
4676: _dup2(DUP_STDAUX, 3);
4677: msdos_file_handler_open(3, "STDAUX", 0, 2, 0x80c0, 0);
4678: }
4679: if(!file_handler[4].valid) {
4680: _dup2(DUP_STDPRN, 4);
1.1.1.37 root 4681: msdos_file_handler_open(4, "STDPRN", 0, 1, 0xa8c0, 0, 0, 1); // LPT1
1.1.1.21 root 4682: }
4683: for(int i = 0; i < 5; i++) {
4684: if(msdos_psp_get_file_table(i, current_psp) == 0xff) {
4685: msdos_psp_set_file_table(i, i, current_psp);
4686: }
4687: }
1.1 root 4688: }
4689:
1.1.1.37 root 4690: int msdos_read(int fd, void *buffer, unsigned int count)
4691: {
4692: if(fd < process->max_files && file_handler[fd].valid && file_handler[fd].sio_port >= 1 && file_handler[fd].sio_port <= 4) {
4693: // read from serial port
4694: int read = 0;
4695: if(sio_port_number[file_handler[fd].sio_port - 1] != 0) {
4696: UINT8 *buf = (UINT8 *)buffer;
4697: UINT8 selector = sio_read(file_handler[fd].sio_port - 1, 3);
4698: sio_write(file_handler[fd].sio_port - 1, 3, selector & ~0x80);
1.1.1.38 root 4699: DWORD timeout = timeGetTime() + 1000;
4700: while(read < count) {
4701: if(sio_read(file_handler[fd].sio_port - 1, 5) & 0x01) {
4702: buf[read++] = sio_read(file_handler[fd].sio_port - 1, 0);
4703: timeout = timeGetTime() + 1000;
4704: } else {
4705: if(timeGetTime() > timeout) {
4706: break;
4707: }
4708: Sleep(10);
1.1.1.37 root 4709: }
4710: }
4711: sio_write(file_handler[fd].sio_port - 1, 3, selector);
4712: }
4713: return(read);
4714: }
4715: return(_read(fd, buffer, count));
4716: }
4717:
1.1 root 4718: int msdos_kbhit()
4719: {
4720: msdos_stdio_reopen();
4721:
1.1.1.20 root 4722: process_t *process = msdos_process_info_get(current_psp);
4723: int fd = msdos_psp_get_file_table(0, current_psp);
4724:
4725: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 4726: // stdin is redirected to file
1.1.1.20 root 4727: return(eof(fd) == 0);
1.1 root 4728: }
4729:
4730: // check keyboard status
1.1.1.35 root 4731: if(key_recv != 0) {
1.1 root 4732: return(1);
4733: }
1.1.1.35 root 4734: if(key_buf_char != NULL && key_buf_scan != NULL) {
4735: #ifdef USE_SERVICE_THREAD
4736: EnterCriticalSection(&key_buf_crit_sect);
4737: #endif
4738: bool empty = key_buf_char->empty();
4739: #ifdef USE_SERVICE_THREAD
4740: LeaveCriticalSection(&key_buf_crit_sect);
4741: #endif
4742: if(!empty) return(1);
4743: }
4744: return(_kbhit());
1.1 root 4745: }
4746:
4747: int msdos_getch_ex(int echo)
4748: {
4749: static char prev = 0;
4750:
4751: msdos_stdio_reopen();
4752:
1.1.1.20 root 4753: process_t *process = msdos_process_info_get(current_psp);
4754: int fd = msdos_psp_get_file_table(0, current_psp);
4755:
4756: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 4757: // stdin is redirected to file
4758: retry:
4759: char data;
1.1.1.37 root 4760: if(msdos_read(fd, &data, 1) == 1) {
1.1 root 4761: char tmp = data;
4762: if(data == 0x0a) {
4763: if(prev == 0x0d) {
4764: goto retry; // CRLF -> skip LF
4765: } else {
4766: data = 0x0d; // LF only -> CR
4767: }
4768: }
4769: prev = tmp;
4770: return(data);
4771: }
4772: return(EOF);
4773: }
4774:
4775: // input from console
1.1.1.5 root 4776: int key_char, key_scan;
1.1.1.33 root 4777: if(key_recv != 0) {
1.1.1.5 root 4778: key_char = (key_code >> 0) & 0xff;
4779: key_scan = (key_code >> 8) & 0xff;
4780: key_code >>= 16;
1.1.1.33 root 4781: key_recv >>= 16;
1.1.1.5 root 4782: } else {
1.1.1.35 root 4783: while(key_buf_char != NULL && key_buf_scan != NULL && !m_halted) {
4784: if(key_buf_char != NULL && key_buf_scan != NULL) {
4785: #ifdef USE_SERVICE_THREAD
4786: EnterCriticalSection(&key_buf_crit_sect);
4787: #endif
4788: bool empty = key_buf_char->empty();
4789: #ifdef USE_SERVICE_THREAD
4790: LeaveCriticalSection(&key_buf_crit_sect);
4791: #endif
4792: if(!empty) break;
4793: }
1.1.1.23 root 4794: if(!(fd < process->max_files && file_handler[fd].valid && file_handler[fd].atty && file_mode[file_handler[fd].mode].in)) {
4795: // NOTE: stdin is redirected to stderr when we do "type (file) | more" on freedos's command.com
4796: if(_kbhit()) {
1.1.1.32 root 4797: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 4798: #ifdef USE_SERVICE_THREAD
4799: EnterCriticalSection(&key_buf_crit_sect);
4800: #endif
1.1.1.32 root 4801: key_buf_char->write(_getch());
1.1.1.35 root 4802: key_buf_scan->write(0x00);
4803: #ifdef USE_SERVICE_THREAD
4804: LeaveCriticalSection(&key_buf_crit_sect);
4805: #endif
1.1.1.32 root 4806: }
1.1.1.23 root 4807: } else {
4808: Sleep(10);
4809: }
4810: } else {
4811: if(!update_key_buffer()) {
4812: Sleep(10);
4813: }
1.1.1.14 root 4814: }
4815: }
4816: if(m_halted) {
1.1.1.33 root 4817: // insert CR to terminate input loops
1.1.1.14 root 4818: key_char = 0x0d;
4819: key_scan = 0;
1.1.1.32 root 4820: } else if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 4821: #ifdef USE_SERVICE_THREAD
4822: EnterCriticalSection(&key_buf_crit_sect);
4823: #endif
1.1.1.14 root 4824: key_char = key_buf_char->read();
4825: key_scan = key_buf_scan->read();
1.1.1.41! root 4826: // write to bottom of key buffer
! 4827: mem[0x43c] = (UINT8)key_char;
! 4828: mem[0x43d] = (UINT8)key_scan;
1.1.1.35 root 4829: #ifdef USE_SERVICE_THREAD
4830: LeaveCriticalSection(&key_buf_crit_sect);
4831: #endif
1.1.1.5 root 4832: }
1.1 root 4833: }
4834: if(echo && key_char) {
4835: msdos_putch(key_char);
4836: }
4837: return key_char ? key_char : (key_scan != 0xe0) ? key_scan : 0;
4838: }
4839:
4840: inline int msdos_getch()
4841: {
4842: return(msdos_getch_ex(0));
4843: }
4844:
4845: inline int msdos_getche()
4846: {
4847: return(msdos_getch_ex(1));
4848: }
4849:
4850: int msdos_write(int fd, const void *buffer, unsigned int count)
4851: {
1.1.1.37 root 4852: if(fd < process->max_files && file_handler[fd].valid && file_handler[fd].sio_port >= 1 && file_handler[fd].sio_port <= 4) {
4853: // write to serial port
1.1.1.38 root 4854: int written = 0;
1.1.1.37 root 4855: if(sio_port_number[file_handler[fd].sio_port - 1] != 0) {
4856: UINT8 *buf = (UINT8 *)buffer;
4857: UINT8 selector = sio_read(file_handler[fd].sio_port - 1, 3);
4858: sio_write(file_handler[fd].sio_port - 1, 3, selector & ~0x80);
1.1.1.38 root 4859: DWORD timeout = timeGetTime() + 1000;
4860: while(written < count) {
4861: if(sio_read(file_handler[fd].sio_port - 1, 5) & 0x20) {
4862: sio_write(file_handler[fd].sio_port - 1, 0, buf[written++]);
4863: timeout = timeGetTime() + 1000;
4864: } else {
4865: if(timeGetTime() > timeout) {
4866: break;
4867: }
4868: Sleep(10);
4869: }
1.1.1.37 root 4870: }
4871: sio_write(file_handler[fd].sio_port - 1, 3, selector);
4872: }
1.1.1.38 root 4873: return(written);
1.1.1.37 root 4874: } else if(fd < process->max_files && file_handler[fd].valid && file_handler[fd].lpt_port >= 1 && file_handler[fd].lpt_port <= 3) {
4875: // write to printer port
4876: UINT8 *buf = (UINT8 *)buffer;
4877: for(unsigned int i = 0; i < count; i++) {
4878: // printer_out(file_handler[fd].lpt_port - 1, buf[i]);
4879: pcbios_printer_out(file_handler[fd].lpt_port - 1, buf[i]);
4880: }
4881: return(count);
4882: } else if(fd == 1 && file_handler[1].valid && !file_handler[1].atty) {
1.1 root 4883: // CR+LF -> LF
1.1.1.37 root 4884: static int is_cr = 0;
1.1 root 4885: UINT8 *buf = (UINT8 *)buffer;
4886: for(unsigned int i = 0; i < count; i++) {
4887: UINT8 data = buf[i];
4888: if(is_cr) {
4889: if(data != 0x0a) {
4890: UINT8 tmp = 0x0d;
4891: _write(1, &tmp, 1);
4892: }
4893: _write(1, &data, 1);
4894: is_cr = 0;
4895: } else if(data == 0x0d) {
4896: is_cr = 1;
4897: } else {
4898: _write(1, &data, 1);
4899: }
4900: }
4901: return(count);
4902: }
1.1.1.14 root 4903: vram_flush();
1.1 root 4904: return(_write(fd, buffer, count));
4905: }
4906:
4907: void msdos_putch(UINT8 data)
1.1.1.35 root 4908: #ifdef USE_SERVICE_THREAD
4909: {
4910: EnterCriticalSection(&putch_crit_sect);
4911: msdos_putch_tmp(data);
4912: LeaveCriticalSection(&putch_crit_sect);
4913: }
4914: void msdos_putch_tmp(UINT8 data)
4915: #endif
1.1 root 4916: {
1.1.1.34 root 4917: CONSOLE_SCREEN_BUFFER_INFO csbi;
4918: SMALL_RECT rect;
4919: COORD co;
1.1 root 4920: static int p = 0;
4921: static int is_kanji = 0;
4922: static int is_esc = 0;
4923: static int stored_x;
4924: static int stored_y;
4925: static WORD stored_a;
1.1.1.20 root 4926: static char tmp[64], out[64];
1.1 root 4927:
4928: msdos_stdio_reopen();
4929:
1.1.1.20 root 4930: process_t *process = msdos_process_info_get(current_psp);
4931: int fd = msdos_psp_get_file_table(1, current_psp);
4932:
4933: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 4934: // stdout is redirected to file
1.1.1.20 root 4935: msdos_write(fd, &data, 1);
1.1 root 4936: return;
4937: }
1.1.1.23 root 4938: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 4939:
4940: // output to console
4941: tmp[p++] = data;
4942:
1.1.1.14 root 4943: vram_flush();
4944:
1.1 root 4945: if(is_kanji) {
4946: // kanji character
4947: is_kanji = 0;
4948: } else if(is_esc) {
4949: // escape sequense
4950: if((tmp[1] == ')' || tmp[1] == '(') && p == 3) {
4951: p = is_esc = 0;
4952: } else if(tmp[1] == '=' && p == 4) {
4953: co.X = tmp[3] - 0x20;
1.1.1.14 root 4954: co.Y = tmp[2] - 0x20 + scr_top;
1.1 root 4955: SetConsoleCursorPosition(hStdout, co);
4956: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14 root 4957: mem[0x451 + mem[0x462] * 2] = co.Y - scr_top;
1.1 root 4958: cursor_moved = false;
4959: p = is_esc = 0;
4960: } else if((data >= 'a' && data <= 'z') || (data >= 'A' && data <= 'Z') || data == '*') {
4961: GetConsoleScreenBufferInfo(hStdout, &csbi);
4962: co.X = csbi.dwCursorPosition.X;
4963: co.Y = csbi.dwCursorPosition.Y;
4964: WORD wAttributes = csbi.wAttributes;
4965:
4966: if(tmp[1] == 'D') {
4967: co.Y++;
4968: } else if(tmp[1] == 'E') {
4969: co.X = 0;
4970: co.Y++;
4971: } else if(tmp[1] == 'M') {
4972: co.Y--;
4973: } else if(tmp[1] == '*') {
1.1.1.14 root 4974: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
4975: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
4976: co.X = 0;
4977: co.Y = csbi.srWindow.Top;
1.1 root 4978: } else if(tmp[1] == '[') {
4979: int param[256], params = 0;
4980: memset(param, 0, sizeof(param));
4981: for(int i = 2; i < p; i++) {
4982: if(tmp[i] >= '0' && tmp[i] <= '9') {
4983: param[params] *= 10;
4984: param[params] += tmp[i] - '0';
4985: } else {
4986: params++;
4987: }
4988: }
4989: if(data == 'A') {
1.1.1.14 root 4990: co.Y -= (params == 0) ? 1 : param[0];
1.1 root 4991: } else if(data == 'B') {
1.1.1.14 root 4992: co.Y += (params == 0) ? 1 : param[0];
1.1 root 4993: } else if(data == 'C') {
1.1.1.14 root 4994: co.X += (params == 0) ? 1 : param[0];
1.1 root 4995: } else if(data == 'D') {
1.1.1.14 root 4996: co.X -= (params == 0) ? 1 : param[0];
1.1 root 4997: } else if(data == 'H' || data == 'f') {
1.1.1.14 root 4998: co.X = (param[1] == 0 ? 1 : param[1]) - 1;
4999: co.Y = (param[0] == 0 ? 1 : param[0]) - 1 + csbi.srWindow.Top;
1.1 root 5000: } else if(data == 'J') {
1.1.1.14 root 5001: clear_scr_buffer(csbi.wAttributes);
1.1 root 5002: if(param[0] == 0) {
5003: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 5004: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5005: if(co.Y < csbi.srWindow.Bottom) {
5006: SET_RECT(rect, 0, co.Y + 1, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5007: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5008: }
5009: } else if(param[0] == 1) {
1.1.1.14 root 5010: if(co.Y > csbi.srWindow.Top) {
5011: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, co.Y - 1);
5012: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5013: }
5014: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14 root 5015: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5016: } else if(param[0] == 2) {
1.1.1.14 root 5017: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5018: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5019: co.X = co.Y = 0;
5020: }
5021: } else if(data == 'K') {
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);
1.1 root 5026: } else if(param[0] == 1) {
5027: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14 root 5028: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5029: } else if(param[0] == 2) {
5030: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 5031: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5032: }
5033: } else if(data == 'L') {
1.1.1.14 root 5034: if(params == 0) {
5035: param[0] = 1;
1.1 root 5036: }
1.1.1.14 root 5037: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5038: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5039: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5040: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5041: clear_scr_buffer(csbi.wAttributes);
1.1 root 5042: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y + param[0] - 1);
1.1.1.14 root 5043: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5044: co.X = 0;
5045: } else if(data == 'M') {
1.1.1.14 root 5046: if(params == 0) {
5047: param[0] = 1;
5048: }
5049: if(co.Y + param[0] > csbi.srWindow.Bottom) {
5050: clear_scr_buffer(csbi.wAttributes);
5051: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5052: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 5053: } else {
1.1.1.14 root 5054: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5055: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5056: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
5057: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
5058: clear_scr_buffer(csbi.wAttributes);
1.1 root 5059: }
5060: co.X = 0;
5061: } else if(data == 'h') {
5062: if(tmp[2] == '>' && tmp[3] == '5') {
5063: CONSOLE_CURSOR_INFO cur;
5064: GetConsoleCursorInfo(hStdout, &cur);
5065: if(cur.bVisible) {
5066: cur.bVisible = FALSE;
1.1.1.14 root 5067: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 5068: }
5069: }
5070: } else if(data == 'l') {
5071: if(tmp[2] == '>' && tmp[3] == '5') {
5072: CONSOLE_CURSOR_INFO cur;
5073: GetConsoleCursorInfo(hStdout, &cur);
5074: if(!cur.bVisible) {
5075: cur.bVisible = TRUE;
1.1.1.14 root 5076: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 5077: }
5078: }
5079: } else if(data == 'm') {
5080: wAttributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
5081: int reverse = 0, hidden = 0;
5082: for(int i = 0; i < params; i++) {
5083: if(param[i] == 1) {
5084: wAttributes |= FOREGROUND_INTENSITY;
5085: } else if(param[i] == 4) {
5086: wAttributes |= COMMON_LVB_UNDERSCORE;
5087: } else if(param[i] == 7) {
5088: reverse = 1;
5089: } else if(param[i] == 8 || param[i] == 16) {
5090: hidden = 1;
5091: } else if((param[i] >= 17 && param[i] <= 23) || (param[i] >= 30 && param[i] <= 37)) {
5092: wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
5093: if(param[i] >= 17 && param[i] <= 23) {
5094: param[i] -= 16;
5095: } else {
5096: param[i] -= 30;
5097: }
5098: if(param[i] & 1) {
5099: wAttributes |= FOREGROUND_RED;
5100: }
5101: if(param[i] & 2) {
5102: wAttributes |= FOREGROUND_GREEN;
5103: }
5104: if(param[i] & 4) {
5105: wAttributes |= FOREGROUND_BLUE;
5106: }
5107: } else if(param[i] >= 40 && param[i] <= 47) {
5108: wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
5109: if((param[i] - 40) & 1) {
5110: wAttributes |= BACKGROUND_RED;
5111: }
5112: if((param[i] - 40) & 2) {
5113: wAttributes |= BACKGROUND_GREEN;
5114: }
5115: if((param[i] - 40) & 4) {
5116: wAttributes |= BACKGROUND_BLUE;
5117: }
5118: }
5119: }
5120: if(reverse) {
5121: wAttributes &= ~0xff;
5122: wAttributes |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
5123: }
5124: if(hidden) {
5125: wAttributes &= ~0x0f;
5126: wAttributes |= (wAttributes >> 4) & 0x0f;
5127: }
5128: } else if(data == 'n') {
5129: if(param[0] == 6) {
5130: char tmp[16];
5131: sprintf(tmp, "\x1b[%d;%dR", co.Y + 1, co.X + 1);
5132: int len = strlen(tmp);
1.1.1.32 root 5133: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 5134: #ifdef USE_SERVICE_THREAD
5135: EnterCriticalSection(&key_buf_crit_sect);
5136: #endif
1.1.1.32 root 5137: for(int i = 0; i < len; i++) {
5138: key_buf_char->write(tmp[i]);
5139: key_buf_scan->write(0x00);
5140: }
1.1.1.35 root 5141: #ifdef USE_SERVICE_THREAD
5142: LeaveCriticalSection(&key_buf_crit_sect);
5143: #endif
1.1 root 5144: }
5145: }
5146: } else if(data == 's') {
5147: stored_x = co.X;
5148: stored_y = co.Y;
5149: stored_a = wAttributes;
5150: } else if(data == 'u') {
5151: co.X = stored_x;
5152: co.Y = stored_y;
5153: wAttributes = stored_a;
5154: }
5155: }
5156: if(co.X < 0) {
5157: co.X = 0;
5158: } else if(co.X >= csbi.dwSize.X) {
5159: co.X = csbi.dwSize.X - 1;
5160: }
1.1.1.14 root 5161: if(co.Y < csbi.srWindow.Top) {
5162: co.Y = csbi.srWindow.Top;
5163: } else if(co.Y > csbi.srWindow.Bottom) {
5164: co.Y = csbi.srWindow.Bottom;
1.1 root 5165: }
5166: if(co.X != csbi.dwCursorPosition.X || co.Y != csbi.dwCursorPosition.Y) {
5167: SetConsoleCursorPosition(hStdout, co);
5168: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14 root 5169: mem[0x451 + mem[0x462] * 2] = co.Y - csbi.srWindow.Top;
1.1 root 5170: cursor_moved = false;
5171: }
5172: if(wAttributes != csbi.wAttributes) {
5173: SetConsoleTextAttribute(hStdout, wAttributes);
5174: }
5175: p = is_esc = 0;
5176: }
5177: return;
5178: } else {
5179: if(msdos_lead_byte_check(data)) {
5180: is_kanji = 1;
5181: return;
5182: } else if(data == 0x1b) {
5183: is_esc = 1;
5184: return;
5185: }
5186: }
1.1.1.20 root 5187:
5188: DWORD q = 0, num;
5189: is_kanji = 0;
5190: for(int i = 0; i < p; i++) {
5191: UINT8 c = tmp[i];
5192: if(is_kanji) {
5193: is_kanji = 0;
5194: } else if(msdos_lead_byte_check(data)) {
5195: is_kanji = 1;
5196: } else if(msdos_ctrl_code_check(data)) {
5197: out[q++] = '^';
5198: c += 'A' - 1;
5199: }
5200: out[q++] = c;
5201: }
1.1.1.34 root 5202: if(q == 1 && out[0] == 0x08) {
5203: // back space
5204: GetConsoleScreenBufferInfo(hStdout, &csbi);
5205: if(csbi.dwCursorPosition.X > 0) {
5206: co.X = csbi.dwCursorPosition.X - 1;
5207: co.Y = csbi.dwCursorPosition.Y;
5208: SetConsoleCursorPosition(hStdout, co);
5209: } else if(csbi.dwCursorPosition.Y > 0) {
5210: co.X = csbi.dwSize.X - 1;
5211: co.Y = csbi.dwCursorPosition.Y - 1;
5212: SetConsoleCursorPosition(hStdout, co);
5213: } else {
5214: WriteConsole(hStdout, out, q, &num, NULL); // to make sure
5215: }
5216: } else {
5217: WriteConsole(hStdout, out, q, &num, NULL);
5218: }
1.1 root 5219: p = 0;
1.1.1.14 root 5220:
1.1.1.15 root 5221: if(!restore_console_on_exit) {
5222: GetConsoleScreenBufferInfo(hStdout, &csbi);
5223: scr_top = csbi.srWindow.Top;
5224: }
1.1 root 5225: cursor_moved = true;
5226: }
5227:
5228: int msdos_aux_in()
5229: {
1.1.1.21 root 5230: msdos_stdio_reopen();
5231:
1.1.1.20 root 5232: process_t *process = msdos_process_info_get(current_psp);
5233: int fd = msdos_psp_get_file_table(3, current_psp);
5234:
5235: if(fd < process->max_files && file_handler[fd].valid && !eof(fd)) {
1.1 root 5236: char data = 0;
1.1.1.37 root 5237: msdos_read(fd, &data, 1);
1.1 root 5238: return(data);
5239: } else {
5240: return(EOF);
5241: }
5242: }
5243:
5244: void msdos_aux_out(char data)
5245: {
1.1.1.21 root 5246: msdos_stdio_reopen();
5247:
1.1.1.20 root 5248: process_t *process = msdos_process_info_get(current_psp);
5249: int fd = msdos_psp_get_file_table(3, current_psp);
5250:
5251: if(fd < process->max_files && file_handler[fd].valid) {
5252: msdos_write(fd, &data, 1);
1.1 root 5253: }
5254: }
5255:
5256: void msdos_prn_out(char data)
5257: {
1.1.1.21 root 5258: msdos_stdio_reopen();
5259:
1.1.1.20 root 5260: process_t *process = msdos_process_info_get(current_psp);
5261: int fd = msdos_psp_get_file_table(4, current_psp);
5262:
5263: if(fd < process->max_files && file_handler[fd].valid) {
5264: msdos_write(fd, &data, 1);
1.1 root 5265: }
5266: }
5267:
5268: // memory control
5269:
1.1.1.39 root 5270: mcb_t *msdos_mcb_create(int mcb_seg, UINT8 mz, UINT16 psp, int paragraphs, char *prog_name)
1.1 root 5271: {
5272: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5273:
5274: mcb->mz = mz;
5275: mcb->psp = psp;
1.1.1.30 root 5276: mcb->paragraphs = paragraphs;
1.1.1.39 root 5277:
5278: if(prog_name != NULL) {
5279: memset(mcb->prog_name, 0, 8);
5280: memcpy(mcb->prog_name, prog_name, min(8, strlen(prog_name)));
5281: }
1.1 root 5282: return(mcb);
5283: }
5284:
1.1.1.39 root 5285: mcb_t *msdos_mcb_create(int mcb_seg, UINT8 mz, UINT16 psp, int paragraphs)
5286: {
5287: return(msdos_mcb_create(mcb_seg, mz, psp, paragraphs, NULL));
5288: }
5289:
1.1 root 5290: void msdos_mcb_check(mcb_t *mcb)
5291: {
5292: if(!(mcb->mz == 'M' || mcb->mz == 'Z')) {
1.1.1.28 root 5293: #if 0
5294: // shutdown now !!!
5295: fatalerror("broken memory control block\n");
5296: #else
5297: // return error code and continue
5298: throw(0x07); // broken memory control block
5299: #endif
1.1 root 5300: }
5301: }
5302:
1.1.1.39 root 5303: void msdos_mem_split(int seg, int paragraphs)
1.1 root 5304: {
5305: int mcb_seg = seg - 1;
5306: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5307: msdos_mcb_check(mcb);
5308:
1.1.1.30 root 5309: if(mcb->paragraphs > paragraphs) {
1.1 root 5310: int new_seg = mcb_seg + 1 + paragraphs;
1.1.1.30 root 5311: int new_paragraphs = mcb->paragraphs - paragraphs - 1;
1.1 root 5312:
5313: msdos_mcb_create(new_seg, mcb->mz, 0, new_paragraphs);
5314: mcb->mz = 'M';
1.1.1.30 root 5315: mcb->paragraphs = paragraphs;
1.1 root 5316: }
5317: }
5318:
5319: void msdos_mem_merge(int seg)
5320: {
5321: int mcb_seg = seg - 1;
5322: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5323: msdos_mcb_check(mcb);
5324:
5325: while(1) {
5326: if(mcb->mz == 'Z') {
5327: break;
5328: }
1.1.1.30 root 5329: int next_seg = mcb_seg + 1 + mcb->paragraphs;
1.1 root 5330: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
5331: msdos_mcb_check(next_mcb);
5332:
5333: if(next_mcb->psp != 0) {
5334: break;
5335: }
5336: mcb->mz = next_mcb->mz;
1.1.1.30 root 5337: mcb->paragraphs = mcb->paragraphs + 1 + next_mcb->paragraphs;
1.1 root 5338: }
5339: }
5340:
1.1.1.8 root 5341: int msdos_mem_alloc(int mcb_seg, int paragraphs, int new_process)
1.1 root 5342: {
5343: while(1) {
5344: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1.1.33 root 5345: bool last_block;
1.1 root 5346:
1.1.1.14 root 5347: if(mcb->psp == 0) {
5348: msdos_mem_merge(mcb_seg + 1);
5349: } else {
5350: msdos_mcb_check(mcb);
5351: }
1.1.1.33 root 5352: if(!(last_block = (mcb->mz == 'Z'))) {
5353: // check if the next is dummy mcb to link to umb
5354: int next_seg = mcb_seg + 1 + mcb->paragraphs;
5355: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
5356: last_block = (next_mcb->mz == 'Z' && next_mcb->paragraphs == 0);
5357: }
5358: if(!(new_process && !last_block)) {
1.1.1.30 root 5359: if(mcb->psp == 0 && mcb->paragraphs >= paragraphs) {
1.1 root 5360: msdos_mem_split(mcb_seg + 1, paragraphs);
5361: mcb->psp = current_psp;
5362: return(mcb_seg + 1);
5363: }
5364: }
5365: if(mcb->mz == 'Z') {
5366: break;
5367: }
1.1.1.30 root 5368: mcb_seg += 1 + mcb->paragraphs;
1.1 root 5369: }
5370: return(-1);
5371: }
5372:
5373: int msdos_mem_realloc(int seg, int paragraphs, int *max_paragraphs)
5374: {
5375: int mcb_seg = seg - 1;
5376: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5377: msdos_mcb_check(mcb);
1.1.1.30 root 5378: int current_paragraphs = mcb->paragraphs;
1.1 root 5379:
5380: msdos_mem_merge(seg);
1.1.1.30 root 5381: if(paragraphs > mcb->paragraphs) {
1.1.1.14 root 5382: if(max_paragraphs) {
1.1.1.30 root 5383: *max_paragraphs = mcb->paragraphs;
1.1.1.14 root 5384: }
1.1 root 5385: msdos_mem_split(seg, current_paragraphs);
5386: return(-1);
5387: }
5388: msdos_mem_split(seg, paragraphs);
5389: return(0);
5390: }
5391:
5392: void msdos_mem_free(int seg)
5393: {
5394: int mcb_seg = seg - 1;
5395: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5396: msdos_mcb_check(mcb);
5397:
5398: mcb->psp = 0;
5399: msdos_mem_merge(seg);
5400: }
5401:
1.1.1.8 root 5402: int msdos_mem_get_free(int mcb_seg, int new_process)
1.1 root 5403: {
5404: int max_paragraphs = 0;
5405:
5406: while(1) {
5407: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1.1.33 root 5408: bool last_block;
5409:
1.1 root 5410: msdos_mcb_check(mcb);
5411:
1.1.1.33 root 5412: if(!(last_block = (mcb->mz == 'Z'))) {
5413: // check if the next is dummy mcb to link to umb
5414: int next_seg = mcb_seg + 1 + mcb->paragraphs;
5415: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
5416: last_block = (next_mcb->mz == 'Z' && next_mcb->paragraphs == 0);
5417: }
5418: if(!(new_process && !last_block)) {
1.1.1.30 root 5419: if(mcb->psp == 0 && mcb->paragraphs > max_paragraphs) {
5420: max_paragraphs = mcb->paragraphs;
1.1 root 5421: }
5422: }
5423: if(mcb->mz == 'Z') {
5424: break;
5425: }
1.1.1.30 root 5426: mcb_seg += 1 + mcb->paragraphs;
1.1 root 5427: }
1.1.1.14 root 5428: return(max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs);
1.1 root 5429: }
5430:
1.1.1.8 root 5431: int msdos_mem_get_last_mcb(int mcb_seg, UINT16 psp)
5432: {
5433: int last_seg = -1;
5434:
5435: while(1) {
5436: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5437: msdos_mcb_check(mcb);
5438:
1.1.1.14 root 5439: if(mcb->psp == psp) {
1.1.1.8 root 5440: last_seg = mcb_seg;
5441: }
1.1.1.14 root 5442: if(mcb->mz == 'Z') {
5443: break;
5444: }
1.1.1.30 root 5445: mcb_seg += 1 + mcb->paragraphs;
1.1.1.8 root 5446: }
5447: return(last_seg);
5448: }
5449:
1.1.1.19 root 5450: int msdos_mem_get_umb_linked()
5451: {
1.1.1.33 root 5452: mcb_t *mcb = (mcb_t *)(mem + MEMORY_END - 16);
5453: msdos_mcb_check(mcb);
1.1.1.19 root 5454:
1.1.1.33 root 5455: if(mcb->mz == 'M') {
5456: return(-1);
1.1.1.19 root 5457: }
5458: return(0);
5459: }
5460:
1.1.1.33 root 5461: void msdos_mem_link_umb()
1.1.1.19 root 5462: {
1.1.1.33 root 5463: mcb_t *mcb = (mcb_t *)(mem + MEMORY_END - 16);
5464: msdos_mcb_check(mcb);
1.1.1.19 root 5465:
1.1.1.33 root 5466: mcb->mz = 'M';
5467: mcb->paragraphs = (UMB_TOP >> 4) - (MEMORY_END >> 4);
1.1.1.39 root 5468:
5469: ((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked |= 0x01;
1.1.1.19 root 5470: }
5471:
1.1.1.33 root 5472: void msdos_mem_unlink_umb()
1.1.1.19 root 5473: {
1.1.1.33 root 5474: mcb_t *mcb = (mcb_t *)(mem + MEMORY_END - 16);
5475: msdos_mcb_check(mcb);
1.1.1.19 root 5476:
1.1.1.33 root 5477: mcb->mz = 'Z';
5478: mcb->paragraphs = 0;
1.1.1.39 root 5479:
5480: ((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked &= ~0x01;
1.1.1.19 root 5481: }
5482:
1.1.1.29 root 5483: #ifdef SUPPORT_HMA
5484:
5485: hma_mcb_t *msdos_hma_mcb_create(int offset, int owner, int size, int next)
5486: {
5487: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5488:
5489: mcb->ms[0] = 'M';
5490: mcb->ms[1] = 'S';
5491: mcb->owner = owner;
5492: mcb->size = size;
5493: mcb->next = next;
5494: return(mcb);
5495: }
5496:
5497: bool msdos_is_hma_mcb_valid(hma_mcb_t *mcb)
5498: {
5499: return(mcb->ms[0] == 'M' && mcb->ms[1] == 'S');
5500: }
5501:
5502: int msdos_hma_mem_split(int offset, int size)
5503: {
5504: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5505:
5506: if(!msdos_is_hma_mcb_valid(mcb)) {
5507: return(-1);
5508: }
5509: if(mcb->size >= size + 0x10) {
5510: int new_offset = offset + 0x10 + size;
5511: int new_size = mcb->size - 0x10 - size;
5512:
5513: msdos_hma_mcb_create(new_offset, 0, new_size, mcb->next);
5514: mcb->size = size;
5515: mcb->next = new_offset;
5516: return(0);
5517: }
5518: return(-1);
5519: }
5520:
5521: void msdos_hma_mem_merge(int offset)
5522: {
5523: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5524:
5525: if(!msdos_is_hma_mcb_valid(mcb)) {
5526: return;
5527: }
5528: while(1) {
5529: if(mcb->next == 0) {
5530: break;
5531: }
5532: hma_mcb_t *next_mcb = (hma_mcb_t *)(mem + 0xffff0 + mcb->next);
5533:
5534: if(!msdos_is_hma_mcb_valid(next_mcb)) {
5535: return;
5536: }
5537: if(next_mcb->owner != 0) {
5538: break;
5539: }
5540: mcb->size += 0x10 + next_mcb->size;
5541: mcb->next = next_mcb->next;
5542: }
5543: }
5544:
5545: int msdos_hma_mem_alloc(int size, UINT16 owner)
5546: {
5547: int offset = 0x10; // first mcb in HMA
5548:
5549: while(1) {
5550: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5551:
5552: if(!msdos_is_hma_mcb_valid(mcb)) {
5553: return(-1);
5554: }
5555: if(mcb->owner == 0) {
5556: msdos_hma_mem_merge(offset);
5557: }
5558: if(mcb->owner == 0 && mcb->size >= size) {
5559: msdos_hma_mem_split(offset, size);
5560: mcb->owner = owner;
5561: return(offset);
5562: }
5563: if(mcb->next == 0) {
5564: break;
5565: }
5566: offset = mcb->next;
5567: }
5568: return(-1);
5569: }
5570:
5571: int msdos_hma_mem_realloc(int offset, int size)
5572: {
5573: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5574:
5575: if(!msdos_is_hma_mcb_valid(mcb)) {
5576: return(-1);
5577: }
5578: if(mcb->size < size) {
5579: return(-1);
5580: }
5581: msdos_hma_mem_split(offset, size);
5582: return(0);
5583: }
5584:
5585: void msdos_hma_mem_free(int offset)
5586: {
5587: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5588:
5589: if(!msdos_is_hma_mcb_valid(mcb)) {
5590: return;
5591: }
5592: mcb->owner = 0;
5593: msdos_hma_mem_merge(offset);
5594: }
5595:
5596: int msdos_hma_mem_get_free(int *available_offset)
5597: {
5598: int offset = 0x10; // first mcb in HMA
5599: int size = 0;
5600:
5601: while(1) {
5602: hma_mcb_t *mcb = (hma_mcb_t *)(mem + 0xffff0 + offset);
5603:
5604: if(!msdos_is_hma_mcb_valid(mcb)) {
5605: return(0);
5606: }
5607: if(mcb->owner == 0 && size < mcb->size) {
5608: if(available_offset != NULL) {
5609: *available_offset = offset;
5610: }
5611: size = mcb->size;
5612: }
5613: if(mcb->next == 0) {
5614: break;
5615: }
5616: offset = mcb->next;
5617: }
5618: return(size);
5619: }
5620:
5621: #endif
5622:
1.1 root 5623: // environment
5624:
5625: void msdos_env_set_argv(int env_seg, char *argv)
5626: {
5627: char *dst = (char *)(mem + (env_seg << 4));
5628:
5629: while(1) {
5630: if(dst[0] == 0) {
5631: break;
5632: }
5633: dst += strlen(dst) + 1;
5634: }
5635: *dst++ = 0; // end of environment
5636: *dst++ = 1; // top of argv[0]
5637: *dst++ = 0;
5638: memcpy(dst, argv, strlen(argv));
5639: dst += strlen(argv);
5640: *dst++ = 0;
5641: *dst++ = 0;
5642: }
5643:
5644: char *msdos_env_get_argv(int env_seg)
5645: {
5646: static char env[ENV_SIZE];
5647: char *src = env;
5648:
5649: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
5650: while(1) {
5651: if(src[0] == 0) {
5652: if(src[1] == 1) {
5653: return(src + 3);
5654: }
5655: break;
5656: }
5657: src += strlen(src) + 1;
5658: }
5659: return(NULL);
5660: }
5661:
5662: char *msdos_env_get(int env_seg, const char *name)
5663: {
5664: static char env[ENV_SIZE];
5665: char *src = env;
5666:
5667: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
5668: while(1) {
5669: if(src[0] == 0) {
5670: break;
5671: }
5672: int len = strlen(src);
5673: char *n = my_strtok(src, "=");
5674: char *v = src + strlen(n) + 1;
5675:
5676: if(_stricmp(name, n) == 0) {
5677: return(v);
5678: }
5679: src += len + 1;
5680: }
5681: return(NULL);
5682: }
5683:
5684: void msdos_env_set(int env_seg, char *name, char *value)
5685: {
5686: char env[ENV_SIZE];
5687: char *src = env;
5688: char *dst = (char *)(mem + (env_seg << 4));
5689: char *argv = msdos_env_get_argv(env_seg);
5690: int done = 0;
5691:
5692: memcpy(src, dst, ENV_SIZE);
5693: memset(dst, 0, ENV_SIZE);
5694: while(1) {
5695: if(src[0] == 0) {
5696: break;
5697: }
5698: int len = strlen(src);
5699: char *n = my_strtok(src, "=");
5700: char *v = src + strlen(n) + 1;
5701: char tmp[1024];
5702:
5703: if(_stricmp(name, n) == 0) {
5704: sprintf(tmp, "%s=%s", n, value);
5705: done = 1;
5706: } else {
5707: sprintf(tmp, "%s=%s", n, v);
5708: }
5709: memcpy(dst, tmp, strlen(tmp));
5710: dst += strlen(tmp) + 1;
5711: src += len + 1;
5712: }
5713: if(!done) {
5714: char tmp[1024];
5715:
5716: sprintf(tmp, "%s=%s", name, value);
5717: memcpy(dst, tmp, strlen(tmp));
5718: dst += strlen(tmp) + 1;
5719: }
5720: if(argv) {
5721: *dst++ = 0; // end of environment
5722: *dst++ = 1; // top of argv[0]
5723: *dst++ = 0;
5724: memcpy(dst, argv, strlen(argv));
5725: dst += strlen(argv);
5726: *dst++ = 0;
5727: *dst++ = 0;
5728: }
5729: }
5730:
5731: // process
5732:
1.1.1.8 root 5733: psp_t *msdos_psp_create(int psp_seg, UINT16 mcb_seg, UINT16 parent_psp, UINT16 env_seg)
1.1 root 5734: {
5735: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
5736:
5737: memset(psp, 0, PSP_SIZE);
5738: psp->exit[0] = 0xcd;
5739: psp->exit[1] = 0x20;
1.1.1.8 root 5740: psp->first_mcb = mcb_seg;
1.1 root 5741: psp->far_call = 0xea;
5742: psp->cpm_entry.w.l = 0xfff1; // int 21h, retf
5743: psp->cpm_entry.w.h = 0xf000;
5744: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
5745: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
5746: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
5747: psp->parent_psp = parent_psp;
1.1.1.20 root 5748: if(parent_psp == (UINT16)-1) {
5749: for(int i = 0; i < 20; i++) {
5750: if(file_handler[i].valid) {
5751: psp->file_table[i] = i;
5752: } else {
5753: psp->file_table[i] = 0xff;
5754: }
1.1 root 5755: }
1.1.1.20 root 5756: } else {
5757: memcpy(psp->file_table, ((psp_t *)(mem + (parent_psp << 4)))->file_table, 20);
1.1 root 5758: }
5759: psp->env_seg = env_seg;
5760: psp->stack.w.l = REG16(SP);
1.1.1.3 root 5761: psp->stack.w.h = SREG(SS);
1.1.1.14 root 5762: psp->file_table_size = 20;
5763: psp->file_table_ptr.w.l = 0x18;
5764: psp->file_table_ptr.w.h = psp_seg;
1.1 root 5765: psp->service[0] = 0xcd;
5766: psp->service[1] = 0x21;
5767: psp->service[2] = 0xcb;
5768: return(psp);
5769: }
5770:
1.1.1.20 root 5771: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg)
5772: {
5773: if(psp_seg && fd < 20) {
5774: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
5775: psp->file_table[fd] = value;
5776: }
5777: }
5778:
5779: int msdos_psp_get_file_table(int fd, int psp_seg)
5780: {
5781: if(psp_seg && fd < 20) {
5782: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
5783: fd = psp->file_table[fd];
5784: }
5785: return fd;
5786: }
5787:
1.1 root 5788: int msdos_process_exec(char *cmd, param_block_t *param, UINT8 al)
5789: {
5790: // load command file
5791: int fd = -1;
5792: int dos_command = 0;
1.1.1.24 root 5793: char command[MAX_PATH], path[MAX_PATH], opt[MAX_PATH], *name = NULL, name_tmp[MAX_PATH];
1.1.1.38 root 5794: char pipe_stdin_path[MAX_PATH] = {0};
5795: char pipe_stdout_path[MAX_PATH] = {0};
1.1.1.39 root 5796: char pipe_stderr_path[MAX_PATH] = {0};
1.1 root 5797:
5798: int opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
5799: int opt_len = mem[opt_ofs];
5800: memset(opt, 0, sizeof(opt));
5801: memcpy(opt, mem + opt_ofs + 1, opt_len);
5802:
1.1.1.14 root 5803: if(strlen(cmd) >= 5 && _stricmp(&cmd[strlen(cmd) - 4], ".BAT") == 0) {
5804: // this is a batch file, run command.com
5805: char tmp[MAX_PATH];
5806: if(opt_len != 0) {
5807: sprintf(tmp, "/C %s %s", cmd, opt);
5808: } else {
5809: sprintf(tmp, "/C %s", cmd);
5810: }
5811: strcpy(opt, tmp);
5812: opt_len = strlen(opt);
5813: mem[opt_ofs] = opt_len;
5814: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
5815: strcpy(command, comspec_path);
5816: strcpy(name_tmp, "COMMAND.COM");
5817: } else {
5818: if(_stricmp(cmd, "C:\\COMMAND.COM") == 0) {
5819: // redirect C:\COMMAND.COM to comspec_path
5820: strcpy(command, comspec_path);
5821: } else {
5822: strcpy(command, cmd);
5823: }
1.1.1.24 root 5824: if(GetFullPathName(command, MAX_PATH, path, &name) == 0) {
5825: return(-1);
5826: }
1.1.1.14 root 5827: memset(name_tmp, 0, sizeof(name_tmp));
5828: strcpy(name_tmp, name);
5829:
5830: // check command.com
1.1.1.38 root 5831: if((_stricmp(name, "COMMAND.COM") == 0 || _stricmp(name, "COMMAND") == 0) && _access(comspec_path, 0) != 0) {
5832: // we can not load command.com, so run program directly if "command /c (program)" is specified
1.1.1.14 root 5833: if(opt_len == 0) {
5834: // process_t *current_process = msdos_process_info_get(current_psp);
5835: process_t *current_process = NULL;
5836: for(int i = 0; i < MAX_PROCESS; i++) {
5837: if(process[i].psp == current_psp) {
5838: current_process = &process[i];
5839: break;
5840: }
5841: }
5842: if(current_process != NULL) {
5843: param->cmd_line.dw = current_process->dta.dw;
5844: opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
5845: opt_len = mem[opt_ofs];
5846: memset(opt, 0, sizeof(opt));
5847: memcpy(opt, mem + opt_ofs + 1, opt_len);
5848: }
5849: }
5850: for(int i = 0; i < opt_len; i++) {
5851: if(opt[i] == ' ') {
5852: continue;
5853: }
5854: if(opt[i] == '/' && (opt[i + 1] == 'c' || opt[i + 1] == 'C') && opt[i + 2] == ' ') {
5855: for(int j = i + 3; j < opt_len; j++) {
5856: if(opt[j] == ' ') {
5857: continue;
5858: }
5859: char *token = my_strtok(opt + j, " ");
5860:
1.1.1.38 root 5861: strcpy(command, token);
5862: char tmp[MAX_PATH];
5863: strcpy(tmp, token + strlen(token) + 1);
1.1.1.39 root 5864: strcpy(opt, "");
5865: for(int i = 0; i < strlen(tmp); i++) {
5866: if(tmp[i] != ' ') {
5867: strcpy(opt, tmp + i);
5868: break;
5869: }
5870: }
5871: strcpy(tmp, opt);
1.1.1.38 root 5872:
5873: if(al == 0x00) {
1.1.1.39 root 5874: #define GET_FILE_PATH() { \
5875: if(token[0] != '>' && token[0] != '<') { \
5876: token++; \
5877: } \
5878: token++; \
5879: while(*token == ' ') { \
5880: token++; \
5881: } \
5882: char *ptr = token; \
5883: while(*ptr != ' ' && *ptr != '\r' && *ptr != '\0') { \
5884: ptr++; \
5885: } \
5886: *ptr = '\0'; \
5887: }
5888: if((token = strstr(opt, "0<")) != NULL || (token = strstr(opt, "<")) != NULL) {
5889: GET_FILE_PATH();
1.1.1.38 root 5890: strcpy(pipe_stdin_path, token);
5891: strcpy(opt, tmp);
5892: }
1.1.1.39 root 5893: if((token = strstr(opt, "1>")) != NULL || (token = strstr(opt, ">")) != NULL) {
5894: GET_FILE_PATH();
1.1.1.38 root 5895: strcpy(pipe_stdout_path, token);
5896: strcpy(opt, tmp);
5897: }
1.1.1.39 root 5898: if((token = strstr(opt, "2>")) != NULL) {
5899: GET_FILE_PATH();
5900: strcpy(pipe_stderr_path, token);
5901: strcpy(opt, tmp);
5902: }
5903: #undef GET_FILE_PATH
5904:
5905: if((token = strstr(opt, "0<")) != NULL) {
5906: *token = '\0';
5907: }
5908: if((token = strstr(opt, "1>")) != NULL) {
5909: *token = '\0';
5910: }
5911: if((token = strstr(opt, "2>")) != NULL) {
5912: *token = '\0';
5913: }
1.1.1.38 root 5914: if((token = strstr(opt, "<")) != NULL) {
5915: *token = '\0';
5916: }
5917: if((token = strstr(opt, ">")) != NULL) {
5918: *token = '\0';
5919: }
1.1.1.14 root 5920: }
1.1.1.39 root 5921: for(int i = strlen(opt) - 1; i >= 0 && opt[i] == ' '; i--) {
5922: opt[i] = '\0';
5923: }
1.1.1.38 root 5924: opt_len = strlen(opt);
5925: mem[opt_ofs] = opt_len;
5926: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
5927: dos_command = 1;
1.1.1.14 root 5928: break;
1.1 root 5929: }
5930: }
1.1.1.14 root 5931: break;
1.1 root 5932: }
5933: }
5934: }
5935:
5936: // load command file
5937: strcpy(path, command);
5938: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
5939: sprintf(path, "%s.COM", command);
5940: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
5941: sprintf(path, "%s.EXE", command);
5942: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
1.1.1.14 root 5943: sprintf(path, "%s.BAT", command);
5944: if(_access(path, 0) == 0) {
5945: // this is a batch file, run command.com
5946: char tmp[MAX_PATH];
5947: if(opt_len != 0) {
5948: sprintf(tmp, "/C %s %s", path, opt);
5949: } else {
5950: sprintf(tmp, "/C %s", path);
5951: }
5952: strcpy(opt, tmp);
5953: opt_len = strlen(opt);
5954: mem[opt_ofs] = opt_len;
5955: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
5956: strcpy(path, comspec_path);
5957: strcpy(name_tmp, "COMMAND.COM");
5958: fd = _open(path, _O_RDONLY | _O_BINARY);
5959: } else {
5960: // search path in parent environments
5961: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
5962: char *env = msdos_env_get(parent_psp->env_seg, "PATH");
5963: if(env != NULL) {
5964: char env_path[4096];
5965: strcpy(env_path, env);
5966: char *token = my_strtok(env_path, ";");
5967:
5968: while(token != NULL) {
5969: if(strlen(token) != 0) {
5970: sprintf(path, "%s", msdos_combine_path(token, command));
5971: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
5972: break;
5973: }
5974: sprintf(path, "%s.COM", msdos_combine_path(token, command));
5975: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
5976: break;
5977: }
5978: sprintf(path, "%s.EXE", msdos_combine_path(token, command));
5979: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
5980: break;
5981: }
5982: sprintf(path, "%s.BAT", msdos_combine_path(token, command));
5983: if(_access(path, 0) == 0) {
5984: // this is a batch file, run command.com
5985: char tmp[MAX_PATH];
5986: if(opt_len != 0) {
5987: sprintf(tmp, "/C %s %s", path, opt);
5988: } else {
5989: sprintf(tmp, "/C %s", path);
5990: }
5991: strcpy(opt, tmp);
5992: opt_len = strlen(opt);
5993: mem[opt_ofs] = opt_len;
5994: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
5995: strcpy(path, comspec_path);
5996: strcpy(name_tmp, "COMMAND.COM");
5997: fd = _open(path, _O_RDONLY | _O_BINARY);
5998: break;
5999: }
1.1.1.8 root 6000: }
1.1.1.14 root 6001: token = my_strtok(NULL, ";");
1.1 root 6002: }
6003: }
6004: }
6005: }
6006: }
6007: }
6008: if(fd == -1) {
1.1.1.38 root 6009: // we can not find command.com in the path, so open comspec_path
6010: if(_stricmp(command, "COMMAND.COM") == 0 || _stricmp(command, "COMMAND") == 0) {
6011: strcpy(command, comspec_path);
6012: strcpy(path, command);
6013: fd = _open(path, _O_RDONLY | _O_BINARY);
6014: }
6015: }
6016: if(fd == -1) {
1.1 root 6017: if(dos_command) {
6018: // may be dos command
6019: char tmp[MAX_PATH];
6020: sprintf(tmp, "%s %s", command, opt);
6021: system(tmp);
6022: return(0);
6023: } else {
6024: return(-1);
6025: }
6026: }
6027: _read(fd, file_buffer, sizeof(file_buffer));
6028: _close(fd);
6029:
6030: // copy environment
1.1.1.29 root 6031: int umb_linked, env_seg, psp_seg;
1.1 root 6032:
1.1.1.29 root 6033: if((umb_linked = msdos_mem_get_umb_linked()) != 0) {
6034: msdos_mem_unlink_umb();
6035: }
1.1.1.8 root 6036: if((env_seg = msdos_mem_alloc(first_mcb, ENV_SIZE >> 4, 1)) == -1) {
1.1.1.29 root 6037: if((env_seg = msdos_mem_alloc(UMB_TOP >> 4, ENV_SIZE >> 4, 1)) == -1) {
6038: if(umb_linked != 0) {
6039: msdos_mem_link_umb();
6040: }
6041: return(-1);
6042: }
1.1 root 6043: }
6044: if(param->env_seg == 0) {
6045: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
6046: memcpy(mem + (env_seg << 4), mem + (parent_psp->env_seg << 4), ENV_SIZE);
6047: } else {
6048: memcpy(mem + (env_seg << 4), mem + (param->env_seg << 4), ENV_SIZE);
6049: }
6050: msdos_env_set_argv(env_seg, msdos_short_full_path(path));
6051:
6052: // check exe header
6053: exe_header_t *header = (exe_header_t *)file_buffer;
1.1.1.8 root 6054: int paragraphs, free_paragraphs = msdos_mem_get_free(first_mcb, 1);
1.1 root 6055: UINT16 cs, ss, ip, sp;
6056:
6057: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
6058: // memory allocation
6059: int header_size = header->header_size * 16;
6060: int load_size = header->pages * 512 - header_size;
6061: if(header_size + load_size < 512) {
6062: load_size = 512 - header_size;
6063: }
6064: paragraphs = (PSP_SIZE + load_size) >> 4;
6065: if(paragraphs + header->min_alloc > free_paragraphs) {
6066: msdos_mem_free(env_seg);
6067: return(-1);
6068: }
6069: paragraphs += header->max_alloc ? header->max_alloc : header->min_alloc;
6070: if(paragraphs > free_paragraphs) {
6071: paragraphs = free_paragraphs;
6072: }
1.1.1.8 root 6073: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1.1.29 root 6074: if((psp_seg = msdos_mem_alloc(UMB_TOP >> 4, paragraphs, 1)) == -1) {
6075: if(umb_linked != 0) {
6076: msdos_mem_link_umb();
6077: }
6078: msdos_mem_free(env_seg);
6079: return(-1);
6080: }
1.1 root 6081: }
6082: // relocation
6083: int start_seg = psp_seg + (PSP_SIZE >> 4);
6084: for(int i = 0; i < header->relocations; i++) {
6085: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
6086: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
6087: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
6088: }
6089: memcpy(mem + (start_seg << 4), file_buffer + header_size, load_size);
6090: // segments
6091: cs = header->init_cs + start_seg;
6092: ss = header->init_ss + start_seg;
6093: ip = header->init_ip;
6094: sp = header->init_sp - 2; // for symdeb
6095: } else {
6096: // memory allocation
6097: paragraphs = free_paragraphs;
1.1.1.8 root 6098: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1.1.29 root 6099: if((psp_seg = msdos_mem_alloc(UMB_TOP >> 4, paragraphs, 1)) == -1) {
6100: if(umb_linked != 0) {
6101: msdos_mem_link_umb();
6102: }
6103: msdos_mem_free(env_seg);
6104: return(-1);
6105: }
1.1 root 6106: }
6107: int start_seg = psp_seg + (PSP_SIZE >> 4);
6108: memcpy(mem + (start_seg << 4), file_buffer, 0x10000 - PSP_SIZE);
6109: // segments
6110: cs = ss = psp_seg;
6111: ip = 0x100;
6112: sp = 0xfffe;
6113: }
1.1.1.29 root 6114: if(umb_linked != 0) {
6115: msdos_mem_link_umb();
6116: }
1.1 root 6117:
6118: // create psp
1.1.1.3 root 6119: *(UINT16 *)(mem + 4 * 0x22 + 0) = m_eip;
6120: *(UINT16 *)(mem + 4 * 0x22 + 2) = SREG(CS);
1.1 root 6121: psp_t *psp = msdos_psp_create(psp_seg, psp_seg + paragraphs, current_psp, env_seg);
6122: memcpy(psp->fcb1, mem + (param->fcb1.w.h << 4) + param->fcb1.w.l, sizeof(psp->fcb1));
6123: memcpy(psp->fcb2, mem + (param->fcb2.w.h << 4) + param->fcb2.w.l, sizeof(psp->fcb2));
6124: memcpy(psp->buffer, mem + (param->cmd_line.w.h << 4) + param->cmd_line.w.l, sizeof(psp->buffer));
6125:
6126: mcb_t *mcb_env = (mcb_t *)(mem + ((env_seg - 1) << 4));
6127: mcb_t *mcb_psp = (mcb_t *)(mem + ((psp_seg - 1) << 4));
6128: mcb_psp->psp = mcb_env->psp = psp_seg;
6129:
1.1.1.4 root 6130: for(int i = 0; i < 8; i++) {
6131: if(name_tmp[i] == '.') {
6132: mcb_psp->prog_name[i] = '\0';
6133: break;
6134: } else if(i < 7 && msdos_lead_byte_check(name_tmp[i])) {
6135: mcb_psp->prog_name[i] = name_tmp[i];
6136: i++;
6137: mcb_psp->prog_name[i] = name_tmp[i];
6138: } else if(name_tmp[i] >= 'a' && name_tmp[i] <= 'z') {
6139: mcb_psp->prog_name[i] = name_tmp[i] - 'a' + 'A';
6140: } else {
6141: mcb_psp->prog_name[i] = name_tmp[i];
6142: }
6143: }
6144:
1.1 root 6145: // process info
6146: process_t *process = msdos_process_info_create(psp_seg);
6147: strcpy(process->module_dir, msdos_short_full_dir(path));
1.1.1.33 root 6148: #ifdef USE_DEBUGGER
6149: strcpy(process->module_path, path);
6150: #endif
1.1 root 6151: process->dta.w.l = 0x80;
6152: process->dta.w.h = psp_seg;
6153: process->switchar = '/';
6154: process->max_files = 20;
6155: process->parent_int_10h_feh_called = int_10h_feh_called;
6156: process->parent_int_10h_ffh_called = int_10h_ffh_called;
1.1.1.14 root 6157: process->parent_ds = SREG(DS);
1.1.1.31 root 6158: process->parent_es = SREG(ES);
1.1 root 6159:
6160: current_psp = psp_seg;
1.1.1.23 root 6161: msdos_sda_update(current_psp);
1.1 root 6162:
6163: if(al == 0x00) {
6164: int_10h_feh_called = int_10h_ffh_called = false;
6165:
1.1.1.38 root 6166: // pipe
6167: if(pipe_stdin_path[0] != '\0') {
6168: if((fd = _open(pipe_stdin_path, _O_RDONLY | _O_BINARY)) != -1) {
6169: UINT16 info = msdos_drive_number(pipe_stdin_path);
6170: msdos_file_handler_open(fd, pipe_stdin_path, _isatty(fd), 0, info, current_psp);
6171: psp->file_table[0] = fd;
6172: msdos_psp_set_file_table(fd, fd, current_psp);
6173: }
6174: }
6175: if(pipe_stdout_path[0] != '\0') {
6176: if(_access(pipe_stdout_path, 0) == 0) {
6177: SetFileAttributes(pipe_stdout_path, FILE_ATTRIBUTE_NORMAL);
6178: DeleteFile(pipe_stdout_path);
6179: }
6180: if((fd = _open(pipe_stdout_path, _O_WRONLY | _O_BINARY | _O_CREAT)) != -1) {
6181: UINT16 info = msdos_drive_number(pipe_stdout_path);
6182: msdos_file_handler_open(fd, pipe_stdout_path, _isatty(fd), 1, info, current_psp);
6183: psp->file_table[1] = fd;
6184: msdos_psp_set_file_table(fd, fd, current_psp);
6185: }
6186: }
1.1.1.39 root 6187: if(pipe_stderr_path[0] != '\0') {
6188: if(_access(pipe_stderr_path, 0) == 0) {
6189: SetFileAttributes(pipe_stderr_path, FILE_ATTRIBUTE_NORMAL);
6190: DeleteFile(pipe_stderr_path);
6191: }
6192: if((fd = _open(pipe_stderr_path, _O_WRONLY | _O_BINARY | _O_CREAT)) != -1) {
6193: UINT16 info = msdos_drive_number(pipe_stderr_path);
6194: msdos_file_handler_open(fd, pipe_stderr_path, _isatty(fd), 2, info, current_psp);
6195: psp->file_table[2] = fd;
6196: msdos_psp_set_file_table(fd, fd, current_psp);
6197: }
6198: }
1.1.1.38 root 6199:
1.1 root 6200: // registers and segments
6201: REG16(AX) = REG16(BX) = 0x00;
6202: REG16(CX) = 0xff;
6203: REG16(DX) = psp_seg;
6204: REG16(SI) = ip;
6205: REG16(DI) = sp;
6206: REG16(SP) = sp;
1.1.1.3 root 6207: SREG(DS) = SREG(ES) = psp_seg;
6208: SREG(SS) = ss;
6209: i386_load_segment_descriptor(DS);
6210: i386_load_segment_descriptor(ES);
6211: i386_load_segment_descriptor(SS);
1.1 root 6212:
6213: *(UINT16 *)(mem + (ss << 4) + sp) = 0;
6214: i386_jmp_far(cs, ip);
6215: } else if(al == 0x01) {
6216: // copy ss:sp and cs:ip to param block
6217: param->sp = sp;
6218: param->ss = ss;
6219: param->ip = ip;
6220: param->cs = cs;
1.1.1.31 root 6221:
6222: // the AX value to be passed to the child program is put on top of the child's stack
6223: *(UINT16 *)(mem + (ss << 4) + sp) = REG16(AX);
1.1 root 6224: }
6225: return(0);
6226: }
6227:
6228: void msdos_process_terminate(int psp_seg, int ret, int mem_free)
6229: {
6230: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
6231:
6232: *(UINT32 *)(mem + 4 * 0x22) = psp->int_22h.dw;
6233: *(UINT32 *)(mem + 4 * 0x23) = psp->int_23h.dw;
6234: *(UINT32 *)(mem + 4 * 0x24) = psp->int_24h.dw;
6235:
1.1.1.3 root 6236: SREG(SS) = psp->stack.w.h;
6237: i386_load_segment_descriptor(SS);
1.1 root 6238: REG16(SP) = psp->stack.w.l;
6239: i386_jmp_far(psp->int_22h.w.h, psp->int_22h.w.l);
6240:
1.1.1.28 root 6241: // process_t *current_process = msdos_process_info_get(psp_seg);
6242: process_t *current_process = NULL;
6243: for(int i = 0; i < MAX_PROCESS; i++) {
6244: if(process[i].psp == psp_seg) {
6245: current_process = &process[i];
6246: break;
6247: }
6248: }
6249: if(current_process == NULL) {
6250: throw(0x1f); // general failure
6251: }
6252: int_10h_feh_called = current_process->parent_int_10h_feh_called;
6253: int_10h_ffh_called = current_process->parent_int_10h_ffh_called;
6254: if(current_process->called_by_int2eh) {
6255: REG16(AX) = ret;
6256: }
6257: SREG(DS) = current_process->parent_ds;
1.1.1.31 root 6258: SREG(ES) = current_process->parent_es;
1.1.1.14 root 6259: i386_load_segment_descriptor(DS);
1.1.1.31 root 6260: i386_load_segment_descriptor(ES);
1.1 root 6261:
6262: if(mem_free) {
1.1.1.8 root 6263: int mcb_seg;
6264: while((mcb_seg = msdos_mem_get_last_mcb(first_mcb, psp_seg)) != -1) {
6265: msdos_mem_free(mcb_seg + 1);
6266: }
6267: while((mcb_seg = msdos_mem_get_last_mcb(UMB_TOP >> 4, psp_seg)) != -1) {
6268: msdos_mem_free(mcb_seg + 1);
6269: }
1.1 root 6270:
6271: for(int i = 0; i < MAX_FILES; i++) {
6272: if(file_handler[i].valid && file_handler[i].psp == psp_seg) {
6273: _close(i);
1.1.1.20 root 6274: msdos_file_handler_close(i);
6275: msdos_psp_set_file_table(i, 0x0ff, psp_seg); // FIXME: consider duplicated file handles
1.1 root 6276: }
6277: }
1.1.1.13 root 6278: msdos_dta_info_free(psp_seg);
1.1 root 6279: }
1.1.1.14 root 6280: msdos_stdio_reopen();
1.1 root 6281:
1.1.1.28 root 6282: memset(current_process, 0, sizeof(process_t));
1.1 root 6283:
6284: current_psp = psp->parent_psp;
6285: retval = ret;
1.1.1.23 root 6286: msdos_sda_update(current_psp);
1.1 root 6287: }
6288:
6289: // drive
6290:
6291: int msdos_drive_param_block_update(int drive_num, UINT16 *seg, UINT16 *ofs, int force_update)
6292: {
1.1.1.41! root 6293: if(!(drive_num >= 0 && drive_num < 26)) {
! 6294: return(0);
! 6295: }
1.1 root 6296: *seg = DPB_TOP >> 4;
6297: *ofs = sizeof(dpb_t) * drive_num;
6298: dpb_t *dpb = (dpb_t *)(mem + (*seg << 4) + *ofs);
6299:
6300: if(!force_update && dpb->free_clusters != 0) {
6301: return(dpb->bytes_per_sector ? 1 : 0);
6302: }
6303: memset(dpb, 0, sizeof(dpb_t));
6304:
6305: int res = 0;
6306: char dev[64];
6307: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num);
6308:
1.1.1.17 root 6309: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1.1 root 6310: if(hFile != INVALID_HANDLE_VALUE) {
6311: DISK_GEOMETRY geo;
6312: DWORD dwSize;
6313: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
6314: dpb->bytes_per_sector = (UINT16)geo.BytesPerSector;
6315: dpb->highest_sector_num = (UINT8)(geo.SectorsPerTrack - 1);
6316: dpb->highest_cluster_num = (UINT16)(geo.TracksPerCylinder * geo.Cylinders.QuadPart + 1);
1.1.1.14 root 6317: dpb->maximum_cluster_num = (UINT32)(geo.TracksPerCylinder * geo.Cylinders.QuadPart + 1);
1.1 root 6318: switch(geo.MediaType) {
6319: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K)
6320: dpb->media_type = 0xff;
6321: break;
6322: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K)
6323: dpb->media_type = 0xfe;
6324: break;
6325: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K)
6326: dpb->media_type = 0xfd;
6327: break;
6328: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K)
6329: dpb->media_type = 0xfc;
6330: break;
6331: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M)
6332: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5")
6333: dpb->media_type = 0xf9;
6334: break;
6335: case FixedMedia: // hard disk
6336: case RemovableMedia:
1.1.1.19 root 6337: case Unknown:
1.1 root 6338: dpb->media_type = 0xf8;
6339: break;
6340: default:
6341: dpb->media_type = 0xf0;
6342: break;
6343: }
6344: res = 1;
6345: }
1.1.1.14 root 6346: dpb->info_sector = 0xffff;
6347: dpb->backup_boot_sector = 0xffff;
1.1 root 6348: dpb->free_clusters = 0xffff;
1.1.1.14 root 6349: dpb->free_search_cluster = 0xffffffff;
1.1 root 6350: CloseHandle(hFile);
6351: }
1.1.1.41! root 6352: dpb->drive_num = drive_num;
! 6353: dpb->unit_num = drive_num;
! 6354: dpb->next_dpb_ofs = (drive_num == 25) ? 0xffff : *ofs + sizeof(dpb_t);
! 6355: dpb->next_dpb_seg = (drive_num == 25) ? 0xffff : *seg;
1.1 root 6356: return(res);
6357: }
6358:
6359: // pc bios
6360:
1.1.1.35 root 6361: #ifdef USE_SERVICE_THREAD
6362: void start_service_loop(LPTHREAD_START_ROUTINE lpStartAddress)
6363: {
6364: #if defined(HAS_I386)
6365: if(m_SF != 0) {
6366: m_SF = 0;
6367: mem[0xfffd0 + 0x15] = 0x79; // jns -4
6368: } else {
6369: m_SF = 1;
6370: mem[0xfffd0 + 0x15] = 0x78; // js -4
6371: }
6372: #else
6373: if(m_SignVal < 0) {
6374: m_SignVal = 0;
6375: mem[0xfffd0 + 0x15] = 0x79; // jns -4
6376: } else {
6377: m_SignVal = -1;
6378: mem[0xfffd0 + 0x15] = 0x78; // js -4
6379: }
6380: #endif
6381: i386_call_far(0xfffd, 0x0013);
6382: in_service = true;
6383: service_exit = false;
6384: CloseHandle(CreateThread(NULL, 0, lpStartAddress, NULL, 0, NULL));
6385: }
6386:
6387: void finish_service_loop()
6388: {
6389: if(in_service && service_exit) {
6390: #if defined(HAS_I386)
6391: if(m_SF != 0) {
6392: m_SF = 0;
6393: } else {
6394: m_SF = 1;
6395: }
6396: #else
6397: if(m_SignVal < 0) {
6398: m_SignVal = 0;
6399: } else {
6400: m_SignVal = -1;
6401: }
6402: #endif
6403: in_service = false;
6404: }
6405: }
6406: #endif
6407:
1.1.1.19 root 6408: UINT32 get_ticks_since_midnight(UINT32 cur_msec)
6409: {
6410: static unsigned __int64 start_msec_since_midnight = 0;
6411: static unsigned __int64 start_msec_since_hostboot = 0;
6412:
6413: if(start_msec_since_midnight == 0) {
6414: SYSTEMTIME time;
6415: GetLocalTime(&time);
6416: start_msec_since_midnight = ((time.wHour * 60 + time.wMinute) * 60 + time.wSecond) * 1000 + time.wMilliseconds;
6417: start_msec_since_hostboot = cur_msec;
6418: }
6419: unsigned __int64 msec = (start_msec_since_midnight + cur_msec - start_msec_since_hostboot) % (24 * 60 * 60 * 1000);
6420: unsigned __int64 tick = msec * 0x1800b0 / (24 * 60 * 60 * 1000);
6421: return (UINT32)tick;
6422: }
6423:
6424: void pcbios_update_daily_timer_counter(UINT32 cur_msec)
6425: {
6426: UINT32 prev_tick = *(UINT32 *)(mem + 0x46c);
6427: UINT32 next_tick = get_ticks_since_midnight(cur_msec);
6428:
6429: if(prev_tick > next_tick) {
6430: mem[0x470] = 1;
6431: }
6432: *(UINT32 *)(mem + 0x46c) = next_tick;
6433: }
6434:
1.1.1.14 root 6435: inline void pcbios_irq0()
6436: {
6437: //++*(UINT32 *)(mem + 0x46c);
1.1.1.19 root 6438: pcbios_update_daily_timer_counter(timeGetTime());
1.1.1.14 root 6439: }
6440:
1.1.1.16 root 6441: int pcbios_get_text_vram_address(int page)
1.1 root 6442: {
6443: if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 6444: return TEXT_VRAM_TOP;
1.1 root 6445: } else {
1.1.1.14 root 6446: return TEXT_VRAM_TOP + VIDEO_REGEN * (page % vram_pages);
1.1 root 6447: }
6448: }
6449:
1.1.1.16 root 6450: int pcbios_get_shadow_buffer_address(int page)
1.1 root 6451: {
1.1.1.14 root 6452: if(!int_10h_feh_called) {
1.1.1.16 root 6453: return pcbios_get_text_vram_address(page);
1.1.1.14 root 6454: } else if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 6455: return SHADOW_BUF_TOP;
6456: } else {
1.1.1.14 root 6457: return SHADOW_BUF_TOP + VIDEO_REGEN * (page % vram_pages);
1.1.1.8 root 6458: }
6459: }
6460:
1.1.1.16 root 6461: int pcbios_get_shadow_buffer_address(int page, int x, int y)
1.1.1.8 root 6462: {
1.1.1.16 root 6463: return pcbios_get_shadow_buffer_address(page) + (x + y * scr_width) * 2;
1.1 root 6464: }
6465:
1.1.1.16 root 6466: void pcbios_set_console_size(int width, int height, bool clr_screen)
1.1 root 6467: {
1.1.1.14 root 6468: // clear the existing screen, not just the new one
6469: int clr_height = max(height, scr_height);
6470:
1.1.1.16 root 6471: if(scr_width != width || scr_height != height) {
6472: change_console_size(width, height);
1.1.1.14 root 6473: }
6474: mem[0x462] = 0;
6475: *(UINT16 *)(mem + 0x44e) = 0;
6476:
1.1.1.16 root 6477: text_vram_top_address = pcbios_get_text_vram_address(0);
6478: text_vram_end_address = text_vram_top_address + width * height * 2;
6479: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(0);
6480: shadow_buffer_end_address = shadow_buffer_top_address + width * height * 2;
1.1 root 6481:
1.1.1.23 root 6482: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.16 root 6483: if(clr_screen) {
1.1.1.14 root 6484: for(int ofs = shadow_buffer_top_address; ofs < shadow_buffer_end_address;) {
6485: mem[ofs++] = 0x20;
6486: mem[ofs++] = 0x07;
6487: }
6488:
1.1.1.35 root 6489: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6490: EnterCriticalSection(&vram_crit_sect);
1.1.1.35 root 6491: #endif
1.1.1.14 root 6492: for(int y = 0; y < clr_height; y++) {
6493: for(int x = 0; x < scr_width; x++) {
6494: SCR_BUF(y,x).Char.AsciiChar = ' ';
6495: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
1.1 root 6496: }
6497: }
6498: SMALL_RECT rect;
1.1.1.14 root 6499: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + clr_height - 1);
6500: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
6501: vram_length_char = vram_last_length_char = 0;
6502: vram_length_attr = vram_last_length_attr = 0;
1.1.1.35 root 6503: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6504: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35 root 6505: #endif
1.1 root 6506: }
1.1.1.14 root 6507: COORD co;
6508: co.X = 0;
6509: co.Y = scr_top;
6510: SetConsoleCursorPosition(hStdout, co);
6511: cursor_moved = true;
6512: SetConsoleTextAttribute(hStdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
1.1 root 6513: }
6514:
1.1.1.36 root 6515: void pcbios_update_cursor_position()
6516: {
6517: CONSOLE_SCREEN_BUFFER_INFO csbi;
6518: GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
6519: if(!restore_console_on_exit) {
6520: scr_top = csbi.srWindow.Top;
6521: }
6522: mem[0x450 + mem[0x462] * 2] = csbi.dwCursorPosition.X;
6523: mem[0x451 + mem[0x462] * 2] = csbi.dwCursorPosition.Y - scr_top;
6524: }
6525:
1.1.1.16 root 6526: inline void pcbios_int_10h_00h()
6527: {
6528: switch(REG8(AL) & 0x7f) {
6529: case 0x70: // v-text mode
6530: case 0x71: // extended cga v-text mode
6531: pcbios_set_console_size(scr_width, scr_height, !(REG8(AL) & 0x80));
6532: break;
6533: default:
6534: pcbios_set_console_size(80, 25, !(REG8(AL) & 0x80));
6535: break;
6536: }
6537: if(REG8(AL) & 0x80) {
6538: mem[0x487] |= 0x80;
6539: } else {
6540: mem[0x487] &= ~0x80;
6541: }
6542: mem[0x449] = REG8(AL) & 0x7f;
6543: }
6544:
1.1 root 6545: inline void pcbios_int_10h_01h()
6546: {
1.1.1.13 root 6547: mem[0x460] = REG8(CL);
6548: mem[0x461] = REG8(CH);
1.1.1.14 root 6549:
1.1.1.23 root 6550: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 6551: CONSOLE_CURSOR_INFO ci;
6552: GetConsoleCursorInfo(hStdout, &ci);
6553: // ci.bVisible = !(REG8(CH) & 0x60) && REG8(CH) <= REG8(CL);
6554: // if(ci.bVisible) {
6555: int lines = max(8, REG8(CL) + 1);
6556: ci.dwSize = (REG8(CL) - REG8(CH) + 1) * 100 / lines;
6557: // }
6558: SetConsoleCursorInfo(hStdout, &ci);
1.1 root 6559: }
6560:
6561: inline void pcbios_int_10h_02h()
6562: {
1.1.1.14 root 6563: // continuously setting the cursor effectively stops it blinking
6564: if(mem[0x462] == REG8(BH) && (REG8(DL) != mem[0x450 + REG8(BH) * 2] || REG8(DH) != mem[0x451 + REG8(BH) * 2])) {
1.1 root 6565: COORD co;
6566: co.X = REG8(DL);
1.1.1.14 root 6567: co.Y = REG8(DH) + scr_top;
6568:
6569: // some programs hide the cursor by moving it off screen
6570: static bool hidden = false;
1.1.1.23 root 6571: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 6572: CONSOLE_CURSOR_INFO ci;
6573: GetConsoleCursorInfo(hStdout, &ci);
6574:
6575: if(REG8(DH) >= scr_height || !SetConsoleCursorPosition(hStdout, co)) {
6576: if(ci.bVisible) {
6577: ci.bVisible = FALSE;
6578: // SetConsoleCursorInfo(hStdout, &ci);
6579: hidden = true;
6580: }
6581: } else if(hidden) {
6582: if(!ci.bVisible) {
6583: ci.bVisible = TRUE;
6584: // SetConsoleCursorInfo(hStdout, &ci);
6585: }
6586: hidden = false;
6587: }
1.1 root 6588: }
1.1.1.14 root 6589: mem[0x450 + (REG8(BH) % vram_pages) * 2] = REG8(DL);
6590: mem[0x451 + (REG8(BH) % vram_pages) * 2] = REG8(DH);
1.1 root 6591: }
6592:
6593: inline void pcbios_int_10h_03h()
6594: {
1.1.1.14 root 6595: REG8(DL) = mem[0x450 + (REG8(BH) % vram_pages) * 2];
6596: REG8(DH) = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 6597: REG8(CL) = mem[0x460];
6598: REG8(CH) = mem[0x461];
6599: }
6600:
6601: inline void pcbios_int_10h_05h()
6602: {
1.1.1.14 root 6603: if(REG8(AL) >= vram_pages) {
6604: return;
6605: }
6606: if(mem[0x462] != REG8(AL)) {
6607: vram_flush();
6608:
1.1.1.23 root 6609: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6610: SMALL_RECT rect;
1.1.1.14 root 6611: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
6612: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 6613:
1.1.1.16 root 6614: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(mem[0x462]); y < scr_height; y++) {
1.1.1.14 root 6615: for(int x = 0; x < scr_width; x++) {
6616: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
6617: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 6618: }
6619: }
1.1.1.16 root 6620: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(REG8(AL)); y < scr_height; y++) {
1.1.1.14 root 6621: for(int x = 0; x < scr_width; x++) {
6622: SCR_BUF(y,x).Char.AsciiChar = mem[ofs++];
6623: SCR_BUF(y,x).Attributes = mem[ofs++];
1.1 root 6624: }
6625: }
1.1.1.14 root 6626: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 6627:
6628: COORD co;
1.1.1.14 root 6629: co.X = mem[0x450 + REG8(AL) * 2];
6630: co.Y = mem[0x451 + REG8(AL) * 2] + scr_top;
6631: if(co.Y < scr_top + scr_height) {
6632: SetConsoleCursorPosition(hStdout, co);
6633: }
1.1 root 6634: }
1.1.1.14 root 6635: mem[0x462] = REG8(AL);
6636: *(UINT16 *)(mem + 0x44e) = REG8(AL) * VIDEO_REGEN;
6637: int regen = min(scr_width * scr_height * 2, 0x8000);
1.1.1.16 root 6638: text_vram_top_address = pcbios_get_text_vram_address(mem[0x462]);
1.1.1.14 root 6639: text_vram_end_address = text_vram_top_address + regen;
1.1.1.16 root 6640: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(mem[0x462]);
1.1.1.14 root 6641: shadow_buffer_end_address = shadow_buffer_top_address + regen;
1.1 root 6642: }
6643:
6644: inline void pcbios_int_10h_06h()
6645: {
1.1.1.14 root 6646: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
6647: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
6648: return;
6649: }
6650: vram_flush();
6651:
1.1.1.23 root 6652: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6653: SMALL_RECT rect;
1.1.1.14 root 6654: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
6655: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
6656:
6657: int right = min(REG8(DL), scr_width - 1);
6658: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 6659:
6660: if(REG8(AL) == 0) {
1.1.1.14 root 6661: for(int y = REG8(CH); y <= bottom; y++) {
1.1.1.16 root 6662: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 6663: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
6664: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 6665: }
6666: }
6667: } else {
1.1.1.14 root 6668: for(int y = REG8(CH), y2 = min(REG8(CH) + REG8(AL), bottom + 1); y <= bottom; y++, y2++) {
1.1.1.16 root 6669: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 6670: if(y2 <= bottom) {
6671: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 6672: } else {
1.1.1.14 root 6673: SCR_BUF(y,x).Char.AsciiChar = ' ';
6674: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 6675: }
1.1.1.14 root 6676: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
6677: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 6678: }
6679: }
6680: }
1.1.1.14 root 6681: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 6682: }
6683:
6684: inline void pcbios_int_10h_07h()
6685: {
1.1.1.14 root 6686: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
6687: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
6688: return;
6689: }
6690: vram_flush();
6691:
1.1.1.23 root 6692: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6693: SMALL_RECT rect;
1.1.1.14 root 6694: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
6695: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
6696:
6697: int right = min(REG8(DL), scr_width - 1);
6698: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 6699:
6700: if(REG8(AL) == 0) {
1.1.1.14 root 6701: for(int y = REG8(CH); y <= bottom; y++) {
1.1.1.16 root 6702: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 6703: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
6704: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 6705: }
6706: }
6707: } else {
1.1.1.14 root 6708: for(int y = bottom, y2 = max(REG8(CH) - 1, bottom - REG8(AL)); y >= REG8(CH); y--, y2--) {
1.1.1.16 root 6709: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 6710: if(y2 >= REG8(CH)) {
6711: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 6712: } else {
1.1.1.14 root 6713: SCR_BUF(y,x).Char.AsciiChar = ' ';
6714: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 6715: }
1.1.1.14 root 6716: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
6717: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 6718: }
6719: }
6720: }
1.1.1.14 root 6721: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 6722: }
6723:
6724: inline void pcbios_int_10h_08h()
6725: {
6726: COORD co;
6727: DWORD num;
6728:
1.1.1.14 root 6729: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
6730: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 6731:
6732: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 6733: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 6734: co.Y += scr_top;
6735: vram_flush();
1.1 root 6736: ReadConsoleOutputCharacter(hStdout, scr_char, 1, co, &num);
6737: ReadConsoleOutputAttribute(hStdout, scr_attr, 1, co, &num);
6738: REG8(AL) = scr_char[0];
6739: REG8(AH) = scr_attr[0];
6740: } else {
1.1.1.16 root 6741: REG16(AX) = *(UINT16 *)(mem + pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y));
1.1 root 6742: }
6743: }
6744:
6745: inline void pcbios_int_10h_09h()
6746: {
6747: COORD co;
6748:
1.1.1.14 root 6749: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
6750: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
6751:
1.1.1.16 root 6752: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
6753: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 6754:
6755: if(mem[0x462] == REG8(BH)) {
1.1.1.35 root 6756: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6757: EnterCriticalSection(&vram_crit_sect);
1.1.1.35 root 6758: #endif
1.1.1.16 root 6759: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 6760: while(dest < end) {
6761: write_text_vram_char(dest - vram, REG8(AL));
6762: mem[dest++] = REG8(AL);
6763: write_text_vram_attr(dest - vram, REG8(BL));
6764: mem[dest++] = REG8(BL);
1.1 root 6765: }
1.1.1.35 root 6766: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6767: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35 root 6768: #endif
1.1 root 6769: } else {
1.1.1.14 root 6770: while(dest < end) {
1.1 root 6771: mem[dest++] = REG8(AL);
6772: mem[dest++] = REG8(BL);
6773: }
6774: }
6775: }
6776:
6777: inline void pcbios_int_10h_0ah()
6778: {
6779: COORD co;
6780:
1.1.1.14 root 6781: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
6782: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
6783:
1.1.1.16 root 6784: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
6785: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 6786:
6787: if(mem[0x462] == REG8(BH)) {
1.1.1.35 root 6788: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6789: EnterCriticalSection(&vram_crit_sect);
1.1.1.35 root 6790: #endif
1.1.1.16 root 6791: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 6792: while(dest < end) {
6793: write_text_vram_char(dest - vram, REG8(AL));
6794: mem[dest++] = REG8(AL);
6795: dest++;
1.1 root 6796: }
1.1.1.35 root 6797: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6798: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35 root 6799: #endif
1.1 root 6800: } else {
1.1.1.14 root 6801: while(dest < end) {
1.1 root 6802: mem[dest++] = REG8(AL);
6803: dest++;
6804: }
6805: }
6806: }
6807:
1.1.1.40 root 6808: HDC get_console_window_device_context()
6809: {
6810: static HWND hwndFound = 0;
6811:
6812: if(hwndFound == 0) {
6813: // https://support.microsoft.com/en-us/help/124103/how-to-obtain-a-console-window-handle-hwnd
6814: char pszNewWindowTitle[1024];
6815: char pszOldWindowTitle[1024];
6816:
6817: GetConsoleTitle(pszOldWindowTitle, 1024);
6818: wsprintf(pszNewWindowTitle,"%d/%d", GetTickCount(), GetCurrentProcessId());
6819: SetConsoleTitle(pszNewWindowTitle);
6820: Sleep(100);
6821: hwndFound = FindWindow(NULL, pszNewWindowTitle);
6822: SetConsoleTitle(pszOldWindowTitle);
6823: }
6824: return GetDC(hwndFound);
6825: }
6826:
6827: inline void pcbios_int_10h_0ch()
6828: {
6829: HDC hdc = get_console_window_device_context();
6830:
6831: if(hdc != NULL) {
6832: BYTE r = (REG8(AL) & 2) ? 255 : 0;
6833: BYTE g = (REG8(AL) & 4) ? 255 : 0;
6834: BYTE b = (REG8(AL) & 1) ? 255 : 0;
6835:
6836: if(REG8(AL) & 0x80) {
6837: COLORREF color = GetPixel(hdc, REG16(CX), REG16(DX));
6838: if(color != CLR_INVALID) {
6839: r ^= ((DWORD)color & 0x0000ff) ? 255 : 0;
6840: g ^= ((DWORD)color & 0x00ff00) ? 255 : 0;
6841: b ^= ((DWORD)color & 0xff0000) ? 255 : 0;
6842: }
6843: }
6844: SetPixel(hdc, REG16(CX), REG16(DX), RGB(r, g, b));
6845: }
6846: }
6847:
6848: inline void pcbios_int_10h_0dh()
6849: {
6850: HDC hdc = get_console_window_device_context();
6851: BYTE r = 0;
6852: BYTE g = 0;
6853: BYTE b = 0;
6854:
6855: if(hdc != NULL) {
6856: COLORREF color = GetPixel(hdc, REG16(CX), REG16(DX));
6857: if(color != CLR_INVALID) {
6858: r = ((DWORD)color & 0x0000ff) ? 255 : 0;
6859: g = ((DWORD)color & 0x00ff00) ? 255 : 0;
6860: b = ((DWORD)color & 0xff0000) ? 255 : 0;
6861: }
6862: }
6863: REG8(AL) = ((b != 0) ? 1 : 0) | ((r != 0) ? 2 : 0) | ((g != 0) ? 4 : 0);
6864: }
6865:
1.1 root 6866: inline void pcbios_int_10h_0eh()
6867: {
1.1.1.14 root 6868: DWORD num;
6869: COORD co;
6870:
6871: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
6872: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
6873:
6874: if(REG8(AL) == 7) {
6875: //MessageBeep(-1);
6876: } else if(REG8(AL) == 8 || REG8(AL) == 10 || REG8(AL) == 13) {
6877: if(REG8(AL) == 10) {
6878: vram_flush();
6879: }
1.1.1.23 root 6880: WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ®8(AL), 1, &num, NULL);
1.1.1.14 root 6881: cursor_moved = true;
6882: } else {
1.1.1.16 root 6883: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
1.1.1.14 root 6884: if(mem[0x462] == REG8(BH)) {
1.1.1.35 root 6885: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6886: EnterCriticalSection(&vram_crit_sect);
1.1.1.35 root 6887: #endif
1.1.1.16 root 6888: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 6889: write_text_vram_char(dest - vram, REG8(AL));
1.1.1.35 root 6890: #ifdef USE_VRAM_THREAD
1.1.1.14 root 6891: LeaveCriticalSection(&vram_crit_sect);
1.1.1.35 root 6892: #endif
1.1.1.14 root 6893:
1.1.1.23 root 6894: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 6895: if(++co.X == scr_width) {
6896: co.X = 0;
6897: if(++co.Y == scr_height) {
6898: vram_flush();
6899: WriteConsole(hStdout, "\n", 1, &num, NULL);
6900: cursor_moved = true;
6901: }
6902: }
6903: if(!cursor_moved) {
6904: co.Y += scr_top;
6905: SetConsoleCursorPosition(hStdout, co);
6906: cursor_moved = true;
6907: }
6908: }
6909: mem[dest] = REG8(AL);
6910: }
1.1 root 6911: }
6912:
6913: inline void pcbios_int_10h_0fh()
6914: {
6915: REG8(AL) = mem[0x449];
6916: REG8(AH) = mem[0x44a];
6917: REG8(BH) = mem[0x462];
6918: }
6919:
1.1.1.14 root 6920: inline void pcbios_int_10h_11h()
6921: {
6922: switch(REG8(AL)) {
1.1.1.16 root 6923: case 0x01:
1.1.1.14 root 6924: case 0x11:
1.1.1.16 root 6925: pcbios_set_console_size(80, 28, true);
1.1.1.14 root 6926: break;
1.1.1.16 root 6927: case 0x02:
1.1.1.14 root 6928: case 0x12:
1.1.1.16 root 6929: pcbios_set_console_size(80, 50, true);
1.1.1.14 root 6930: break;
1.1.1.16 root 6931: case 0x04:
1.1.1.14 root 6932: case 0x14:
1.1.1.16 root 6933: pcbios_set_console_size(80, 25, true);
6934: break;
6935: case 0x18:
6936: pcbios_set_console_size(80, 50, true);
1.1.1.14 root 6937: break;
6938: case 0x30:
6939: SREG(ES) = 0;
6940: i386_load_segment_descriptor(ES);
6941: REG16(BP) = 0;
6942: REG16(CX) = mem[0x485];
6943: REG8(DL) = mem[0x484];
6944: break;
6945: }
6946: }
6947:
6948: inline void pcbios_int_10h_12h()
6949: {
1.1.1.16 root 6950: switch(REG8(BL)) {
6951: case 0x10:
1.1.1.14 root 6952: REG16(BX) = 0x0003;
6953: REG16(CX) = 0x0009;
1.1.1.16 root 6954: break;
1.1.1.14 root 6955: }
6956: }
6957:
1.1 root 6958: inline void pcbios_int_10h_13h()
6959: {
1.1.1.3 root 6960: int ofs = SREG_BASE(ES) + REG16(BP);
1.1 root 6961: COORD co;
6962: DWORD num;
6963:
6964: co.X = REG8(DL);
1.1.1.14 root 6965: co.Y = REG8(DH) + scr_top;
6966:
6967: vram_flush();
1.1 root 6968:
6969: switch(REG8(AL)) {
6970: case 0x00:
6971: case 0x01:
6972: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 6973: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 6974: CONSOLE_SCREEN_BUFFER_INFO csbi;
6975: GetConsoleScreenBufferInfo(hStdout, &csbi);
6976: SetConsoleCursorPosition(hStdout, co);
6977:
6978: if(csbi.wAttributes != REG8(BL)) {
6979: SetConsoleTextAttribute(hStdout, REG8(BL));
6980: }
1.1.1.14 root 6981: WriteConsole(hStdout, &mem[ofs], REG16(CX), &num, NULL);
6982:
1.1 root 6983: if(csbi.wAttributes != REG8(BL)) {
6984: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
6985: }
6986: if(REG8(AL) == 0x00) {
1.1.1.15 root 6987: if(!restore_console_on_exit) {
6988: GetConsoleScreenBufferInfo(hStdout, &csbi);
6989: scr_top = csbi.srWindow.Top;
6990: }
1.1.1.14 root 6991: co.X = mem[0x450 + REG8(BH) * 2];
6992: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 6993: SetConsoleCursorPosition(hStdout, co);
6994: } else {
6995: cursor_moved = true;
6996: }
6997: } else {
1.1.1.3 root 6998: m_CF = 1;
1.1 root 6999: }
7000: break;
7001: case 0x02:
7002: case 0x03:
7003: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 7004: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 7005: CONSOLE_SCREEN_BUFFER_INFO csbi;
7006: GetConsoleScreenBufferInfo(hStdout, &csbi);
7007: SetConsoleCursorPosition(hStdout, co);
7008:
7009: WORD wAttributes = csbi.wAttributes;
7010: for(int i = 0; i < REG16(CX); i++, ofs += 2) {
7011: if(wAttributes != mem[ofs + 1]) {
7012: SetConsoleTextAttribute(hStdout, mem[ofs + 1]);
7013: wAttributes = mem[ofs + 1];
7014: }
1.1.1.14 root 7015: WriteConsole(hStdout, &mem[ofs], 1, &num, NULL);
1.1 root 7016: }
7017: if(csbi.wAttributes != wAttributes) {
7018: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
7019: }
7020: if(REG8(AL) == 0x02) {
1.1.1.14 root 7021: co.X = mem[0x450 + REG8(BH) * 2];
7022: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 7023: SetConsoleCursorPosition(hStdout, co);
7024: } else {
7025: cursor_moved = true;
7026: }
7027: } else {
1.1.1.3 root 7028: m_CF = 1;
1.1 root 7029: }
7030: break;
7031: case 0x10:
7032: case 0x11:
7033: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 7034: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 7035: ReadConsoleOutputCharacter(hStdout, scr_char, REG16(CX), co, &num);
7036: ReadConsoleOutputAttribute(hStdout, scr_attr, REG16(CX), co, &num);
7037: for(int i = 0; i < num; i++) {
7038: mem[ofs++] = scr_char[i];
7039: mem[ofs++] = scr_attr[i];
7040: if(REG8(AL) == 0x11) {
7041: mem[ofs++] = 0;
7042: mem[ofs++] = 0;
7043: }
7044: }
7045: } else {
1.1.1.16 root 7046: 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 7047: mem[ofs++] = mem[src++];
7048: mem[ofs++] = mem[src++];
7049: if(REG8(AL) == 0x11) {
7050: mem[ofs++] = 0;
7051: mem[ofs++] = 0;
7052: }
1.1.1.14 root 7053: if(++co.X == scr_width) {
7054: if(++co.Y == scr_height) {
1.1 root 7055: break;
7056: }
7057: co.X = 0;
7058: }
7059: }
7060: }
7061: break;
7062: case 0x20:
7063: case 0x21:
7064: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 7065: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 7066: int len = min(REG16(CX), scr_width * scr_height);
7067: for(int i = 0; i < len; i++) {
1.1 root 7068: scr_char[i] = mem[ofs++];
7069: scr_attr[i] = mem[ofs++];
7070: if(REG8(AL) == 0x21) {
7071: ofs += 2;
7072: }
7073: }
1.1.1.14 root 7074: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
7075: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 7076: } else {
1.1.1.16 root 7077: 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 7078: mem[dest++] = mem[ofs++];
7079: mem[dest++] = mem[ofs++];
7080: if(REG8(AL) == 0x21) {
7081: ofs += 2;
7082: }
1.1.1.14 root 7083: if(++co.X == scr_width) {
7084: if(++co.Y == scr_height) {
1.1 root 7085: break;
7086: }
7087: co.X = 0;
7088: }
7089: }
7090: }
7091: break;
7092: default:
1.1.1.22 root 7093: 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 7094: m_CF = 1;
1.1 root 7095: break;
7096: }
7097: }
7098:
1.1.1.30 root 7099: inline void pcbios_int_10h_18h()
7100: {
7101: switch(REG8(AL)) {
7102: case 0x00:
7103: case 0x01:
7104: // REG8(AL) = 0x86;
7105: REG8(AL) = 0x00;
7106: break;
7107: default:
7108: 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));
7109: m_CF = 1;
7110: break;
7111: }
7112: }
7113:
1.1.1.14 root 7114: inline void pcbios_int_10h_1ah()
7115: {
7116: switch(REG8(AL)) {
7117: case 0x00:
7118: REG8(AL) = 0x1a;
7119: REG8(BL) = 0x08;
7120: REG8(BH) = 0x00;
7121: break;
7122: default:
1.1.1.22 root 7123: 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 7124: m_CF = 1;
7125: break;
7126: }
7127: }
7128:
1.1 root 7129: inline void pcbios_int_10h_1dh()
7130: {
7131: switch(REG8(AL)) {
7132: case 0x01:
7133: break;
7134: case 0x02:
7135: REG16(BX) = 0;
7136: break;
7137: default:
1.1.1.22 root 7138: 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));
7139: m_CF = 1;
7140: break;
7141: }
7142: }
7143:
7144: inline void pcbios_int_10h_4fh()
7145: {
7146: switch(REG8(AL)) {
7147: case 0x00:
7148: REG8(AH) = 0x02; // not supported
7149: break;
7150: case 0x01:
7151: case 0x02:
7152: case 0x03:
7153: case 0x04:
7154: case 0x05:
7155: case 0x06:
7156: case 0x07:
7157: case 0x08:
7158: case 0x09:
7159: case 0x0a:
7160: case 0x0b:
7161: case 0x0c:
7162: REG8(AH) = 0x01; // failed
7163: break;
7164: default:
7165: 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 7166: m_CF = 1;
1.1 root 7167: break;
7168: }
7169: }
7170:
7171: inline void pcbios_int_10h_82h()
7172: {
7173: static UINT8 mode = 0;
7174:
7175: switch(REG8(AL)) {
1.1.1.22 root 7176: case 0x00:
1.1 root 7177: if(REG8(BL) != 0xff) {
7178: mode = REG8(BL);
7179: }
7180: REG8(AL) = mode;
7181: break;
7182: default:
1.1.1.22 root 7183: 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 7184: m_CF = 1;
1.1 root 7185: break;
7186: }
7187: }
7188:
1.1.1.22 root 7189: inline void pcbios_int_10h_83h()
7190: {
7191: static UINT8 mode = 0;
7192:
7193: switch(REG8(AL)) {
7194: case 0x00:
7195: REG16(AX) = 0; // offset???
7196: SREG(ES) = (SHADOW_BUF_TOP >> 4);
7197: i386_load_segment_descriptor(ES);
7198: REG16(BX) = (SHADOW_BUF_TOP & 0x0f);
7199: break;
7200: default:
7201: 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));
7202: m_CF = 1;
7203: break;
7204: }
7205: }
7206:
7207: inline void pcbios_int_10h_90h()
7208: {
7209: REG8(AL) = mem[0x449];
7210: }
7211:
7212: inline void pcbios_int_10h_91h()
7213: {
7214: REG8(AL) = 0x04; // VGA
7215: }
7216:
7217: inline void pcbios_int_10h_efh()
7218: {
7219: REG16(DX) = 0xffff;
7220: }
7221:
1.1 root 7222: inline void pcbios_int_10h_feh()
7223: {
7224: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 7225: SREG(ES) = (SHADOW_BUF_TOP >> 4);
1.1.1.3 root 7226: i386_load_segment_descriptor(ES);
1.1.1.8 root 7227: REG16(DI) = (SHADOW_BUF_TOP & 0x0f);
1.1 root 7228: }
7229: int_10h_feh_called = true;
7230: }
7231:
7232: inline void pcbios_int_10h_ffh()
7233: {
7234: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.23 root 7235: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 7236: COORD co;
7237: DWORD num;
7238:
1.1.1.14 root 7239: vram_flush();
7240:
7241: co.X = (REG16(DI) >> 1) % scr_width;
7242: co.Y = (REG16(DI) >> 1) / scr_width;
1.1.1.16 root 7243: int ofs = pcbios_get_shadow_buffer_address(0, co.X, co.Y);
7244: int end = min(ofs + REG16(CX) * 2, pcbios_get_shadow_buffer_address(0, 0, scr_height));
1.1.1.14 root 7245: int len;
7246: for(len = 0; ofs < end; len++) {
7247: scr_char[len] = mem[ofs++];
7248: scr_attr[len] = mem[ofs++];
7249: }
7250: co.Y += scr_top;
7251: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
7252: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 7253: }
7254: int_10h_ffh_called = true;
7255: }
7256:
1.1.1.25 root 7257: inline void pcbios_int_14h_00h()
7258: {
1.1.1.29 root 7259: if(REG16(DX) < 4) {
1.1.1.25 root 7260: static const unsigned int rate[] = {110, 150, 300, 600, 1200, 2400, 4800, 9600};
7261: UINT8 selector = sio_read(REG16(DX), 3);
7262: selector &= ~0x3f;
7263: selector |= REG8(AL) & 0x1f;
7264: UINT16 divisor = 115200 / rate[REG8(AL) >> 5];
7265: sio_write(REG16(DX), 3, selector | 0x80);
7266: sio_write(REG16(DX), 0, divisor & 0xff);
7267: sio_write(REG16(DX), 1, divisor >> 8);
7268: sio_write(REG16(DX), 3, selector);
7269: REG8(AH) = sio_read(REG16(DX), 5);
7270: REG8(AL) = sio_read(REG16(DX), 6);
7271: } else {
7272: REG8(AH) = 0x80;
7273: }
7274: }
7275:
7276: inline void pcbios_int_14h_01h()
7277: {
1.1.1.29 root 7278: if(REG16(DX) < 4) {
1.1.1.25 root 7279: UINT8 selector = sio_read(REG16(DX), 3);
7280: sio_write(REG16(DX), 3, selector & ~0x80);
7281: sio_write(REG16(DX), 0, REG8(AL));
7282: sio_write(REG16(DX), 3, selector);
7283: REG8(AH) = sio_read(REG16(DX), 5);
7284: } else {
7285: REG8(AH) = 0x80;
7286: }
7287: }
7288:
7289: inline void pcbios_int_14h_02h()
7290: {
1.1.1.29 root 7291: if(REG16(DX) < 4) {
1.1.1.25 root 7292: UINT8 selector = sio_read(REG16(DX), 3);
7293: sio_write(REG16(DX), 3, selector & ~0x80);
7294: REG8(AL) = sio_read(REG16(DX), 0);
7295: sio_write(REG16(DX), 3, selector);
7296: REG8(AH) = sio_read(REG16(DX), 5);
7297: } else {
7298: REG8(AH) = 0x80;
7299: }
7300: }
7301:
7302: inline void pcbios_int_14h_03h()
7303: {
1.1.1.29 root 7304: if(REG16(DX) < 4) {
1.1.1.25 root 7305: REG8(AH) = sio_read(REG16(DX), 5);
7306: REG8(AL) = sio_read(REG16(DX), 6);
7307: } else {
7308: REG8(AH) = 0x80;
7309: }
7310: }
7311:
7312: inline void pcbios_int_14h_04h()
7313: {
1.1.1.29 root 7314: if(REG16(DX) < 4) {
1.1.1.25 root 7315: UINT8 selector = sio_read(REG16(DX), 3);
7316: if(REG8(CH) <= 0x03) {
7317: selector = (selector & ~0x03) | REG8(CH);
7318: }
7319: if(REG8(BL) == 0x00) {
7320: selector &= ~0x04;
7321: } else if(REG8(BL) == 0x01) {
7322: selector |= 0x04;
7323: }
7324: if(REG8(BH) == 0x00) {
7325: selector = (selector & ~0x38) | 0x00;
7326: } else if(REG8(BH) == 0x01) {
7327: selector = (selector & ~0x38) | 0x08;
7328: } else if(REG8(BH) == 0x02) {
7329: selector = (selector & ~0x38) | 0x18;
7330: } else if(REG8(BH) == 0x03) {
7331: selector = (selector & ~0x38) | 0x28;
7332: } else if(REG8(BH) == 0x04) {
7333: selector = (selector & ~0x38) | 0x38;
7334: }
7335: if(REG8(AL) == 0x00) {
7336: selector |= 0x40;
7337: } else if(REG8(AL) == 0x01) {
7338: selector &= ~0x40;
7339: }
7340: if(REG8(CL) <= 0x0b) {
7341: static const unsigned int rate[] = {110, 150, 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200};
7342: UINT16 divisor = 115200 / rate[REG8(CL)];
7343: sio_write(REG16(DX), 3, selector | 0x80);
7344: sio_write(REG16(DX), 0, divisor & 0xff);
7345: sio_write(REG16(DX), 1, divisor >> 8);
7346: }
7347: sio_write(REG16(DX), 3, selector);
7348: REG8(AH) = sio_read(REG16(DX), 5);
7349: REG8(AL) = sio_read(REG16(DX), 6);
7350: } else {
7351: REG8(AH) = 0x80;
7352: }
7353: }
7354:
7355: inline void pcbios_int_14h_05h()
7356: {
1.1.1.29 root 7357: if(REG16(DX) < 4) {
1.1.1.25 root 7358: if(REG8(AL) == 0x00) {
7359: REG8(BL) = sio_read(REG16(DX), 4);
7360: REG8(AH) = sio_read(REG16(DX), 5);
7361: REG8(AL) = sio_read(REG16(DX), 6);
7362: } else if(REG8(AL) == 0x01) {
7363: sio_write(REG16(DX), 4, REG8(BL));
7364: REG8(AH) = sio_read(REG16(DX), 5);
7365: REG8(AL) = sio_read(REG16(DX), 6);
7366: } else {
7367: 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));
7368: }
7369: } else {
7370: REG8(AH) = 0x80;
7371: }
7372: }
7373:
1.1.1.14 root 7374: inline void pcbios_int_15h_10h()
7375: {
1.1.1.22 root 7376: switch(REG8(AL)) {
7377: case 0x00:
1.1.1.14 root 7378: Sleep(10);
1.1.1.35 root 7379: REQUEST_HARDWRE_UPDATE();
1.1.1.22 root 7380: break;
7381: default:
7382: 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 7383: REG8(AH) = 0x86;
7384: m_CF = 1;
7385: }
7386: }
7387:
1.1 root 7388: inline void pcbios_int_15h_23h()
7389: {
7390: switch(REG8(AL)) {
1.1.1.22 root 7391: case 0x00:
1.1.1.8 root 7392: REG8(CL) = cmos_read(0x2d);
7393: REG8(CH) = cmos_read(0x2e);
1.1 root 7394: break;
1.1.1.22 root 7395: case 0x01:
1.1.1.8 root 7396: cmos_write(0x2d, REG8(CL));
7397: cmos_write(0x2e, REG8(CH));
1.1 root 7398: break;
7399: default:
1.1.1.22 root 7400: 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 7401: REG8(AH) = 0x86;
1.1.1.3 root 7402: m_CF = 1;
1.1 root 7403: break;
7404: }
7405: }
7406:
7407: inline void pcbios_int_15h_24h()
7408: {
7409: switch(REG8(AL)) {
1.1.1.22 root 7410: case 0x00:
1.1.1.3 root 7411: i386_set_a20_line(0);
1.1 root 7412: REG8(AH) = 0;
7413: break;
1.1.1.22 root 7414: case 0x01:
1.1.1.3 root 7415: i386_set_a20_line(1);
1.1 root 7416: REG8(AH) = 0;
7417: break;
1.1.1.22 root 7418: case 0x02:
1.1 root 7419: REG8(AH) = 0;
1.1.1.3 root 7420: REG8(AL) = (m_a20_mask >> 20) & 1;
1.1 root 7421: REG16(CX) = 0;
7422: break;
1.1.1.22 root 7423: case 0x03:
1.1 root 7424: REG16(AX) = 0;
7425: REG16(BX) = 0;
7426: break;
1.1.1.22 root 7427: default:
7428: 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));
7429: REG8(AH) = 0x86;
7430: m_CF = 1;
7431: break;
1.1 root 7432: }
7433: }
7434:
7435: inline void pcbios_int_15h_49h()
7436: {
1.1.1.27 root 7437: REG8(AH) = 0x00;
7438: REG8(BL) = 0x00; // DOS/V
1.1 root 7439: }
7440:
1.1.1.22 root 7441: inline void pcbios_int_15h_50h()
7442: {
7443: switch(REG8(AL)) {
7444: case 0x00:
7445: case 0x01:
7446: if(REG8(BH) != 0x00 && REG8(BH) != 0x01) {
7447: REG8(AH) = 0x01; // invalid font type in bh
7448: m_CF = 1;
1.1.1.27 root 7449: } else if(REG8(BL) != 0x00) {
1.1.1.22 root 7450: REG8(AH) = 0x02; // bl not zero
7451: m_CF = 1;
7452: } else if(REG16(BP) != 0 && REG16(BP) != 437 && REG16(BP) != 932 && REG16(BP) != 934 && REG16(BP) != 936 && REG16(BP) != 938) {
7453: REG8(AH) = 0x04; // invalid code page
7454: m_CF = 1;
1.1.1.27 root 7455: } else if(REG8(AL) == 0x01) {
7456: REG8(AH) = 0x06; // font is read only
1.1.1.22 root 7457: m_CF = 1;
1.1.1.27 root 7458: } else {
7459: // dummy font read routine is at fffd:000d
7460: SREG(ES) = 0xfffd;
7461: i386_load_segment_descriptor(ES);
1.1.1.32 root 7462: REG16(BX) = 0x000d;
1.1.1.27 root 7463: REG8(AH) = 0x00; // success
1.1.1.22 root 7464: }
7465: break;
7466: default:
7467: 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));
7468: REG8(AH) = 0x86;
7469: m_CF = 1;
7470: break;
7471: }
7472: }
7473:
1.1.1.30 root 7474: inline void pcbios_int_15h_53h()
7475: {
7476: switch(REG8(AL)) {
7477: case 0x00:
7478: // APM is not installed
7479: REG8(AH) = 0x86;
7480: m_CF = 1;
7481: break;
7482: default:
7483: 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));
7484: REG8(AH) = 0x86;
7485: m_CF = 1;
7486: break;
7487: }
7488: }
7489:
1.1.1.35 root 7490:
7491: DWORD WINAPI pcbios_int_15h_86h_thread(LPVOID)
1.1 root 7492: {
7493: UINT32 usec = (REG16(CX) << 16) | REG16(DX);
1.1.1.14 root 7494: UINT32 msec = usec / 1000;
7495:
1.1.1.35 root 7496: while(msec && !m_halted) {
1.1.1.14 root 7497: UINT32 tmp = min(msec, 100);
7498: if(msec - tmp < 10) {
7499: tmp = msec;
7500: }
7501: Sleep(tmp);
7502: msec -= tmp;
7503: }
1.1.1.35 root 7504:
7505: #ifdef USE_SERVICE_THREAD
7506: service_exit = true;
7507: #endif
7508: return(0);
7509: }
7510:
7511: inline void pcbios_int_15h_86h()
7512: {
7513: if(!(REG16(CX) == 0 && REG16(DX) == 0)) {
7514: #ifdef USE_SERVICE_THREAD
7515: start_service_loop(pcbios_int_15h_86h_thread);
7516: #else
7517: pcbios_int_15h_86h_thread(NULL);
7518: REQUEST_HARDWRE_UPDATE();
7519: #endif
7520: }
1.1 root 7521: }
7522:
7523: inline void pcbios_int_15h_87h()
7524: {
7525: // copy extended memory (from DOSBox)
7526: int len = REG16(CX) * 2;
1.1.1.3 root 7527: int ofs = SREG_BASE(ES) + REG16(SI);
1.1 root 7528: int src = (*(UINT32 *)(mem + ofs + 0x12) & 0xffffff); // + (mem[ofs + 0x16] << 24);
7529: int dst = (*(UINT32 *)(mem + ofs + 0x1a) & 0xffffff); // + (mem[ofs + 0x1e] << 24);
7530: memcpy(mem + dst, mem + src, len);
7531: REG16(AX) = 0x00;
7532: }
7533:
7534: inline void pcbios_int_15h_88h()
7535: {
1.1.1.17 root 7536: REG16(AX) = ((min(MAX_MEM, 0x4000000) - 0x100000) >> 10);
1.1 root 7537: }
7538:
7539: inline void pcbios_int_15h_89h()
7540: {
1.1.1.21 root 7541: #if defined(HAS_I286) || defined(HAS_I386)
1.1 root 7542: // switch to protected mode (from DOSBox)
7543: write_io_byte(0x20, 0x10);
7544: write_io_byte(0x21, REG8(BH));
7545: write_io_byte(0x21, 0x00);
7546: write_io_byte(0xa0, 0x10);
7547: write_io_byte(0xa1, REG8(BL));
7548: write_io_byte(0xa1, 0x00);
1.1.1.3 root 7549: i386_set_a20_line(1);
7550: int ofs = SREG_BASE(ES) + REG16(SI);
7551: m_gdtr.limit = *(UINT16 *)(mem + ofs + 0x08);
7552: m_gdtr.base = *(UINT32 *)(mem + ofs + 0x08 + 0x02) & 0xffffff;
7553: m_idtr.limit = *(UINT16 *)(mem + ofs + 0x10);
7554: m_idtr.base = *(UINT32 *)(mem + ofs + 0x10 + 0x02) & 0xffffff;
7555: #if defined(HAS_I386)
7556: m_cr[0] |= 1;
7557: #else
7558: m_msw |= 1;
7559: #endif
7560: SREG(DS) = 0x18;
7561: SREG(ES) = 0x20;
7562: SREG(SS) = 0x28;
7563: i386_load_segment_descriptor(DS);
7564: i386_load_segment_descriptor(ES);
7565: i386_load_segment_descriptor(SS);
1.1.1.21 root 7566: UINT16 offset = *(UINT16 *)(mem + SREG_BASE(SS) + REG16(SP));
1.1 root 7567: REG16(SP) += 6;
1.1.1.3 root 7568: #if defined(HAS_I386)
1.1.1.21 root 7569: UINT32 flags = get_flags();
7570: flags &= (0x20000 | 0x40000 | 0x80000 | 0x100000 | 0x200000);
7571: set_flags(flags);
1.1.1.3 root 7572: #else
1.1.1.21 root 7573: UINT32 flags = CompressFlags();
7574: flags &= (0x20000 | 0x40000 | 0x80000 | 0x100000 | 0x200000);
7575: ExpandFlags(flags);
1.1.1.3 root 7576: #endif
1.1 root 7577: REG16(AX) = 0x00;
1.1.1.21 root 7578: i386_jmp_far(0x30, /*REG16(CX)*/offset);
1.1 root 7579: #else
1.1.1.21 root 7580: // i86/i186/v30: protected mode is not supported
1.1 root 7581: REG8(AH) = 0x86;
1.1.1.3 root 7582: m_CF = 1;
1.1 root 7583: #endif
7584: }
7585:
1.1.1.21 root 7586: inline void pcbios_int_15h_8ah()
7587: {
7588: UINT32 size = MAX_MEM - 0x100000;
7589: REG16(AX) = size & 0xffff;
7590: REG16(DX) = size >> 16;
7591: }
7592:
1.1.1.3 root 7593: #if defined(HAS_I386)
1.1 root 7594: inline void pcbios_int_15h_c9h()
7595: {
7596: REG8(AH) = 0x00;
7597: REG8(CH) = cpu_type;
7598: REG8(CL) = cpu_step;
7599: }
1.1.1.3 root 7600: #endif
1.1 root 7601:
7602: inline void pcbios_int_15h_cah()
7603: {
7604: switch(REG8(AL)) {
1.1.1.22 root 7605: case 0x00:
1.1 root 7606: if(REG8(BL) > 0x3f) {
7607: REG8(AH) = 0x03;
1.1.1.3 root 7608: m_CF = 1;
1.1 root 7609: } else if(REG8(BL) < 0x0e) {
7610: REG8(AH) = 0x04;
1.1.1.3 root 7611: m_CF = 1;
1.1 root 7612: } else {
1.1.1.8 root 7613: REG8(CL) = cmos_read(REG8(BL));
1.1 root 7614: }
7615: break;
1.1.1.22 root 7616: case 0x01:
1.1 root 7617: if(REG8(BL) > 0x3f) {
7618: REG8(AH) = 0x03;
1.1.1.3 root 7619: m_CF = 1;
1.1 root 7620: } else if(REG8(BL) < 0x0e) {
7621: REG8(AH) = 0x04;
1.1.1.3 root 7622: m_CF = 1;
1.1 root 7623: } else {
1.1.1.8 root 7624: cmos_write(REG8(BL), REG8(CL));
1.1 root 7625: }
7626: break;
7627: default:
1.1.1.22 root 7628: 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 7629: REG8(AH) = 0x86;
1.1.1.3 root 7630: m_CF = 1;
1.1 root 7631: break;
7632: }
7633: }
7634:
1.1.1.22 root 7635: inline void pcbios_int_15h_e8h()
1.1.1.17 root 7636: {
1.1.1.22 root 7637: switch(REG8(AL)) {
7638: #if defined(HAS_I386)
7639: case 0x01:
7640: REG16(AX) = REG16(CX) = ((min(MAX_MEM, 0x1000000) - 0x100000) >> 10);
7641: REG16(BX) = REG16(DX) = ((max(MAX_MEM, 0x1000000) - 0x1000000) >> 16);
7642: break;
1.1.1.17 root 7643: #endif
1.1.1.22 root 7644: default:
7645: 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));
7646: REG8(AH) = 0x86;
7647: m_CF = 1;
7648: break;
7649: }
7650: }
1.1.1.17 root 7651:
1.1.1.33 root 7652: void pcbios_update_key_code(bool wait)
1.1 root 7653: {
1.1.1.32 root 7654: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 7655: #ifdef USE_SERVICE_THREAD
7656: EnterCriticalSection(&key_buf_crit_sect);
7657: #endif
7658: bool empty = key_buf_char->empty();
7659: #ifdef USE_SERVICE_THREAD
7660: LeaveCriticalSection(&key_buf_crit_sect);
7661: #endif
7662: if(empty) {
1.1.1.32 root 7663: if(!update_key_buffer()) {
1.1.1.33 root 7664: if(wait) {
1.1.1.32 root 7665: Sleep(10);
7666: } else {
7667: maybe_idle();
7668: }
1.1.1.14 root 7669: }
7670: }
1.1.1.34 root 7671: }
7672: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 7673: #ifdef USE_SERVICE_THREAD
7674: EnterCriticalSection(&key_buf_crit_sect);
7675: #endif
1.1.1.32 root 7676: if(key_buf_char->count() != 0) {
1.1.1.41! root 7677: int key_char = key_buf_char->read();
! 7678: int key_scan = key_buf_scan->read();
! 7679: key_code = key_char << 0;
! 7680: key_code |= key_scan << 8;
1.1.1.35 root 7681: key_recv = 0x0000ffff;
1.1.1.41! root 7682: // write to bottom of key buffer
! 7683: mem[0x43c] = (UINT8)key_char;
! 7684: mem[0x43d] = (UINT8)key_scan;
1.1.1.32 root 7685: }
7686: if(key_buf_char->count() != 0) {
1.1.1.41! root 7687: int key_char = key_buf_char->read();
! 7688: int key_scan = key_buf_scan->read();
! 7689: key_code |= key_char << 16;
! 7690: key_code |= key_scan << 24;
1.1.1.33 root 7691: key_recv |= 0xffff0000;
1.1.1.41! root 7692: // write to bottom of key buffer
! 7693: mem[0x43c] = (UINT8)key_char;
! 7694: mem[0x43d] = (UINT8)key_scan;
1.1.1.32 root 7695: }
1.1.1.35 root 7696: #ifdef USE_SERVICE_THREAD
7697: LeaveCriticalSection(&key_buf_crit_sect);
7698: #endif
1.1 root 7699: }
7700: }
7701:
1.1.1.35 root 7702: DWORD WINAPI pcbios_int_16h_00h_thread(LPVOID)
1.1 root 7703: {
1.1.1.33 root 7704: while(key_recv == 0 && !m_halted) {
7705: pcbios_update_key_code(true);
1.1 root 7706: }
1.1.1.33 root 7707: if((key_recv & 0x0000ffff) && (key_recv & 0xffff0000)) {
7708: if((key_code & 0xffff) == 0x0000 || (key_code & 0xffff) == 0xe000) {
7709: if(REG8(AH) == 0x10) {
7710: key_code = ((key_code >> 8) & 0xff) | ((key_code >> 16) & 0xff00);
7711: } else {
7712: key_code = ((key_code >> 16) & 0xff00);
7713: }
7714: key_recv >>= 16;
1.1 root 7715: }
7716: }
7717: REG16(AX) = key_code & 0xffff;
7718: key_code >>= 16;
1.1.1.33 root 7719: key_recv >>= 16;
1.1.1.35 root 7720:
7721: #ifdef USE_SERVICE_THREAD
7722: service_exit = true;
7723: #endif
7724: return(0);
7725: }
7726:
7727: inline void pcbios_int_16h_00h()
7728: {
7729: #ifdef USE_SERVICE_THREAD
7730: start_service_loop(pcbios_int_16h_00h_thread);
7731: #else
7732: pcbios_int_16h_00h_thread(NULL);
7733: REQUEST_HARDWRE_UPDATE();
7734: #endif
1.1 root 7735: }
7736:
7737: inline void pcbios_int_16h_01h()
7738: {
1.1.1.33 root 7739: if(key_recv == 0) {
7740: pcbios_update_key_code(false);
1.1.1.5 root 7741: }
1.1.1.33 root 7742: if(key_recv != 0) {
7743: UINT32 key_code_tmp = key_code;
7744: if((key_recv & 0x0000ffff) && (key_recv & 0xffff0000)) {
7745: if((key_code_tmp & 0xffff) == 0x0000 || (key_code_tmp & 0xffff) == 0xe000) {
7746: if(REG8(AH) == 0x11) {
7747: key_code_tmp = ((key_code_tmp >> 8) & 0xff) | ((key_code_tmp >> 16) & 0xff00);
7748: } else {
7749: key_code_tmp = ((key_code_tmp >> 16) & 0xff00);
7750: }
7751: }
1.1 root 7752: }
1.1.1.5 root 7753: REG16(AX) = key_code_tmp & 0xffff;
1.1.1.3 root 7754: #if defined(HAS_I386)
1.1.1.33 root 7755: m_ZF = 0;
7756: #else
7757: m_ZeroVal = 1;
7758: #endif
7759: } else {
7760: #if defined(HAS_I386)
7761: m_ZF = 1;
1.1.1.3 root 7762: #else
1.1.1.33 root 7763: m_ZeroVal = 0;
1.1.1.3 root 7764: #endif
1.1.1.33 root 7765: }
1.1 root 7766: }
7767:
7768: inline void pcbios_int_16h_02h()
7769: {
7770: REG8(AL) = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
7771: REG8(AL) |= (GetAsyncKeyState(VK_CAPITAL) & 0x0001) ? 0x40 : 0;
7772: REG8(AL) |= (GetAsyncKeyState(VK_NUMLOCK) & 0x0001) ? 0x20 : 0;
7773: REG8(AL) |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
7774: REG8(AL) |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
7775: REG8(AL) |= (GetAsyncKeyState(VK_CONTROL) & 0x8000) ? 0x04 : 0;
7776: REG8(AL) |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
7777: REG8(AL) |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
7778: }
7779:
7780: inline void pcbios_int_16h_03h()
7781: {
7782: static UINT16 status = 0;
7783:
7784: switch(REG8(AL)) {
7785: case 0x05:
7786: status = REG16(BX);
7787: break;
7788: case 0x06:
7789: REG16(BX) = status;
7790: break;
7791: default:
1.1.1.3 root 7792: m_CF = 1;
1.1 root 7793: break;
7794: }
7795: }
7796:
7797: inline void pcbios_int_16h_05h()
7798: {
1.1.1.32 root 7799: if(key_buf_char != NULL && key_buf_scan != NULL) {
1.1.1.35 root 7800: #ifdef USE_SERVICE_THREAD
7801: EnterCriticalSection(&key_buf_crit_sect);
7802: #endif
1.1.1.32 root 7803: key_buf_char->write(REG8(CL));
7804: key_buf_scan->write(REG8(CH));
1.1.1.35 root 7805: #ifdef USE_SERVICE_THREAD
7806: LeaveCriticalSection(&key_buf_crit_sect);
7807: #endif
1.1.1.32 root 7808: }
1.1 root 7809: REG8(AL) = 0x00;
7810: }
7811:
7812: inline void pcbios_int_16h_12h()
7813: {
7814: pcbios_int_16h_02h();
7815:
7816: REG8(AH) = 0;//(GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x80 : 0;
7817: REG8(AH) |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
7818: REG8(AH) |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
7819: REG8(AH) |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
7820: REG8(AH) |= (GetAsyncKeyState(VK_RMENU ) & 0x8000) ? 0x08 : 0;
7821: REG8(AH) |= (GetAsyncKeyState(VK_RCONTROL) & 0x8000) ? 0x04 : 0;
7822: REG8(AH) |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
7823: REG8(AH) |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
7824: }
7825:
7826: inline void pcbios_int_16h_13h()
7827: {
7828: static UINT16 status = 0;
7829:
7830: switch(REG8(AL)) {
7831: case 0x00:
7832: status = REG16(DX);
7833: break;
7834: case 0x01:
7835: REG16(DX) = status;
7836: break;
7837: default:
1.1.1.22 root 7838: 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 7839: m_CF = 1;
1.1 root 7840: break;
7841: }
7842: }
7843:
7844: inline void pcbios_int_16h_14h()
7845: {
7846: static UINT8 status = 0;
7847:
7848: switch(REG8(AL)) {
7849: case 0x00:
7850: case 0x01:
7851: status = REG8(AL);
7852: break;
7853: case 0x02:
7854: REG8(AL) = status;
7855: break;
7856: default:
1.1.1.22 root 7857: 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 7858: m_CF = 1;
1.1 root 7859: break;
7860: }
7861: }
7862:
1.1.1.24 root 7863: inline void pcbios_int_16h_55h()
7864: {
7865: switch(REG8(AL)) {
7866: case 0x00:
7867: // keyboard tsr is not present
7868: break;
7869: case 0xfe:
7870: // handlers for INT 08, INT 09, INT 16, INT 1B, and INT 1C are installed
7871: break;
7872: case 0xff:
7873: break;
7874: default:
7875: 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));
7876: m_CF = 1;
7877: break;
7878: }
7879: }
7880:
1.1.1.30 root 7881: inline void pcbios_int_16h_6fh()
7882: {
7883: switch(REG8(AL)) {
7884: case 0x00:
7885: // HP Vectra EX-BIOS - "F16_INQUIRE" - Extended BIOS is not installed
7886: break;
7887: default:
7888: 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));
7889: m_CF = 1;
7890: break;
7891: }
7892: }
7893:
1.1.1.37 root 7894: UINT16 pcbios_printer_jis2sjis(UINT16 jis)
7895: {
7896: UINT8 hi = jis >> 8;
7897: UINT8 lo = jis & 0xff;
7898:
7899: lo = (hi & 0x01) ? lo - 0x1f : lo + 0x7d;
7900: hi = (hi - 0x21) / 2 + 0x81;
7901: hi = (hi >= 0xa0) ? hi + 0x40 : hi;
7902: lo = (lo >= 0x7f) ? lo + 0x01 : lo;
7903:
7904: return((hi << 8) + lo);
7905: }
7906:
7907: UINT16 pcbios_printer_sjis2jis(UINT16 sjis)
7908: {
7909: UINT8 hi = sjis >> 8;
7910: UINT8 lo = sjis & 0xff;
7911:
7912: if(hi == 0x80 || (hi >= 0xeb && hi <= 0xef) || (hi >= 0xf4 && hi <= 0xff)) {
7913: return(0x2121);
7914: }
7915: if((lo >= 0x00 && lo <= 0x3f) || lo == 0x7f || (lo >= 0xfd && lo <= 0xff)) {
7916: return(0x2121);
7917: }
7918: if(hi >= 0xf0 && hi <= 0xf3) {
7919: // gaiji
7920: if(lo >= 0x40 && lo <= 0x7e) {
7921: return(0x7721 + lo - 0x40 + (hi - 0xf0) * 0x200);
7922: }
7923: if(lo >= 0x80 && lo <= 0x9e) {
7924: return(0x7760 + lo - 0x80 + (hi - 0xf0) * 0x200);
7925: }
7926: if(lo >= 0x9f && lo <= 0xfc) {
7927: return(0x7821 + lo - 0x9f + (hi - 0xf0) * 0x200);
7928: }
7929: }
7930: hi = (hi >= 0xe0) ? hi - 0x40 : hi;
7931: lo = (lo >= 0x80) ? lo - 0x01 : lo;
7932: hi = ((lo >= 0x9e) ? 1 : 0) + (hi - 0x81) * 2 + 0x21;
7933: lo = ((lo >= 0x9e) ? lo - 0x9e : lo - 0x40) + 0x21;
7934:
7935: return((hi << 8) + lo);
7936: }
7937:
1.1.1.38 root 7938: // AX�e�N�j�J�����t�@�����X�K�C�h 1989
7939: // �t�^10 ���{��g��PRINTER DRIVER NIOS�T�d�l
7940: // 6. �R���g���[���R�[�h�̉��
1.1.1.37 root 7941:
7942: void pcbios_printer_out(int c, UINT8 data)
7943: {
7944: if(pio[c].conv_mode) {
7945: if(pio[c].sjis_hi != 0) {
7946: if(!pio[c].jis_mode) {
7947: printer_out(c, 0x1c);
7948: printer_out(c, 0x26);
7949: pio[c].jis_mode = true;
7950: }
7951: UINT16 jis = pcbios_printer_sjis2jis((pio[c].sjis_hi << 8) | data);
7952: printer_out(c, jis >> 8);
7953: printer_out(c, jis & 0xff);
7954: pio[c].sjis_hi = 0;
7955: } else if(pio[c].esc_buf[0] == 0x1b) {
7956: printer_out(c, data);
7957: if(pio[c].esc_len < sizeof(pio[c].esc_buf)) {
7958: pio[c].esc_buf[pio[c].esc_len] = data;
7959: }
7960: pio[c].esc_len++;
7961:
7962: switch(pio[c].esc_buf[1]) {
1.1.1.38 root 7963: case 0x33: // 1Bh 33h XX
7964: case 0x4a: // 1Bh 4Ah XX
7965: case 0x4e: // 1Bh 4Eh XX
7966: case 0x51: // 1Bh 51h XX
7967: case 0x55: // 1Bh 55h XX
7968: case 0x6c: // 1Bh 6Ch XX
7969: case 0x71: // 1Bh 71h XX
7970: case 0x72: // 1Bh 72h XX
1.1.1.37 root 7971: if(pio[c].esc_len == 3) {
7972: pio[c].esc_buf[0] = 0x00;
7973: }
7974: break;
1.1.1.38 root 7975: case 0x24: // 1Bh 24h XX XX
7976: case 0x5c: // 1Bh 5Ch XX XX
1.1.1.37 root 7977: if(pio[c].esc_len == 4) {
7978: pio[c].esc_buf[0] = 0x00;
7979: }
7980: break;
1.1.1.38 root 7981: case 0x2a: // 1Bh 2Ah XX XX XX data
1.1.1.37 root 7982: if(pio[c].esc_len >= 3) {
7983: switch(pio[c].esc_buf[2]) {
7984: case 0: case 1: case 2: case 3: case 4: case 6:
7985: if(pio[c].esc_len >= 5 && pio[c].esc_len == 5 + (pio[c].esc_buf[3] + pio[c].esc_buf[4] * 256) * 1) {
7986: pio[c].esc_buf[0] = 0x00;
7987: }
7988: break;
7989: case 32: case 33: case 38: case 39: case 40:
7990: if(pio[c].esc_len >= 5 && pio[c].esc_len == 5 + (pio[c].esc_buf[3] + pio[c].esc_buf[4] * 256) * 3) {
7991: pio[c].esc_buf[0] = 0x00;
7992: }
7993: break;
1.1.1.38 root 7994: case 71: case 72: case 73:
7995: if(pio[c].esc_len >= 5 && pio[c].esc_len == 5 + (pio[c].esc_buf[3] + pio[c].esc_buf[4] * 256) * 6) {
7996: pio[c].esc_buf[0] = 0x00;
7997: }
7998: break;
1.1.1.37 root 7999: default:
8000: pio[c].esc_buf[0] = 0x00;
8001: break;
8002: }
8003: }
8004: break;
1.1.1.38 root 8005: case 0x40: // 1Bh 40h
1.1.1.37 root 8006: if(pio[c].jis_mode) {
8007: printer_out(c, 0x1c);
8008: printer_out(c, 0x2e);
8009: pio[c].jis_mode = false;
8010: }
8011: pio[c].esc_buf[0] = 0x00;
8012: break;
1.1.1.38 root 8013: case 0x42: // 1Bh 42h data 00h
8014: case 0x44: // 1Bh 44h data 00h
1.1.1.37 root 8015: if(pio[c].esc_len >= 3 && data == 0) {
8016: pio[c].esc_buf[0] = 0x00;
8017: }
8018: break;
1.1.1.38 root 8019: case 0x43: // 1Bh 43h (00h) XX
1.1.1.37 root 8020: if(pio[c].esc_len >= 3 && data != 0) {
8021: pio[c].esc_buf[0] = 0x00;
8022: }
8023: break;
1.1.1.38 root 8024: default: // 1Bh XX
1.1.1.37 root 8025: pio[c].esc_buf[0] = 0x00;
8026: break;
8027: }
8028: } else if(pio[c].esc_buf[0] == 0x1c) {
8029: printer_out(c, data);
8030: if(pio[c].esc_len < sizeof(pio[c].esc_buf)) {
8031: pio[c].esc_buf[pio[c].esc_len] = data;
8032: }
8033: pio[c].esc_len++;
8034:
8035: switch(pio[c].esc_buf[1]) {
1.1.1.38 root 8036: case 0x21: // 1Ch 21h XX
8037: case 0x2d: // 1Ch 2Dh XX
8038: case 0x57: // 1Ch 57h XX
8039: case 0x6b: // 1Ch 6Bh XX
8040: case 0x72: // 1Ch 72h XX
8041: case 0x78: // 1Ch 78h XX
1.1.1.37 root 8042: if(pio[c].esc_len == 3) {
8043: pio[c].esc_buf[0] = 0x00;
8044: }
8045: break;
1.1.1.38 root 8046: case 0x26: // 1Ch 26h
1.1.1.37 root 8047: pio[c].jis_mode = true;
8048: pio[c].esc_buf[0] = 0x00;
8049: break;
1.1.1.38 root 8050: case 0x2e: // 1Ch 2Eh
1.1.1.37 root 8051: pio[c].jis_mode = false;
8052: pio[c].esc_buf[0] = 0x00;
8053: break;
1.1.1.38 root 8054: case 0x32: // 1Ch 32h XX XX data
1.1.1.37 root 8055: if(pio[c].esc_len == 76) {
8056: pio[c].esc_buf[0] = 0x00;
8057: }
8058: break;
1.1.1.38 root 8059: case 0x44: // 1Bh 44h data 00h
1.1.1.37 root 8060: if(pio[c].esc_len == 6) {
8061: pio[c].esc_buf[0] = 0x00;
8062: }
8063: break;
1.1.1.38 root 8064: case 0x53: // 1Ch 53h XX XX
8065: case 0x54: // 1Ch 54h XX XX
1.1.1.37 root 8066: if(pio[c].esc_len == 4) {
8067: pio[c].esc_buf[0] = 0x00;
8068: }
8069: break;
1.1.1.38 root 8070: default: // 1Ch XX
1.1.1.37 root 8071: pio[c].esc_buf[0] = 0x00;
8072: break;
8073: }
8074: } else if(data == 0x1b || data == 0x1c) {
8075: printer_out(c, data);
8076: pio[c].esc_buf[0] = data;
8077: pio[c].esc_len = 1;
8078: } else if((data >= 0x80 && data <= 0x9f) || (data >= 0xe0 && data <= 0xff)) {
8079: pio[c].sjis_hi = data;
8080: } else {
8081: if(pio[c].jis_mode) {
8082: printer_out(c, 0x1c);
8083: printer_out(c, 0x2e);
8084: pio[c].jis_mode = false;
8085: }
8086: printer_out(c, data);
8087: }
8088: } else {
8089: if(pio[c].jis_mode) {
8090: printer_out(c, 0x1c);
8091: printer_out(c, 0x2e);
8092: pio[c].jis_mode = false;
8093: }
8094: printer_out(c, data);
8095: }
8096: }
8097:
8098: inline void pcbios_int_17h_00h()
8099: {
8100: if(REG16(DX) < 3) {
8101: pcbios_printer_out(REG16(DX), REG8(AL));
8102: REG8(AH) = 0xd0;
8103: }
8104: }
8105:
8106: inline void pcbios_int_17h_01h()
8107: {
8108: if(REG16(DX) < 3) {
8109: REG8(AH) = 0xd0;
8110: }
8111: }
8112:
8113: inline void pcbios_int_17h_02h()
8114: {
8115: if(REG16(DX) < 3) {
8116: REG8(AH) = 0xd0;
8117: }
8118: }
8119:
8120: inline void pcbios_int_17h_03h()
8121: {
8122: switch(REG8(AL)) {
8123: case 0x00:
8124: if(REG16(DX) < 3) {
8125: if(pio[REG16(DX)].jis_mode) {
8126: printer_out(REG16(DX), 0x1c);
8127: printer_out(REG16(DX), 0x2e);
8128: pio[REG16(DX)].jis_mode = false;
8129: }
8130: for(UINT16 i = 0; i < REG16(CX); i++) {
8131: printer_out(REG16(DX), mem[SREG_BASE(ES) + REG16(BX) + i]);
8132: }
8133: REG16(CX) = 0x0000;
8134: REG8(AH) = 0xd0;
8135: }
8136: break;
8137: default:
8138: 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));
8139: break;
8140: }
8141: }
8142:
8143: inline void pcbios_int_17h_50h()
8144: {
8145: switch(REG8(AL)) {
8146: case 0x00:
8147: if(REG16(DX) < 3) {
8148: if(REG16(BX) = 0x0001) {
8149: pio[REG16(DX)].conv_mode = false;
8150: REG8(AL) = 0x00;
8151: } else if(REG16(BX) = 0x0051) {
8152: pio[REG16(DX)].conv_mode = true;
8153: REG8(AL) = 0x00;
8154: } else {
8155: REG8(AL) = 0x01;
8156: }
8157: } else {
8158: REG8(AL) = 0x02;
8159: }
8160: break;
8161: case 0x01:
8162: if(REG16(DX) < 3) {
8163: if(pio[REG16(DX)].conv_mode) {
8164: REG16(BX) = 0x0051;
8165: } else {
8166: REG16(BX) = 0x0001;
8167: }
8168: REG8(AL) = 0x00;
8169: } else {
8170: REG8(AL) = 0x02;
8171: }
8172: break;
8173: default:
8174: 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));
8175: break;
8176: }
8177: }
8178:
8179: inline void pcbios_int_17h_51h()
8180: {
8181: if(REG8(DH) >= 0x21 && REG8(DH) <= 0x7e && REG8(DL) >= 0x21 && REG8(DL) <= 0x7e) {
8182: REG16(DX) = pcbios_printer_jis2sjis(REG16(DX));
8183: } else {
8184: REG16(DX) = 0x0000;
8185: }
8186: }
8187:
8188: inline void pcbios_int_17h_52h()
8189: {
8190: if(((REG8(DH) >= 0x81 && REG8(DH) <= 0x9f) || (REG8(DH) >= 0xe0 && REG8(DH) <= 0xfc)) && (REG8(DL) >= 0x40 && REG8(DL) <= 0xfc && REG8(DL) != 0x7f)) {
8191: REG16(DX) = pcbios_printer_sjis2jis(REG16(DX));
8192: } else {
8193: REG16(DX) = 0x0000;
8194: }
8195: }
8196:
8197: inline void pcbios_int_17h_84h()
8198: {
8199: if(REG16(DX) < 3) {
8200: if(pio[REG16(DX)].jis_mode) {
8201: printer_out(REG16(DX), 0x1c);
8202: printer_out(REG16(DX), 0x2e);
8203: pio[REG16(DX)].jis_mode = false;
8204: }
8205: printer_out(REG16(DX), REG8(AL));
8206: REG8(AH) = 0xd0;
8207: }
8208: }
8209:
8210: inline void pcbios_int_17h_85h()
8211: {
8212: pio[0].conv_mode = (REG8(AL) == 0x00);
8213: }
8214:
1.1 root 8215: inline void pcbios_int_1ah_00h()
8216: {
1.1.1.19 root 8217: pcbios_update_daily_timer_counter(timeGetTime());
8218: REG16(CX) = *(UINT16 *)(mem + 0x46e);
8219: REG16(DX) = *(UINT16 *)(mem + 0x46c);
8220: REG8(AL) = mem[0x470];
8221: mem[0x470] = 0;
1.1 root 8222: }
8223:
8224: inline int to_bcd(int t)
8225: {
8226: int u = (t % 100) / 10;
8227: return (u << 4) | (t % 10);
8228: }
8229:
8230: inline void pcbios_int_1ah_02h()
8231: {
8232: SYSTEMTIME time;
8233:
8234: GetLocalTime(&time);
8235: REG8(CH) = to_bcd(time.wHour);
8236: REG8(CL) = to_bcd(time.wMinute);
8237: REG8(DH) = to_bcd(time.wSecond);
8238: REG8(DL) = 0x00;
8239: }
8240:
8241: inline void pcbios_int_1ah_04h()
8242: {
8243: SYSTEMTIME time;
8244:
8245: GetLocalTime(&time);
8246: REG8(CH) = to_bcd(time.wYear / 100);
8247: REG8(CL) = to_bcd(time.wYear);
8248: REG8(DH) = to_bcd(time.wMonth);
8249: REG8(DL) = to_bcd(time.wDay);
8250: }
8251:
8252: inline void pcbios_int_1ah_0ah()
8253: {
8254: SYSTEMTIME time;
8255: FILETIME file_time;
8256: WORD dos_date, dos_time;
8257:
8258: GetLocalTime(&time);
8259: SystemTimeToFileTime(&time, &file_time);
8260: FileTimeToDosDateTime(&file_time, &dos_date, &dos_time);
8261: REG16(CX) = dos_date;
8262: }
8263:
8264: // msdos system call
8265:
8266: inline void msdos_int_21h_00h()
8267: {
1.1.1.3 root 8268: msdos_process_terminate(SREG(CS), retval, 1);
1.1 root 8269: }
8270:
1.1.1.35 root 8271: DWORD WINAPI msdos_int_21h_01h_thread(LPVOID)
1.1 root 8272: {
8273: REG8(AL) = msdos_getche();
1.1.1.33 root 8274: ctrl_break_detected = ctrl_break_pressed;
1.1.1.26 root 8275:
1.1.1.35 root 8276: #ifdef USE_SERVICE_THREAD
8277: service_exit = true;
8278: #endif
8279: return(0);
8280: }
8281:
8282: inline void msdos_int_21h_01h()
8283: {
8284: #ifdef USE_SERVICE_THREAD
8285: start_service_loop(msdos_int_21h_01h_thread);
8286: #else
8287: msdos_int_21h_01h_thread(NULL);
8288: REQUEST_HARDWRE_UPDATE();
8289: #endif
1.1 root 8290: }
8291:
8292: inline void msdos_int_21h_02h()
8293: {
1.1.1.33 root 8294: UINT8 data = REG8(DL);
8295: msdos_putch(data);
8296: REG8(AL) = data;
8297: ctrl_break_detected = ctrl_break_pressed;
1.1 root 8298: }
8299:
8300: inline void msdos_int_21h_03h()
8301: {
8302: REG8(AL) = msdos_aux_in();
8303: }
8304:
8305: inline void msdos_int_21h_04h()
8306: {
8307: msdos_aux_out(REG8(DL));
8308: }
8309:
8310: inline void msdos_int_21h_05h()
8311: {
8312: msdos_prn_out(REG8(DL));
8313: }
8314:
8315: inline void msdos_int_21h_06h()
8316: {
8317: if(REG8(DL) == 0xff) {
8318: if(msdos_kbhit()) {
8319: REG8(AL) = msdos_getch();
1.1.1.3 root 8320: #if defined(HAS_I386)
8321: m_ZF = 0;
8322: #else
8323: m_ZeroVal = 1;
8324: #endif
1.1 root 8325: } else {
8326: REG8(AL) = 0;
1.1.1.3 root 8327: #if defined(HAS_I386)
8328: m_ZF = 1;
8329: #else
8330: m_ZeroVal = 0;
8331: #endif
1.1.1.14 root 8332: maybe_idle();
1.1 root 8333: }
8334: } else {
1.1.1.33 root 8335: UINT8 data = REG8(DL);
8336: msdos_putch(data);
8337: REG8(AL) = data;
1.1 root 8338: }
8339: }
8340:
1.1.1.35 root 8341: DWORD WINAPI msdos_int_21h_07h_thread(LPVOID)
1.1 root 8342: {
8343: REG8(AL) = msdos_getch();
1.1.1.26 root 8344:
1.1.1.35 root 8345: #ifdef USE_SERVICE_THREAD
8346: service_exit = true;
8347: #endif
8348: return(0);
1.1 root 8349: }
8350:
1.1.1.35 root 8351: inline void msdos_int_21h_07h()
8352: {
8353: #ifdef USE_SERVICE_THREAD
8354: start_service_loop(msdos_int_21h_07h_thread);
8355: #else
8356: msdos_int_21h_07h_thread(NULL);
8357: REQUEST_HARDWRE_UPDATE();
8358: #endif
8359: }
8360:
8361: DWORD WINAPI msdos_int_21h_08h_thread(LPVOID)
1.1 root 8362: {
8363: REG8(AL) = msdos_getch();
1.1.1.33 root 8364: ctrl_break_detected = ctrl_break_pressed;
1.1.1.26 root 8365:
1.1.1.35 root 8366: #ifdef USE_SERVICE_THREAD
8367: service_exit = true;
8368: #endif
8369: return(0);
8370: }
8371:
8372: inline void msdos_int_21h_08h()
8373: {
8374: #ifdef USE_SERVICE_THREAD
8375: start_service_loop(msdos_int_21h_08h_thread);
8376: #else
8377: msdos_int_21h_08h_thread(NULL);
8378: REQUEST_HARDWRE_UPDATE();
8379: #endif
1.1 root 8380: }
8381:
8382: inline void msdos_int_21h_09h()
8383: {
1.1.1.21 root 8384: msdos_stdio_reopen();
8385:
1.1.1.20 root 8386: process_t *process = msdos_process_info_get(current_psp);
8387: int fd = msdos_psp_get_file_table(1, current_psp);
8388:
1.1.1.14 root 8389: char *str = (char *)(mem + SREG_BASE(DS) + REG16(DX));
8390: int len = 0;
1.1 root 8391:
1.1.1.14 root 8392: while(str[len] != '$' && len < 0x10000) {
8393: len++;
8394: }
1.1.1.20 root 8395: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 8396: // stdout is redirected to file
1.1.1.20 root 8397: msdos_write(fd, str, len);
1.1 root 8398: } else {
8399: for(int i = 0; i < len; i++) {
1.1.1.14 root 8400: msdos_putch(str[i]);
1.1 root 8401: }
8402: }
1.1.1.33 root 8403: REG8(AL) = '$';
8404: ctrl_break_detected = ctrl_break_pressed;
1.1 root 8405: }
8406:
1.1.1.35 root 8407: DWORD WINAPI msdos_int_21h_0ah_thread(LPVOID)
1.1 root 8408: {
1.1.1.3 root 8409: int ofs = SREG_BASE(DS) + REG16(DX);
1.1 root 8410: int max = mem[ofs] - 1;
8411: UINT8 *buf = mem + ofs + 2;
8412: int chr, p = 0;
8413:
8414: while((chr = msdos_getch()) != 0x0d) {
1.1.1.33 root 8415: if((ctrl_break_checking && ctrl_break_pressed) || ctrl_c_pressed) {
1.1.1.26 root 8416: p = 0;
1.1.1.33 root 8417: msdos_putch(0x03);
8418: msdos_putch(0x0d);
8419: msdos_putch(0x0a);
1.1.1.26 root 8420: break;
1.1.1.33 root 8421: } else if(ctrl_break_pressed) {
8422: // skip this byte
1.1.1.26 root 8423: } else if(chr == 0x00) {
1.1 root 8424: // skip 2nd byte
8425: msdos_getch();
8426: } else if(chr == 0x08) {
8427: // back space
8428: if(p > 0) {
8429: p--;
1.1.1.20 root 8430: if(msdos_ctrl_code_check(buf[p])) {
1.1.1.34 root 8431: msdos_putch(0x08);
8432: msdos_putch(0x08);
8433: msdos_putch(0x20);
8434: msdos_putch(0x20);
8435: msdos_putch(0x08);
8436: msdos_putch(0x08);
1.1.1.36 root 8437: } else if(p > 0 && msdos_kanji_2nd_byte_check(buf, p)) {
8438: p--;
8439: msdos_putch(0x08);
8440: msdos_putch(0x08);
8441: msdos_putch(0x20);
8442: msdos_putch(0x20);
8443: msdos_putch(0x08);
8444: msdos_putch(0x08);
1.1.1.34 root 8445: } else {
8446: msdos_putch(0x08);
8447: msdos_putch(0x20);
8448: msdos_putch(0x08);
8449: }
8450: }
8451: } else if(chr == 0x1b) {
8452: // escape
8453: while(p > 0) {
8454: p--;
8455: if(msdos_ctrl_code_check(buf[p])) {
8456: msdos_putch(0x08);
8457: msdos_putch(0x08);
8458: msdos_putch(0x20);
8459: msdos_putch(0x20);
8460: msdos_putch(0x08);
8461: msdos_putch(0x08);
1.1.1.20 root 8462: } else {
1.1.1.34 root 8463: msdos_putch(0x08);
8464: msdos_putch(0x20);
8465: msdos_putch(0x08);
1.1.1.20 root 8466: }
1.1 root 8467: }
8468: } else if(p < max) {
8469: buf[p++] = chr;
8470: msdos_putch(chr);
8471: }
8472: }
8473: buf[p] = 0x0d;
8474: mem[ofs + 1] = p;
1.1.1.33 root 8475: ctrl_break_detected = ctrl_break_pressed;
1.1.1.26 root 8476:
1.1.1.35 root 8477: #ifdef USE_SERVICE_THREAD
8478: service_exit = true;
8479: #endif
8480: return(0);
8481: }
8482:
8483: inline void msdos_int_21h_0ah()
8484: {
8485: if(mem[SREG_BASE(DS) + REG16(DX)] != 0x00) {
8486: #ifdef USE_SERVICE_THREAD
8487: start_service_loop(msdos_int_21h_0ah_thread);
8488: #else
8489: msdos_int_21h_0ah_thread(NULL);
8490: REQUEST_HARDWRE_UPDATE();
8491: #endif
8492: }
1.1 root 8493: }
8494:
8495: inline void msdos_int_21h_0bh()
8496: {
8497: if(msdos_kbhit()) {
8498: REG8(AL) = 0xff;
8499: } else {
8500: REG8(AL) = 0x00;
1.1.1.14 root 8501: maybe_idle();
1.1 root 8502: }
1.1.1.33 root 8503: ctrl_break_detected = ctrl_break_pressed;
1.1 root 8504: }
8505:
8506: inline void msdos_int_21h_0ch()
8507: {
8508: // clear key buffer
1.1.1.21 root 8509: msdos_stdio_reopen();
8510:
1.1.1.20 root 8511: process_t *process = msdos_process_info_get(current_psp);
8512: int fd = msdos_psp_get_file_table(0, current_psp);
8513:
8514: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 8515: // stdin is redirected to file
8516: } else {
8517: while(msdos_kbhit()) {
8518: msdos_getch();
8519: }
8520: }
8521:
8522: switch(REG8(AL)) {
8523: case 0x01:
8524: msdos_int_21h_01h();
8525: break;
8526: case 0x06:
8527: msdos_int_21h_06h();
8528: break;
8529: case 0x07:
8530: msdos_int_21h_07h();
8531: break;
8532: case 0x08:
8533: msdos_int_21h_08h();
8534: break;
8535: case 0x0a:
8536: msdos_int_21h_0ah();
8537: break;
8538: default:
1.1.1.22 root 8539: // 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));
8540: // REG16(AX) = 0x01;
8541: // m_CF = 1;
1.1 root 8542: break;
8543: }
8544: }
8545:
8546: inline void msdos_int_21h_0dh()
8547: {
8548: }
8549:
8550: inline void msdos_int_21h_0eh()
8551: {
8552: if(REG8(DL) < 26) {
8553: _chdrive(REG8(DL) + 1);
8554: msdos_cds_update(REG8(DL));
1.1.1.23 root 8555: msdos_sda_update(current_psp);
1.1 root 8556: }
8557: REG8(AL) = 26; // zdrive
8558: }
8559:
1.1.1.14 root 8560: inline void msdos_int_21h_0fh()
8561: {
8562: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8563: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
8564: char *path = msdos_fcb_path(fcb);
8565: 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 8566:
1.1.1.14 root 8567: if(hFile == INVALID_HANDLE_VALUE) {
8568: REG8(AL) = 0xff;
8569: } else {
8570: REG8(AL) = 0;
8571: fcb->current_block = 0;
8572: fcb->record_size = 128;
8573: fcb->file_size = GetFileSize(hFile, NULL);
8574: fcb->handle = hFile;
8575: fcb->cur_record = 0;
8576: }
8577: }
8578:
8579: inline void msdos_int_21h_10h()
8580: {
8581: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8582: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
8583:
8584: REG8(AL) = CloseHandle(fcb->handle) ? 0 : 0xff;
8585: }
8586:
1.1 root 8587: inline void msdos_int_21h_11h()
8588: {
1.1.1.3 root 8589: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8590: fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 8591:
8592: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 8593: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
8594: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
8595: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 8596: char *path = msdos_fcb_path(fcb);
8597: WIN32_FIND_DATA fd;
8598:
1.1.1.13 root 8599: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
8600: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
8601: FindClose(dtainfo->find_handle);
8602: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 8603: }
8604: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 8605: dtainfo->allowable_mask = (ext_fcb->flag == 0xff) ? ext_fcb->attribute : 0x20;
8606: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 8607:
1.1.1.14 root 8608: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
8609: dtainfo->allowable_mask &= ~8;
1.1 root 8610: }
1.1.1.14 root 8611: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
8612: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 8613: !msdos_find_file_has_8dot3name(&fd)) {
8614: if(!FindNextFile(dtainfo->find_handle, &fd)) {
8615: FindClose(dtainfo->find_handle);
8616: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 8617: break;
8618: }
8619: }
8620: }
1.1.1.13 root 8621: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 8622: if(ext_fcb->flag == 0xff) {
8623: ext_find->flag = 0xff;
8624: memset(ext_find->reserved, 0, 5);
8625: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
8626: }
8627: find->drive = _getdrive();
1.1.1.13 root 8628: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 8629: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
8630: find->nt_res = 0;
8631: msdos_find_file_conv_local_time(&fd);
8632: find->create_time_ms = 0;
8633: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
8634: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
8635: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
8636: find->cluster_hi = find->cluster_lo = 0;
8637: find->file_size = fd.nFileSizeLow;
8638: REG8(AL) = 0x00;
1.1.1.14 root 8639: } else if(dtainfo->allowable_mask & 8) {
1.1 root 8640: if(ext_fcb->flag == 0xff) {
8641: ext_find->flag = 0xff;
8642: memset(ext_find->reserved, 0, 5);
8643: ext_find->attribute = 8;
8644: }
8645: find->drive = _getdrive();
8646: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
8647: find->attribute = 8;
8648: find->nt_res = 0;
8649: msdos_find_file_conv_local_time(&fd);
8650: find->create_time_ms = 0;
8651: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
8652: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
8653: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
8654: find->cluster_hi = find->cluster_lo = 0;
8655: find->file_size = 0;
1.1.1.14 root 8656: dtainfo->allowable_mask &= ~8;
1.1 root 8657: REG8(AL) = 0x00;
8658: } else {
8659: REG8(AL) = 0xff;
8660: }
8661: }
8662:
8663: inline void msdos_int_21h_12h()
8664: {
1.1.1.3 root 8665: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1.1.14 root 8666: // fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 8667:
8668: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 8669: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
8670: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
8671: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 8672: WIN32_FIND_DATA fd;
8673:
1.1.1.13 root 8674: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
8675: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
8676: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 8677: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 8678: !msdos_find_file_has_8dot3name(&fd)) {
8679: if(!FindNextFile(dtainfo->find_handle, &fd)) {
8680: FindClose(dtainfo->find_handle);
8681: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 8682: break;
8683: }
8684: }
8685: } else {
1.1.1.13 root 8686: FindClose(dtainfo->find_handle);
8687: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 8688: }
8689: }
1.1.1.13 root 8690: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 8691: if(ext_fcb->flag == 0xff) {
8692: ext_find->flag = 0xff;
8693: memset(ext_find->reserved, 0, 5);
8694: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
8695: }
8696: find->drive = _getdrive();
1.1.1.13 root 8697: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 8698: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
8699: find->nt_res = 0;
8700: msdos_find_file_conv_local_time(&fd);
8701: find->create_time_ms = 0;
8702: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
8703: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
8704: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
8705: find->cluster_hi = find->cluster_lo = 0;
8706: find->file_size = fd.nFileSizeLow;
8707: REG8(AL) = 0x00;
1.1.1.14 root 8708: } else if(dtainfo->allowable_mask & 8) {
1.1 root 8709: if(ext_fcb->flag == 0xff) {
8710: ext_find->flag = 0xff;
8711: memset(ext_find->reserved, 0, 5);
8712: ext_find->attribute = 8;
8713: }
8714: find->drive = _getdrive();
8715: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
8716: find->attribute = 8;
8717: find->nt_res = 0;
8718: msdos_find_file_conv_local_time(&fd);
8719: find->create_time_ms = 0;
8720: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
8721: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
8722: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
8723: find->cluster_hi = find->cluster_lo = 0;
8724: find->file_size = 0;
1.1.1.14 root 8725: dtainfo->allowable_mask &= ~8;
1.1 root 8726: REG8(AL) = 0x00;
8727: } else {
8728: REG8(AL) = 0xff;
8729: }
8730: }
8731:
8732: inline void msdos_int_21h_13h()
8733: {
1.1.1.3 root 8734: if(remove(msdos_fcb_path((fcb_t *)(mem + SREG_BASE(DS) + REG16(DX))))) {
1.1 root 8735: REG8(AL) = 0xff;
8736: } else {
8737: REG8(AL) = 0x00;
8738: }
8739: }
8740:
1.1.1.16 root 8741: inline void msdos_int_21h_14h()
8742: {
8743: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8744: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
8745: process_t *process = msdos_process_info_get(current_psp);
8746: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
8747: DWORD num = 0;
8748:
8749: memset(mem + dta_laddr, 0, fcb->record_size);
8750: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
8751: REG8(AL) = 1;
8752: } else {
8753: UINT32 position = fcb->current_block * fcb->record_size + fcb->cur_record + num;
8754: fcb->current_block = (position & 0xffffff) / fcb->record_size;
8755: fcb->cur_record = (position & 0xffffff) % fcb->record_size;
8756: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
8757: }
8758: }
8759:
8760: inline void msdos_int_21h_15h()
1.1.1.14 root 8761: {
8762: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8763: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.16 root 8764: process_t *process = msdos_process_info_get(current_psp);
8765: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
8766: DWORD num = 0;
1.1.1.14 root 8767:
1.1.1.16 root 8768: if(!WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
8769: REG8(AL) = 1;
8770: } else {
8771: fcb->file_size = GetFileSize(fcb->handle, NULL);
8772: UINT32 position = fcb->current_block * fcb->record_size + fcb->cur_record + num;
8773: fcb->current_block = (position & 0xffffff) / fcb->record_size;
8774: fcb->cur_record = (position & 0xffffff) % fcb->record_size;
8775: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
8776: }
8777: }
8778:
8779: inline void msdos_int_21h_16h()
8780: {
8781: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8782: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.14 root 8783: char *path = msdos_fcb_path(fcb);
8784: 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 8785:
1.1.1.14 root 8786: if(hFile == INVALID_HANDLE_VALUE) {
8787: REG8(AL) = 0xff;
8788: } else {
8789: REG8(AL) = 0;
8790: fcb->current_block = 0;
8791: fcb->record_size = 128;
8792: fcb->file_size = 0;
8793: fcb->handle = hFile;
8794: fcb->cur_record = 0;
8795: }
8796: }
8797:
1.1.1.16 root 8798: inline void msdos_int_21h_17h()
8799: {
8800: ext_fcb_t *ext_fcb_src = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8801: fcb_t *fcb_src = (fcb_t *)(ext_fcb_src + (ext_fcb_src->flag == 0xff ? 1 : 0));
8802: char *path_src = msdos_fcb_path(fcb_src);
8803: ext_fcb_t *ext_fcb_dst = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + 16);
8804: fcb_t *fcb_dst = (fcb_t *)(ext_fcb_dst + (ext_fcb_dst->flag == 0xff ? 1 : 0));
8805: char *path_dst = msdos_fcb_path(fcb_dst);
8806:
8807: if(rename(path_src, path_dst)) {
8808: REG8(AL) = 0xff;
8809: } else {
8810: REG8(AL) = 0;
8811: }
8812: }
8813:
1.1 root 8814: inline void msdos_int_21h_18h()
8815: {
8816: REG8(AL) = 0x00;
8817: }
8818:
8819: inline void msdos_int_21h_19h()
8820: {
8821: REG8(AL) = _getdrive() - 1;
8822: }
8823:
8824: inline void msdos_int_21h_1ah()
8825: {
8826: process_t *process = msdos_process_info_get(current_psp);
8827:
8828: process->dta.w.l = REG16(DX);
1.1.1.3 root 8829: process->dta.w.h = SREG(DS);
1.1.1.23 root 8830: msdos_sda_update(current_psp);
1.1 root 8831: }
8832:
8833: inline void msdos_int_21h_1bh()
8834: {
8835: int drive_num = _getdrive() - 1;
8836: UINT16 seg, ofs;
8837:
8838: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
8839: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
8840: REG8(AL) = dpb->highest_sector_num + 1;
8841: REG16(CX) = dpb->bytes_per_sector;
8842: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 8843: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 8844: } else {
8845: REG8(AL) = 0xff;
1.1.1.3 root 8846: m_CF = 1;
1.1 root 8847: }
8848:
8849: }
8850:
8851: inline void msdos_int_21h_1ch()
8852: {
1.1.1.41! root 8853: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
1.1 root 8854: UINT16 seg, ofs;
8855:
8856: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
8857: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
8858: REG8(AL) = dpb->highest_sector_num + 1;
8859: REG16(CX) = dpb->bytes_per_sector;
8860: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 8861: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 8862: } else {
8863: REG8(AL) = 0xff;
1.1.1.3 root 8864: m_CF = 1;
1.1 root 8865: }
8866:
8867: }
8868:
8869: inline void msdos_int_21h_1dh()
8870: {
8871: REG8(AL) = 0;
8872: }
8873:
8874: inline void msdos_int_21h_1eh()
8875: {
8876: REG8(AL) = 0;
8877: }
8878:
8879: inline void msdos_int_21h_1fh()
8880: {
8881: int drive_num = _getdrive() - 1;
8882: UINT16 seg, ofs;
8883:
8884: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
8885: REG8(AL) = 0;
1.1.1.3 root 8886: SREG(DS) = seg;
8887: i386_load_segment_descriptor(DS);
1.1 root 8888: REG16(BX) = ofs;
8889: } else {
8890: REG8(AL) = 0xff;
1.1.1.3 root 8891: m_CF = 1;
1.1 root 8892: }
8893: }
8894:
8895: inline void msdos_int_21h_20h()
8896: {
8897: REG8(AL) = 0;
8898: }
8899:
1.1.1.14 root 8900: inline void msdos_int_21h_21h()
8901: {
8902: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8903: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
8904:
8905: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
8906: REG8(AL) = 1;
8907: } else {
8908: process_t *process = msdos_process_info_get(current_psp);
8909: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
8910: memset(mem + dta_laddr, 0, fcb->record_size);
1.1.1.16 root 8911: DWORD num = 0;
1.1.1.14 root 8912: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
8913: REG8(AL) = 1;
8914: } else {
8915: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
8916: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
1.1.1.16 root 8917: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
1.1.1.14 root 8918: }
8919: }
8920: }
8921:
8922: inline void msdos_int_21h_22h()
8923: {
8924: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8925: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
8926:
8927: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
8928: REG8(AL) = 0xff;
8929: } else {
8930: process_t *process = msdos_process_info_get(current_psp);
8931: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
1.1.1.16 root 8932: DWORD num = 0;
1.1.1.14 root 8933: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL);
8934: fcb->file_size = GetFileSize(fcb->handle, NULL);
8935: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
8936: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
1.1.1.16 root 8937: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
1.1.1.14 root 8938: }
8939: }
8940:
1.1.1.16 root 8941: inline void msdos_int_21h_23h()
8942: {
8943: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8944: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
8945: char *path = msdos_fcb_path(fcb);
8946: HANDLE hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
8947:
8948: if(hFile == INVALID_HANDLE_VALUE) {
8949: REG8(AL) = 0xff;
8950: } else {
8951: UINT32 size = GetFileSize(hFile, NULL);
8952: fcb->rand_record = size / fcb->record_size + ((size % fcb->record_size) != 0);
8953: REG8(AL) = 0;
8954: }
8955: }
8956:
8957: inline void msdos_int_21h_24h()
8958: {
8959: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8960: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
8961:
8962: fcb->rand_record = fcb->current_block * fcb->record_size + fcb->cur_record;
8963: }
8964:
1.1 root 8965: inline void msdos_int_21h_25h()
8966: {
8967: *(UINT16 *)(mem + 4 * REG8(AL) + 0) = REG16(DX);
1.1.1.3 root 8968: *(UINT16 *)(mem + 4 * REG8(AL) + 2) = SREG(DS);
1.1 root 8969: }
8970:
8971: inline void msdos_int_21h_26h()
8972: {
8973: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
8974:
8975: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
8976: psp->first_mcb = REG16(DX) + 16;
8977: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
8978: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
8979: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
8980: psp->parent_psp = 0;
8981: }
8982:
1.1.1.16 root 8983: inline void msdos_int_21h_27h()
8984: {
8985: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
8986: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
8987:
8988: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
8989: REG8(AL) = 1;
8990: } else {
8991: process_t *process = msdos_process_info_get(current_psp);
8992: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
8993: memset(mem + dta_laddr, 0, fcb->record_size * REG16(CX));
8994: DWORD num = 0;
8995: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size * REG16(CX), &num, NULL) || num == 0) {
8996: REG8(AL) = 1;
8997: } else {
8998: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
8999: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
9000: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
9001: REG16(CX) = num / fcb->record_size + ((num % fcb->record_size) != 0);
9002: }
9003: }
9004: }
9005:
9006: inline void msdos_int_21h_28h()
9007: {
9008: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
9009: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
9010:
9011: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
9012: REG8(AL) = 0xff;
9013: } else {
9014: process_t *process = msdos_process_info_get(current_psp);
9015: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
9016: DWORD num = 0;
9017: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size * REG16(CX), &num, NULL);
9018: fcb->file_size = GetFileSize(fcb->handle, NULL);
9019: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
9020: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
9021: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
9022: REG16(CX) = num / fcb->record_size + ((num % fcb->record_size) != 0);
9023: }
9024: }
9025:
1.1 root 9026: inline void msdos_int_21h_29h()
9027: {
1.1.1.20 root 9028: int ofs = 0;//SREG_BASE(DS) + REG16(SI);
9029: char buffer[1024], name[MAX_PATH], ext[MAX_PATH];
1.1 root 9030: UINT8 drv = 0;
9031: char sep_chars[] = ":.;,=+";
9032: char end_chars[] = "\\<>|/\"[]";
9033: char spc_chars[] = " \t";
9034:
1.1.1.20 root 9035: memcpy(buffer, mem + SREG_BASE(DS) + REG16(SI), 1023);
9036: buffer[1023] = 0;
9037: memset(name, 0x20, sizeof(name));
9038: memset(ext, 0x20, sizeof(ext));
9039:
1.1 root 9040: if(REG8(AL) & 1) {
1.1.1.20 root 9041: ofs += strspn((char *)(buffer + ofs), spc_chars);
9042: if(my_strchr(sep_chars, buffer[ofs]) && buffer[ofs] != '\0') {
1.1 root 9043: ofs++;
9044: }
9045: }
1.1.1.20 root 9046: ofs += strspn((char *)(buffer + ofs), spc_chars);
1.1 root 9047:
1.1.1.24 root 9048: if(buffer[ofs + 1] == ':') {
9049: if(buffer[ofs] >= 'a' && buffer[ofs] <= 'z') {
9050: drv = buffer[ofs] - 'a' + 1;
1.1.1.20 root 9051: ofs += 2;
1.1.1.24 root 9052: if(buffer[ofs] == '\\' || buffer[ofs] == '/') {
9053: ofs++;
9054: }
9055: } else if(buffer[ofs] >= 'A' && buffer[ofs] <= 'Z') {
9056: drv = buffer[ofs] - 'A' + 1;
1.1 root 9057: ofs += 2;
1.1.1.24 root 9058: if(buffer[ofs] == '\\' || buffer[ofs] == '/') {
9059: ofs++;
9060: }
1.1 root 9061: }
9062: }
1.1.1.20 root 9063: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) {
9064: UINT8 c = buffer[ofs];
9065: if(is_kanji) {
9066: is_kanji = 0;
9067: } else if(msdos_lead_byte_check(c)) {
9068: is_kanji = 1;
9069: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
1.1 root 9070: break;
9071: } else if(c >= 'a' && c <= 'z') {
9072: c -= 0x20;
9073: }
9074: ofs++;
9075: name[i] = c;
9076: }
1.1.1.20 root 9077: if(buffer[ofs] == '.') {
1.1 root 9078: ofs++;
1.1.1.20 root 9079: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) {
9080: UINT8 c = buffer[ofs];
9081: if(is_kanji) {
9082: is_kanji = 0;
9083: } else if(msdos_lead_byte_check(c)) {
9084: is_kanji = 1;
9085: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
1.1 root 9086: break;
9087: } else if(c >= 'a' && c <= 'z') {
9088: c -= 0x20;
9089: }
9090: ofs++;
9091: ext[i] = c;
9092: }
9093: }
1.1.1.20 root 9094: int si = REG16(SI) + ofs;
1.1.1.3 root 9095: int ds = SREG(DS);
1.1 root 9096: while(si > 0xffff) {
9097: si -= 0x10;
9098: ds++;
9099: }
9100: REG16(SI) = si;
1.1.1.3 root 9101: SREG(DS) = ds;
9102: i386_load_segment_descriptor(DS);
1.1 root 9103:
1.1.1.3 root 9104: UINT8 *fcb = mem + SREG_BASE(ES) + REG16(DI);
1.1.1.20 root 9105: if(!(REG8(AL) & 2) || drv != 0) {
9106: fcb[0] = drv;
9107: }
9108: if(!(REG8(AL) & 4) || name[0] != 0x20) {
9109: memcpy(fcb + 1, name, 8);
9110: }
9111: if(!(REG8(AL) & 8) || ext[0] != 0x20) {
9112: memcpy(fcb + 9, ext, 3);
9113: }
9114: for(int i = 1, found_star = 0; i < 1 + 8; i++) {
1.1 root 9115: if(fcb[i] == '*') {
9116: found_star = 1;
9117: }
9118: if(found_star) {
9119: fcb[i] = '?';
9120: }
9121: }
1.1.1.20 root 9122: for(int i = 9, found_star = 0; i < 9 + 3; i++) {
1.1 root 9123: if(fcb[i] == '*') {
9124: found_star = 1;
9125: }
9126: if(found_star) {
9127: fcb[i] = '?';
9128: }
9129: }
9130:
9131: if(drv == 0 || (drv > 0 && drv <= 26 && (GetLogicalDrives() & ( 1 << (drv - 1) )))) {
9132: if(memchr(fcb + 1, '?', 8 + 3)) {
9133: REG8(AL) = 0x01;
1.1.1.20 root 9134: } else {
9135: REG8(AL) = 0x00;
1.1 root 9136: }
9137: } else {
9138: REG8(AL) = 0xff;
9139: }
9140: }
9141:
9142: inline void msdos_int_21h_2ah()
9143: {
9144: SYSTEMTIME sTime;
9145:
9146: GetLocalTime(&sTime);
9147: REG16(CX) = sTime.wYear;
9148: REG8(DH) = (UINT8)sTime.wMonth;
9149: REG8(DL) = (UINT8)sTime.wDay;
9150: REG8(AL) = (UINT8)sTime.wDayOfWeek;
9151: }
9152:
9153: inline void msdos_int_21h_2bh()
9154: {
1.1.1.14 root 9155: REG8(AL) = 0xff;
1.1 root 9156: }
9157:
9158: inline void msdos_int_21h_2ch()
9159: {
9160: SYSTEMTIME sTime;
9161:
9162: GetLocalTime(&sTime);
9163: REG8(CH) = (UINT8)sTime.wHour;
9164: REG8(CL) = (UINT8)sTime.wMinute;
9165: REG8(DH) = (UINT8)sTime.wSecond;
1.1.1.14 root 9166: REG8(DL) = (UINT8)sTime.wMilliseconds / 10;
1.1 root 9167: }
9168:
9169: inline void msdos_int_21h_2dh()
9170: {
9171: REG8(AL) = 0x00;
9172: }
9173:
9174: inline void msdos_int_21h_2eh()
9175: {
9176: process_t *process = msdos_process_info_get(current_psp);
9177:
9178: process->verify = REG8(AL);
9179: }
9180:
9181: inline void msdos_int_21h_2fh()
9182: {
9183: process_t *process = msdos_process_info_get(current_psp);
9184:
9185: REG16(BX) = process->dta.w.l;
1.1.1.3 root 9186: SREG(ES) = process->dta.w.h;
9187: i386_load_segment_descriptor(ES);
1.1 root 9188: }
9189:
9190: inline void msdos_int_21h_30h()
9191: {
9192: // Version Flag / OEM
1.1.1.27 root 9193: if(REG8(AL) == 0x01) {
1.1.1.29 root 9194: #ifdef SUPPORT_HMA
9195: REG16(BX) = 0x0000;
9196: #else
9197: REG16(BX) = 0x1000; // DOS is in HMA
9198: #endif
1.1 root 9199: } else {
1.1.1.27 root 9200: // NOTE: EXDEB invites BL shows the machine type (0=PC-98, 1=PC/AT, 2=FMR),
9201: // but this is not correct on Windows 98 SE
9202: // REG16(BX) = 0xff01; // OEM = Microsoft, PC/AT
9203: REG16(BX) = 0xff00; // OEM = Microsoft
1.1 root 9204: }
1.1.1.27 root 9205: REG16(CX) = 0x0000;
1.1.1.30 root 9206: REG8(AL) = dos_major_version; // 7
9207: REG8(AH) = dos_minor_version; // 10
1.1 root 9208: }
9209:
9210: inline void msdos_int_21h_31h()
9211: {
1.1.1.29 root 9212: try {
9213: msdos_mem_realloc(current_psp, REG16(DX), NULL);
9214: } catch(...) {
9215: // recover the broken mcb
9216: int mcb_seg = current_psp - 1;
9217: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1.1.33 root 9218:
1.1.1.29 root 9219: if(mcb_seg < (MEMORY_END >> 4)) {
1.1.1.33 root 9220: mcb->mz = 'M';
9221: mcb->paragraphs = (MEMORY_END >> 4) - mcb_seg - 2;
9222:
1.1.1.29 root 9223: if(((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked & 0x01) {
1.1.1.39 root 9224: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', PSP_SYSTEM, (UMB_TOP >> 4) - (MEMORY_END >> 4), "SC");
1.1.1.29 root 9225: } else {
1.1.1.39 root 9226: msdos_mcb_create((MEMORY_END >> 4) - 1, 'Z', PSP_SYSTEM, 0, "SC");
1.1.1.29 root 9227: }
9228: } else {
9229: mcb->mz = 'Z';
1.1.1.30 root 9230: mcb->paragraphs = (UMB_END >> 4) - mcb_seg - 1;
1.1.1.29 root 9231: }
9232: msdos_mem_realloc(current_psp, REG16(DX), NULL);
9233: }
1.1 root 9234: msdos_process_terminate(current_psp, REG8(AL) | 0x300, 0);
9235: }
9236:
9237: inline void msdos_int_21h_32h()
9238: {
9239: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
9240: UINT16 seg, ofs;
9241:
9242: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
9243: REG8(AL) = 0;
1.1.1.3 root 9244: SREG(DS) = seg;
9245: i386_load_segment_descriptor(DS);
1.1 root 9246: REG16(BX) = ofs;
9247: } else {
9248: REG8(AL) = 0xff;
1.1.1.3 root 9249: m_CF = 1;
1.1 root 9250: }
9251: }
9252:
9253: inline void msdos_int_21h_33h()
9254: {
9255: char path[MAX_PATH];
9256:
9257: switch(REG8(AL)) {
9258: case 0x00:
1.1.1.33 root 9259: REG8(DL) = ctrl_break_checking;
1.1 root 9260: break;
9261: case 0x01:
1.1.1.33 root 9262: ctrl_break_checking = REG8(DL);
9263: break;
9264: case 0x02:
9265: {
9266: UINT8 old = ctrl_break_checking;
9267: ctrl_break_checking = REG8(DL);
9268: REG8(DL) = old;
9269: }
9270: break;
9271: case 0x03:
9272: case 0x04:
9273: // DOS 4.0+ - Unused
1.1 root 9274: break;
9275: case 0x05:
9276: GetSystemDirectory(path, MAX_PATH);
9277: if(path[0] >= 'a' && path[0] <= 'z') {
9278: REG8(DL) = path[0] - 'a' + 1;
9279: } else {
9280: REG8(DL) = path[0] - 'A' + 1;
9281: }
9282: break;
9283: case 0x06:
1.1.1.2 root 9284: // MS-DOS version (7.10)
1.1 root 9285: REG8(BL) = 7;
1.1.1.2 root 9286: REG8(BH) = 10;
1.1 root 9287: REG8(DL) = 0;
1.1.1.29 root 9288: #ifdef SUPPORT_HMA
9289: REG8(DH) = 0x00;
9290: #else
9291: REG8(DH) = 0x10; // DOS is in HMA
9292: #endif
1.1 root 9293: break;
1.1.1.6 root 9294: case 0x07:
9295: if(REG8(DL) == 0) {
9296: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag &= ~0x20;
9297: } else if(REG8(DL) == 1) {
9298: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag |= 0x20;
9299: }
9300: break;
1.1 root 9301: default:
1.1.1.22 root 9302: 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 9303: REG16(AX) = 0x01;
1.1.1.3 root 9304: m_CF = 1;
1.1 root 9305: break;
9306: }
9307: }
9308:
1.1.1.23 root 9309: inline void msdos_int_21h_34h()
9310: {
9311: SREG(ES) = SDA_TOP >> 4;
9312: i386_load_segment_descriptor(ES);
9313: REG16(BX) = offsetof(sda_t, indos_flag);;
9314: }
9315:
1.1 root 9316: inline void msdos_int_21h_35h()
9317: {
9318: REG16(BX) = *(UINT16 *)(mem + 4 * REG8(AL) + 0);
1.1.1.3 root 9319: SREG(ES) = *(UINT16 *)(mem + 4 * REG8(AL) + 2);
9320: i386_load_segment_descriptor(ES);
1.1 root 9321: }
9322:
9323: inline void msdos_int_21h_36h()
9324: {
9325: struct _diskfree_t df = {0};
9326:
9327: if(_getdiskfree(REG8(DL), &df) == 0) {
9328: REG16(AX) = (UINT16)df.sectors_per_cluster;
9329: REG16(CX) = (UINT16)df.bytes_per_sector;
1.1.1.13 root 9330: REG16(BX) = df.avail_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.avail_clusters;
9331: REG16(DX) = df.total_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.total_clusters;
1.1 root 9332: } else {
9333: REG16(AX) = 0xffff;
9334: }
9335: }
9336:
9337: inline void msdos_int_21h_37h()
9338: {
1.1.1.22 root 9339: static UINT8 dev_flag = 0xff;
1.1 root 9340:
9341: switch(REG8(AL)) {
9342: case 0x00:
1.1.1.22 root 9343: {
9344: process_t *process = msdos_process_info_get(current_psp);
9345: REG8(AL) = 0x00;
9346: REG8(DL) = process->switchar;
9347: }
1.1 root 9348: break;
9349: case 0x01:
1.1.1.22 root 9350: {
9351: process_t *process = msdos_process_info_get(current_psp);
9352: REG8(AL) = 0x00;
9353: process->switchar = REG8(DL);
1.1.1.23 root 9354: msdos_sda_update(current_psp);
1.1.1.22 root 9355: }
9356: break;
9357: case 0x02:
9358: REG8(DL) = dev_flag;
9359: break;
9360: case 0x03:
9361: dev_flag = REG8(DL);
9362: break;
9363: case 0xd0:
9364: case 0xd1:
9365: case 0xd2:
9366: case 0xd3:
9367: case 0xd4:
9368: case 0xd5:
9369: case 0xd6:
9370: case 0xd7:
9371: case 0xdc:
9372: case 0xdd:
9373: case 0xde:
9374: case 0xdf:
9375: // diet ???
9376: REG16(AX) = 1;
1.1 root 9377: break;
9378: default:
1.1.1.22 root 9379: 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 9380: REG16(AX) = 1;
9381: break;
9382: }
9383: }
9384:
1.1.1.19 root 9385: int get_country_info(country_info_t *ci)
1.1.1.17 root 9386: {
9387: char LCdata[80];
9388:
1.1.1.19 root 9389: ZeroMemory(ci, offsetof(country_info_t, reserved));
1.1.1.17 root 9390: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRDIGITS, LCdata, sizeof(LCdata));
9391: ci->currency_dec_digits = atoi(LCdata);
9392: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRENCY, LCdata, sizeof(LCdata));
9393: ci->currency_format = *LCdata - '0';
9394: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDATE, LCdata, sizeof(LCdata));
9395: ci->date_format = *LCdata - '0';
9396: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SCURRENCY, LCdata, sizeof(LCdata));
9397: memcpy(&ci->currency_symbol, LCdata, 4);
9398: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDATE, LCdata, sizeof(LCdata));
9399: *ci->date_sep = *LCdata;
9400: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, LCdata, sizeof(LCdata));
9401: *ci->dec_sep = *LCdata;
9402: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SLIST, LCdata, sizeof(LCdata));
9403: *ci->list_sep = *LCdata;
9404: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, LCdata, sizeof(LCdata));
9405: *ci->thou_sep = *LCdata;
9406: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIME, LCdata, sizeof(LCdata));
9407: *ci->time_sep = *LCdata;
9408: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIMEFORMAT, LCdata, sizeof(LCdata));
9409: if(strchr(LCdata, 'H') != NULL) {
9410: ci->time_format = 1;
9411: }
1.1.1.27 root 9412: ci->case_map.w.l = 0x000a; // dummy case map routine is at fffd:000a
1.1.1.24 root 9413: ci->case_map.w.h = 0xfffd;
1.1.1.17 root 9414: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICOUNTRY, LCdata, sizeof(LCdata));
9415: return atoi(LCdata);
9416: }
9417:
1.1.1.14 root 9418: inline void msdos_int_21h_38h()
9419: {
9420: switch(REG8(AL)) {
9421: case 0x00:
1.1.1.19 root 9422: REG16(BX) = get_country_info((country_info_t *)(mem + SREG_BASE(DS) + REG16(DX)));
1.1.1.14 root 9423: break;
9424: default:
1.1.1.22 root 9425: 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 9426: REG16(AX) = 2;
9427: m_CF = 1;
9428: break;
9429: }
9430: }
9431:
1.1 root 9432: inline void msdos_int_21h_39h(int lfn)
9433: {
1.1.1.3 root 9434: if(_mkdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 9435: REG16(AX) = errno;
1.1.1.3 root 9436: m_CF = 1;
1.1 root 9437: }
9438: }
9439:
9440: inline void msdos_int_21h_3ah(int lfn)
9441: {
1.1.1.3 root 9442: if(_rmdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 9443: REG16(AX) = errno;
1.1.1.3 root 9444: m_CF = 1;
1.1 root 9445: }
9446: }
9447:
9448: inline void msdos_int_21h_3bh(int lfn)
9449: {
1.1.1.3 root 9450: if(_chdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1.1.17 root 9451: REG16(AX) = 3; // must be 3 (path not found)
1.1.1.3 root 9452: m_CF = 1;
1.1 root 9453: }
9454: }
9455:
9456: inline void msdos_int_21h_3ch()
9457: {
1.1.1.3 root 9458: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 9459: int attr = GetFileAttributes(path);
1.1.1.37 root 9460: int fd = -1;
1.1.1.11 root 9461: UINT16 info;
1.1.1.37 root 9462: int sio_port = 0;
9463: int lpt_port = 0;
1.1 root 9464:
1.1.1.11 root 9465: if(msdos_is_con_path(path)) {
9466: fd = _open("CON", _O_WRONLY | _O_BINARY);
9467: info = 0x80d3;
1.1.1.37 root 9468: } else if((sio_port = msdos_is_comm_path(path)) != 0) {
1.1.1.38 root 9469: fd = _open("NUL", _O_RDWR | _O_BINARY);
1.1.1.14 root 9470: info = 0x80d3;
1.1.1.37 root 9471: msdos_set_comm_params(sio_port, path);
9472: } else if((lpt_port = msdos_is_prn_path(path)) != 0) {
9473: fd = _open("NUL", _O_WRONLY | _O_BINARY);
9474: info = 0xa8c0;
1.1.1.29 root 9475: } else if(msdos_is_device_path(path)) {
1.1.1.20 root 9476: fd = _open("NUL", _O_WRONLY | _O_BINARY);
9477: info = 0x80d3;
1.1 root 9478: } else {
9479: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
1.1.1.11 root 9480: info = msdos_drive_number(path);
1.1 root 9481: }
9482: if(fd != -1) {
9483: if(attr == -1) {
9484: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
9485: }
9486: SetFileAttributes(path, attr);
9487: REG16(AX) = fd;
1.1.1.37 root 9488: msdos_file_handler_open(fd, path, _isatty(fd), 2, info, current_psp, sio_port, lpt_port);
1.1.1.20 root 9489: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 9490: } else {
9491: REG16(AX) = errno;
1.1.1.3 root 9492: m_CF = 1;
1.1 root 9493: }
9494: }
9495:
9496: inline void msdos_int_21h_3dh()
9497: {
1.1.1.3 root 9498: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 9499: int mode = REG8(AL) & 0x03;
1.1.1.37 root 9500: int fd = -1;
1.1.1.11 root 9501: UINT16 info;
1.1.1.37 root 9502: int sio_port = 0;
9503: int lpt_port = 0;
1.1 root 9504:
9505: if(mode < 0x03) {
1.1.1.11 root 9506: if(msdos_is_con_path(path)) {
1.1.1.13 root 9507: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 9508: info = 0x80d3;
1.1.1.37 root 9509: } else if((sio_port = msdos_is_comm_path(path)) != 0) {
9510: fd = msdos_open("NUL", file_mode[mode].mode);
1.1.1.14 root 9511: info = 0x80d3;
1.1.1.37 root 9512: msdos_set_comm_params(sio_port, path);
9513: } else if((lpt_port = msdos_is_prn_path(path)) != 0) {
9514: fd = _open("NUL", file_mode[mode].mode);
9515: info = 0xa8c0;
1.1.1.29 root 9516: } else if(msdos_is_device_path(path)) {
1.1.1.20 root 9517: fd = msdos_open("NUL", file_mode[mode].mode);
9518: info = 0x80d3;
1.1.1.11 root 9519: } else {
1.1.1.13 root 9520: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 9521: info = msdos_drive_number(path);
9522: }
1.1 root 9523: if(fd != -1) {
9524: REG16(AX) = fd;
1.1.1.37 root 9525: msdos_file_handler_open(fd, path, _isatty(fd), mode, info, current_psp, sio_port, lpt_port);
1.1.1.20 root 9526: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 9527: } else {
9528: REG16(AX) = errno;
1.1.1.3 root 9529: m_CF = 1;
1.1 root 9530: }
9531: } else {
9532: REG16(AX) = 0x0c;
1.1.1.3 root 9533: m_CF = 1;
1.1 root 9534: }
9535: }
9536:
9537: inline void msdos_int_21h_3eh()
9538: {
9539: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 9540: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 9541:
1.1.1.20 root 9542: if(fd < process->max_files && file_handler[fd].valid) {
9543: _close(fd);
9544: msdos_file_handler_close(fd);
9545: msdos_psp_set_file_table(REG16(BX), 0x0ff, current_psp);
1.1 root 9546: } else {
9547: REG16(AX) = 0x06;
1.1.1.3 root 9548: m_CF = 1;
1.1 root 9549: }
9550: }
9551:
1.1.1.35 root 9552: DWORD WINAPI msdos_int_21h_3fh_thread(LPVOID)
9553: {
9554: UINT8 *buf = mem + SREG_BASE(DS) + REG16(DX);
9555: int max = REG16(CX);
9556: int p = 0;
9557:
9558: while(max > p) {
9559: int chr = msdos_getch();
9560:
9561: if((ctrl_break_checking && ctrl_break_pressed) || ctrl_c_pressed) {
9562: p = 0;
9563: buf[p++] = 0x0d;
9564: if(max > p) {
9565: buf[p++] = 0x0a;
9566: }
9567: msdos_putch(0x03);
9568: msdos_putch(0x0d);
9569: msdos_putch(0x0a);
9570: break;
9571: } else if(ctrl_break_pressed) {
9572: // skip this byte
9573: } else if(chr == 0x00) {
9574: // skip 2nd byte
9575: msdos_getch();
9576: } else if(chr == 0x0d) {
9577: // carriage return
9578: buf[p++] = 0x0d;
9579: if(max > p) {
9580: buf[p++] = 0x0a;
9581: }
9582: msdos_putch('\n');
9583: break;
9584: } else if(chr == 0x08) {
9585: // back space
9586: if(p > 0) {
9587: p--;
9588: if(msdos_ctrl_code_check(buf[p])) {
9589: msdos_putch(0x08);
9590: msdos_putch(0x08);
9591: msdos_putch(0x20);
9592: msdos_putch(0x20);
9593: msdos_putch(0x08);
9594: msdos_putch(0x08);
1.1.1.36 root 9595: } else if(p > 0 && msdos_kanji_2nd_byte_check(buf, p)) {
9596: p--;
9597: msdos_putch(0x08);
9598: msdos_putch(0x08);
9599: msdos_putch(0x20);
9600: msdos_putch(0x20);
9601: msdos_putch(0x08);
9602: msdos_putch(0x08);
1.1.1.35 root 9603: } else {
9604: msdos_putch(0x08);
9605: msdos_putch(0x20);
9606: msdos_putch(0x08);
9607: }
9608: }
9609: } else if(chr == 0x1b) {
9610: // escape
9611: while(p > 0) {
9612: p--;
9613: if(msdos_ctrl_code_check(buf[p])) {
9614: msdos_putch(0x08);
9615: msdos_putch(0x08);
9616: msdos_putch(0x20);
9617: msdos_putch(0x20);
9618: msdos_putch(0x08);
9619: msdos_putch(0x08);
9620: } else {
9621: msdos_putch(0x08);
9622: msdos_putch(0x20);
9623: msdos_putch(0x08);
9624: }
9625: }
9626: } else {
9627: buf[p++] = chr;
9628: msdos_putch(chr);
9629: }
9630: }
9631: REG16(AX) = p;
9632:
9633: #ifdef USE_SERVICE_THREAD
9634: service_exit = true;
9635: #endif
9636: return(0);
9637: }
9638:
1.1 root 9639: inline void msdos_int_21h_3fh()
9640: {
9641: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 9642: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 9643:
1.1.1.20 root 9644: if(fd < process->max_files && file_handler[fd].valid) {
9645: if(file_mode[file_handler[fd].mode].in) {
9646: if(file_handler[fd].atty) {
1.1 root 9647: // BX is stdin or is redirected to stdin
1.1.1.35 root 9648: if(REG16(CX) != 0) {
9649: #ifdef USE_SERVICE_THREAD
9650: start_service_loop(msdos_int_21h_3fh_thread);
9651: #else
9652: msdos_int_21h_3fh_thread(NULL);
9653: REQUEST_HARDWRE_UPDATE();
9654: #endif
9655: } else {
9656: REG16(AX) = 0;
1.1 root 9657: }
9658: } else {
1.1.1.37 root 9659: REG16(AX) = msdos_read(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 9660: }
9661: } else {
9662: REG16(AX) = 0x05;
1.1.1.3 root 9663: m_CF = 1;
1.1 root 9664: }
9665: } else {
9666: REG16(AX) = 0x06;
1.1.1.3 root 9667: m_CF = 1;
1.1 root 9668: }
9669: }
9670:
9671: inline void msdos_int_21h_40h()
9672: {
9673: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 9674: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 9675:
1.1.1.20 root 9676: if(fd < process->max_files && file_handler[fd].valid) {
9677: if(file_mode[file_handler[fd].mode].out) {
1.1 root 9678: if(REG16(CX)) {
1.1.1.20 root 9679: if(file_handler[fd].atty) {
1.1 root 9680: // BX is stdout/stderr or is redirected to stdout
9681: for(int i = 0; i < REG16(CX); i++) {
1.1.1.3 root 9682: msdos_putch(mem[SREG_BASE(DS) + REG16(DX) + i]);
1.1 root 9683: }
9684: REG16(AX) = REG16(CX);
9685: } else {
1.1.1.20 root 9686: REG16(AX) = msdos_write(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 9687: }
9688: } else {
1.1.1.20 root 9689: UINT32 pos = _tell(fd);
9690: _lseek(fd, 0, SEEK_END);
9691: UINT32 size = _tell(fd);
1.1.1.12 root 9692: if(pos < size) {
1.1.1.20 root 9693: _lseek(fd, pos, SEEK_SET);
9694: SetEndOfFile((HANDLE)_get_osfhandle(fd));
1.1.1.12 root 9695: } else {
9696: for(UINT32 i = size; i < pos; i++) {
9697: UINT8 tmp = 0;
1.1.1.23 root 9698: msdos_write(fd, &tmp, 1);
1.1.1.12 root 9699: }
1.1.1.20 root 9700: _lseek(fd, pos, SEEK_SET);
1.1 root 9701: }
1.1.1.23 root 9702: REG16(AX) = 0;
1.1 root 9703: }
9704: } else {
9705: REG16(AX) = 0x05;
1.1.1.3 root 9706: m_CF = 1;
1.1 root 9707: }
9708: } else {
9709: REG16(AX) = 0x06;
1.1.1.3 root 9710: m_CF = 1;
1.1 root 9711: }
9712: }
9713:
9714: inline void msdos_int_21h_41h(int lfn)
9715: {
1.1.1.3 root 9716: if(remove(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 9717: REG16(AX) = errno;
1.1.1.3 root 9718: m_CF = 1;
1.1 root 9719: }
9720: }
9721:
9722: inline void msdos_int_21h_42h()
9723: {
9724: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 9725: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 9726:
1.1.1.20 root 9727: if(fd < process->max_files && file_handler[fd].valid) {
1.1 root 9728: if(REG8(AL) < 0x03) {
1.1.1.35 root 9729: static const int ptrname[] = { SEEK_SET, SEEK_CUR, SEEK_END };
1.1.1.20 root 9730: _lseek(fd, (REG16(CX) << 16) | REG16(DX), ptrname[REG8(AL)]);
9731: UINT32 pos = _tell(fd);
1.1 root 9732: REG16(AX) = pos & 0xffff;
9733: REG16(DX) = (pos >> 16);
9734: } else {
9735: REG16(AX) = 0x01;
1.1.1.3 root 9736: m_CF = 1;
1.1 root 9737: }
9738: } else {
9739: REG16(AX) = 0x06;
1.1.1.3 root 9740: m_CF = 1;
1.1 root 9741: }
9742: }
9743:
9744: inline void msdos_int_21h_43h(int lfn)
9745: {
1.1.1.3 root 9746: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn);
1.1 root 9747: int attr;
9748:
1.1.1.14 root 9749: if(!lfn && REG8(AL) > 2) {
9750: REG16(AX) = 0x01;
9751: m_CF = 1;
9752: return;
9753: }
9754: switch(REG8(lfn ? BL : AL)) {
1.1 root 9755: case 0x00:
9756: if((attr = GetFileAttributes(path)) != -1) {
1.1.1.14 root 9757: REG16(CX) = (UINT16)msdos_file_attribute_create((UINT16)attr);
9758: } else {
9759: REG16(AX) = (UINT16)GetLastError();
9760: m_CF = 1;
9761: }
9762: break;
9763: case 0x01:
9764: if(!SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)))) {
9765: REG16(AX) = (UINT16)GetLastError();
9766: m_CF = 1;
9767: }
9768: break;
9769: case 0x02:
9770: {
9771: DWORD size = GetCompressedFileSize(path, NULL);
9772: if(size != INVALID_FILE_SIZE) {
9773: if(size != 0 && size == GetFileSize(path, NULL)) {
9774: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
9775: // this isn't correct if the file is in the NTFS MFT
9776: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
9777: size = ((size - 1) | (sectors_per_cluster * bytes_per_sector - 1)) + 1;
9778: }
9779: }
9780: REG16(AX) = LOWORD(size);
9781: REG16(DX) = HIWORD(size);
9782: } else {
9783: REG16(AX) = (UINT16)GetLastError();
9784: m_CF = 1;
1.1 root 9785: }
1.1.1.14 root 9786: }
9787: break;
9788: case 0x03:
9789: case 0x05:
9790: case 0x07:
9791: {
9792: HANDLE hFile = CreateFile(path, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
9793: if(hFile != INVALID_HANDLE_VALUE) {
9794: FILETIME local, time;
9795: DosDateTimeToFileTime(REG16(DI), /*REG8(BL) == 5 ? 0 : */REG16(CX), &local);
9796: if(REG8(BL) == 7) {
9797: ULARGE_INTEGER hund;
9798: hund.LowPart = local.dwLowDateTime;
9799: hund.HighPart = local.dwHighDateTime;
9800: hund.QuadPart += REG16(SI) * 100000;
9801: local.dwLowDateTime = hund.LowPart;
9802: local.dwHighDateTime = hund.HighPart;
9803: }
9804: LocalFileTimeToFileTime(&local, &time);
9805: if(!SetFileTime(hFile, REG8(BL) == 0x07 ? &time : NULL,
9806: REG8(BL) == 0x05 ? &time : NULL,
9807: REG8(BL) == 0x03 ? &time : NULL)) {
9808: REG16(AX) = (UINT16)GetLastError();
9809: m_CF = 1;
9810: }
9811: CloseHandle(hFile);
9812: } else {
9813: REG16(AX) = (UINT16)GetLastError();
9814: m_CF = 1;
1.1 root 9815: }
1.1.1.14 root 9816: }
9817: break;
9818: case 0x04:
9819: case 0x06:
9820: case 0x08:
9821: {
9822: WIN32_FILE_ATTRIBUTE_DATA fad;
9823: if(GetFileAttributesEx(path, GetFileExInfoStandard, (LPVOID)&fad)) {
9824: FILETIME *time, local;
9825: time = REG8(BL) == 0x04 ? &fad.ftLastWriteTime :
9826: 0x06 ? &fad.ftLastAccessTime :
9827: &fad.ftCreationTime;
9828: FileTimeToLocalFileTime(time, &local);
9829: FileTimeToDosDateTime(&local, ®16(DI), ®16(CX));
9830: if(REG8(BL) == 0x08) {
9831: ULARGE_INTEGER hund;
9832: hund.LowPart = local.dwLowDateTime;
9833: hund.HighPart = local.dwHighDateTime;
9834: hund.QuadPart /= 100000;
9835: REG16(SI) = (UINT16)(hund.QuadPart % 200);
9836: }
9837: } else {
9838: REG16(AX) = (UINT16)GetLastError();
9839: m_CF = 1;
1.1 root 9840: }
1.1.1.14 root 9841: }
9842: break;
9843: default:
1.1.1.22 root 9844: 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 9845: REG16(AX) = 0x01;
9846: m_CF = 1;
9847: break;
9848: }
9849: }
9850:
9851: inline void msdos_int_21h_44h()
9852: {
1.1.1.22 root 9853: static UINT16 iteration_count = 0;
9854:
1.1.1.20 root 9855: process_t *process = msdos_process_info_get(current_psp);
9856: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
9857:
1.1.1.14 root 9858: UINT32 val = DRIVE_NO_ROOT_DIR;
9859:
9860: switch(REG8(AL)) {
9861: case 0x00:
9862: case 0x01:
9863: case 0x02:
9864: case 0x03:
9865: case 0x04:
9866: case 0x05:
9867: case 0x06:
9868: case 0x07:
1.1.1.20 root 9869: if(fd >= process->max_files || !file_handler[fd].valid) {
9870: REG16(AX) = 0x06;
9871: m_CF = 1;
9872: return;
1.1.1.14 root 9873: }
9874: break;
9875: case 0x08:
9876: case 0x09:
9877: if(REG8(BL) >= ('Z' - 'A' + 1)) {
9878: // invalid drive number
9879: REG16(AX) = 0x0f;
9880: m_CF = 1;
9881: return;
9882: } else {
9883: if(REG8(BL) == 0) {
9884: val = GetDriveType(NULL);
9885: } else {
9886: char tmp[8];
9887: sprintf(tmp, "%c:\\", 'A' + REG8(BL) - 1);
9888: val = GetDriveType(tmp);
9889: }
9890: if(val == DRIVE_NO_ROOT_DIR) {
9891: // no drive
9892: REG16(AX) = 0x0f;
9893: m_CF = 1;
9894: return;
1.1 root 9895: }
9896: }
9897: break;
9898: }
9899: switch(REG8(AL)) {
9900: case 0x00: // get ioctrl data
1.1.1.20 root 9901: REG16(DX) = file_handler[fd].info;
1.1 root 9902: break;
9903: case 0x01: // set ioctrl data
1.1.1.20 root 9904: file_handler[fd].info |= REG8(DL);
1.1 root 9905: break;
9906: case 0x02: // recv from character device
9907: case 0x03: // send to character device
9908: case 0x04: // recv from block device
9909: case 0x05: // send to block device
9910: REG16(AX) = 0x05;
1.1.1.3 root 9911: m_CF = 1;
1.1 root 9912: break;
9913: case 0x06: // get read status
1.1.1.20 root 9914: if(file_mode[file_handler[fd].mode].in) {
9915: if(file_handler[fd].atty) {
1.1.1.14 root 9916: REG8(AL) = msdos_kbhit() ? 0xff : 0x00;
1.1 root 9917: } else {
1.1.1.20 root 9918: REG8(AL) = eof(fd) ? 0x00 : 0xff;
1.1 root 9919: }
1.1.1.14 root 9920: } else {
9921: REG8(AL) = 0x00;
1.1 root 9922: }
9923: break;
9924: case 0x07: // get write status
1.1.1.20 root 9925: if(file_mode[file_handler[fd].mode].out) {
1.1.1.14 root 9926: REG8(AL) = 0xff;
9927: } else {
9928: REG8(AL) = 0x00;
1.1 root 9929: }
9930: break;
9931: case 0x08: // check removable drive
1.1.1.14 root 9932: if(val == DRIVE_REMOVABLE || val == DRIVE_CDROM) {
9933: // removable drive
9934: REG16(AX) = 0x00;
1.1 root 9935: } else {
1.1.1.14 root 9936: // fixed drive
9937: REG16(AX) = 0x01;
1.1 root 9938: }
9939: break;
9940: case 0x09: // check remote drive
1.1.1.14 root 9941: if(val == DRIVE_REMOTE) {
9942: // remote drive
9943: REG16(DX) = 0x1000;
1.1 root 9944: } else {
1.1.1.14 root 9945: // local drive
9946: REG16(DX) = 0x00;
1.1 root 9947: }
9948: break;
1.1.1.21 root 9949: case 0x0a: // check remote handle
9950: REG16(DX) = 0x00; // FIXME
9951: break;
1.1 root 9952: case 0x0b: // set retry count
9953: break;
1.1.1.22 root 9954: case 0x0c: // generic character device request
9955: if(REG8(CL) == 0x45) {
9956: // set iteration (retry) count
9957: iteration_count = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX));
9958: } else if(REG8(CL) == 0x4a) {
9959: // select code page
9960: active_code_page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2);
9961: msdos_nls_tables_update();
9962: } else if(REG8(CL) == 0x65) {
9963: // get iteration (retry) count
9964: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX)) = iteration_count;
9965: } else if(REG8(CL) == 0x6a) {
9966: // query selected code page
9967: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = 2; // FIXME
9968: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2) = active_code_page;
9969:
9970: CPINFO info;
9971: GetCPInfo(active_code_page, &info);
9972:
9973: if(info.MaxCharSize != 1) {
9974: for(int i = 0;; i++) {
9975: UINT8 lo = info.LeadByte[2 * i + 0];
9976: UINT8 hi = info.LeadByte[2 * i + 1];
9977:
9978: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4 + 4 * i + 0) = lo;
9979: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4 + 4 * i + 2) = hi;
9980: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) + 4;
9981:
9982: if(lo == 0 && hi == 0) {
9983: break;
9984: }
9985: }
9986: }
9987: } else if(REG8(CL) == 0x7f) {
9988: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x00) = 0;
9989: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x01) = 0;
9990: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02) = 14;
9991: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x04) = 1;
9992: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x06) = 1;
9993: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x07) = 0;
9994: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x08) = 4;
9995: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0a) = 8 * (*(UINT16 *)(mem + 0x44a));
9996: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0c) = 16 * (*(UINT8 *)(mem + 0x484) + 1);
9997: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0e) = *(UINT16 *)(mem + 0x44a);
9998: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x10) = *(UINT8 *)(mem + 0x484) + 1;
9999: } else {
10000: 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));
10001: REG16(AX) = 0x01; // invalid function
10002: m_CF = 1;
10003: }
10004: break;
10005: case 0x0d: // generic block device request
10006: if(REG8(CL) == 0x40) {
10007: // set device parameters
10008: } else if(REG8(CL) == 0x46) {
10009: // set volume serial number
10010: } else if(REG8(CL) == 0x4a) {
10011: // lock logical volume
10012: } else if(REG8(CL) == 0x4b) {
10013: // lock physical volume
10014: } else if(REG8(CL) == 0x60) {
10015: // get device parameters
10016: char dev[] = "\\\\.\\A:";
10017: dev[4] = 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
10018:
10019: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
10020: if(hFile != INVALID_HANDLE_VALUE) {
10021: DISK_GEOMETRY geo;
10022: DWORD dwSize;
10023: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
10024: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x07; // ???
10025: switch(geo.MediaType) {
10026: case F5_360_512:
10027: case F5_320_512:
10028: case F5_320_1024:
10029: case F5_180_512:
10030: case F5_160_512:
10031: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x00; // 320K/360K disk
10032: break;
10033: case F5_1Pt2_512:
10034: case F3_1Pt2_512:
10035: case F3_1Pt23_1024:
10036: case F5_1Pt23_1024:
10037: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x01; // 1.2M disk
10038: break;
10039: case F3_720_512:
10040: case F3_640_512:
10041: case F5_640_512:
10042: case F5_720_512:
10043: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x02; // 720K disk
10044: break;
10045: case F8_256_128:
10046: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x03; // single-density 8-inch disk
10047: break;
10048: case FixedMedia:
10049: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // fixed disk
10050: break;
10051: case F3_1Pt44_512:
10052: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x07; // (DOS 3.3+) other type of block device, normally 1.44M floppy
10053: break;
10054: case F3_2Pt88_512:
10055: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x09; // (DOS 5+) 2.88M floppy
10056: break;
10057: default:
10058: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // fixed disk
10059: // *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // (DOS 3.3+) other type of block device, normally 1.44M floppy
10060: break;
10061: }
10062: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x02) = (geo.MediaType == FixedMedia) ? 0x01 : 0x00;
10063: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04) = (geo.Cylinders.QuadPart > 0xffff) ? 0xffff : geo.Cylinders.QuadPart;
10064: switch(geo.MediaType) {
10065: case F5_360_512:
10066: case F5_320_512:
10067: case F5_320_1024:
10068: case F5_180_512:
10069: case F5_160_512:
10070: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06) = 0x01; // 320K/360K disk
10071: break;
10072: default:
10073: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06) = 0x00; // other drive types
10074: break;
10075: }
10076: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x00) = geo.BytesPerSector;
10077: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x02) = geo.SectorsPerTrack * geo.TracksPerCylinder;
10078: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x03) = 0;
10079: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x05) = 0;
10080: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x06) = 0;
10081: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x08) = 0;
10082: switch(geo.MediaType) {
10083: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K)
10084: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xff;
10085: break;
10086: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K)
10087: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfe;
10088: break;
10089: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K)
10090: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfd;
10091: break;
10092: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K)
10093: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfc;
10094: break;
10095: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M)
10096: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5")
10097: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf9;
10098: break;
10099: case FixedMedia: // hard disk
10100: case RemovableMedia:
10101: case Unknown:
10102: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf8;
10103: break;
10104: default:
10105: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf0;
10106: break;
10107: }
10108: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0d) = geo.SectorsPerTrack;
10109: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0f) = 1;
10110: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x11) = 0;
10111: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x15) = geo.TracksPerCylinder * geo.Cylinders.QuadPart;
10112: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x1f) = geo.Cylinders.QuadPart;
10113: // 21h BYTE device type
10114: // 22h WORD device attributes (removable or not, etc)
10115: } else {
10116: REG16(AX) = 0x0f; // invalid drive
10117: m_CF = 1;
10118: }
10119: CloseHandle(hFile);
10120: } else {
10121: REG16(AX) = 0x0f; // invalid drive
10122: m_CF = 1;
10123: }
10124: } else if(REG8(CL) == 0x66) {
10125: // get volume serial number
10126: char path[] = "A:\\";
10127: char volume_label[MAX_PATH];
10128: DWORD serial_number = 0;
10129: char file_system[MAX_PATH];
10130:
10131: path[0] = 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
10132:
10133: if(GetVolumeInformation(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) {
10134: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0;
10135: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x02) = serial_number;
10136: memset(mem + SREG_BASE(DS) + REG16(SI) + 0x06, 0x20, 11);
10137: memcpy(mem + SREG_BASE(DS) + REG16(SI) + 0x06, volume_label, min(strlen(volume_label), 11));
10138: memset(mem + SREG_BASE(DS) + REG16(SI) + 0x11, 0x20, 8);
10139: memcpy(mem + SREG_BASE(DS) + REG16(SI) + 0x11, file_system, min(strlen(file_system), 8));
10140: } else {
10141: REG16(AX) = 0x0f; // invalid drive
10142: m_CF = 1;
10143: }
10144: } else if(REG8(CL) == 0x67) {
10145: // get access flag
10146: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0;
10147: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 1;
10148: } else if(REG8(CL) == 0x68) {
10149: // sense media type
10150: char dev[64];
10151: sprintf(dev, "\\\\.\\%c:", 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1);
10152:
10153: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
10154: if(hFile != INVALID_HANDLE_VALUE) {
10155: DISK_GEOMETRY geo;
10156: DWORD dwSize;
10157: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
10158: switch(geo.MediaType) {
10159: case F3_720_512:
10160: case F5_720_512:
10161: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
10162: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x02;
10163: break;
10164: case F3_1Pt44_512:
10165: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
10166: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x07;
10167: break;
10168: case F3_2Pt88_512:
10169: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
10170: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x09;
10171: break;
10172: default:
10173: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x00;
10174: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x00; // ???
10175: break;
10176: }
10177: } else {
10178: REG16(AX) = 0x0f; // invalid drive
10179: m_CF = 1;
10180: }
10181: CloseHandle(hFile);
10182: } else {
10183: REG16(AX) = 0x0f; // invalid drive
10184: m_CF = 1;
10185: }
10186: } else if(REG8(CL) == 0x6a) {
10187: // unlock logical volume
10188: } else if(REG8(CL) == 0x6b) {
10189: // unlock physical volume
10190: } else {
10191: 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));
10192: REG16(AX) = 0x01; // invalid function
10193: m_CF = 1;
10194: }
10195: break;
10196: case 0x0e: // get logical drive map
10197: {
10198: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
10199: if(!(GetLogicalDrives() & bits)) {
10200: REG16(AX) = 0x0f; // invalid drive
10201: m_CF = 1;
10202: } else {
10203: REG8(AL) = 0;
10204: }
10205: }
10206: break;
10207: case 0x0f: // set logical drive map
10208: {
10209: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
10210: if(!(GetLogicalDrives() & bits)) {
10211: REG16(AX) = 0x0f; // invalid drive
10212: m_CF = 1;
10213: }
10214: }
10215: break;
10216: case 0x10: // query generic ioctrl capability (handle)
10217: switch(REG8(CL)) {
10218: case 0x45:
10219: case 0x4a:
10220: case 0x65:
10221: case 0x6a:
10222: case 0x7f:
10223: REG16(AX) = 0x0000; // supported
10224: break;
10225: default:
10226: REG8(AL) = 0x01; // ioctl capability not available
10227: m_CF = 1;
10228: break;
10229: }
10230: break;
10231: case 0x11: // query generic ioctrl capability (drive)
10232: switch(REG8(CL)) {
10233: case 0x40:
10234: case 0x46:
10235: case 0x4a:
10236: case 0x4b:
10237: case 0x60:
10238: case 0x66:
10239: case 0x67:
10240: case 0x68:
10241: case 0x6a:
10242: case 0x6b:
10243: REG16(AX) = 0x0000; // supported
10244: break;
10245: default:
10246: REG8(AL) = 0x01; // ioctl capability not available
10247: m_CF = 1;
10248: break;
10249: }
10250: break;
10251: case 0x12: // determine dos type
10252: case 0x51: // concurrent dos v3.2+ - installation check
10253: case 0x52: // determine dos type/get dr dos versuin
10254: REG16(AX) = 0x01; // this is not DR-DOS
10255: m_CF = 1;
10256: break;
1.1 root 10257: default:
1.1.1.22 root 10258: 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 10259: REG16(AX) = 0x01;
1.1.1.3 root 10260: m_CF = 1;
1.1 root 10261: break;
10262: }
10263: }
10264:
10265: inline void msdos_int_21h_45h()
10266: {
10267: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 10268: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 10269:
1.1.1.20 root 10270: if(fd < process->max_files && file_handler[fd].valid) {
10271: int dup_fd = _dup(fd);
10272: if(dup_fd != -1) {
10273: REG16(AX) = dup_fd;
10274: msdos_file_handler_dup(dup_fd, fd, current_psp);
10275: // msdos_psp_set_file_table(dup_fd, fd, current_psp);
10276: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp);
1.1 root 10277: } else {
10278: REG16(AX) = errno;
1.1.1.3 root 10279: m_CF = 1;
1.1 root 10280: }
10281: } else {
10282: REG16(AX) = 0x06;
1.1.1.3 root 10283: m_CF = 1;
1.1 root 10284: }
10285: }
10286:
10287: inline void msdos_int_21h_46h()
10288: {
10289: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 10290: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
10291: int dup_fd = REG16(CX);
10292: int tmp_fd = msdos_psp_get_file_table(REG16(CX), current_psp);
1.1 root 10293:
1.1.1.20 root 10294: if(REG16(BX) == REG16(CX)) {
10295: REG16(AX) = 0x06;
10296: m_CF = 1;
10297: } else if(fd < process->max_files && file_handler[fd].valid && dup_fd < process->max_files) {
10298: if(tmp_fd < process->max_files && file_handler[tmp_fd].valid) {
10299: _close(tmp_fd);
10300: msdos_file_handler_close(tmp_fd);
10301: msdos_psp_set_file_table(dup_fd, 0x0ff, current_psp);
10302: }
10303: if(_dup2(fd, dup_fd) != -1) {
10304: msdos_file_handler_dup(dup_fd, fd, current_psp);
10305: // msdos_psp_set_file_table(dup_fd, fd, current_psp);
10306: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp);
1.1 root 10307: } else {
10308: REG16(AX) = errno;
1.1.1.3 root 10309: m_CF = 1;
1.1 root 10310: }
10311: } else {
10312: REG16(AX) = 0x06;
1.1.1.3 root 10313: m_CF = 1;
1.1 root 10314: }
10315: }
10316:
10317: inline void msdos_int_21h_47h(int lfn)
10318: {
10319: char path[MAX_PATH];
10320:
10321: if(_getdcwd(REG8(DL), path, MAX_PATH) != NULL) {
10322: if(path[1] == ':') {
10323: // the returned path does not include a drive or the initial backslash
1.1.1.3 root 10324: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), (lfn ? path : msdos_short_path(path)) + 3);
1.1 root 10325: } else {
1.1.1.3 root 10326: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn ? path : msdos_short_path(path));
1.1 root 10327: }
10328: } else {
10329: REG16(AX) = errno;
1.1.1.3 root 10330: m_CF = 1;
1.1 root 10331: }
10332: }
10333:
10334: inline void msdos_int_21h_48h()
10335: {
1.1.1.19 root 10336: int seg, umb_linked;
1.1 root 10337:
1.1.1.8 root 10338: if((malloc_strategy & 0xf0) == 0x00) {
1.1.1.19 root 10339: // unlink umb not to allocate memory in umb
10340: if((umb_linked = msdos_mem_get_umb_linked()) != 0) {
10341: msdos_mem_unlink_umb();
10342: }
1.1.1.8 root 10343: if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
10344: REG16(AX) = seg;
10345: } else {
10346: REG16(AX) = 0x08;
10347: REG16(BX) = msdos_mem_get_free(first_mcb, 0);
10348: m_CF = 1;
10349: }
1.1.1.19 root 10350: if(umb_linked != 0) {
10351: msdos_mem_link_umb();
10352: }
1.1.1.8 root 10353: } else if((malloc_strategy & 0xf0) == 0x40) {
10354: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
10355: REG16(AX) = seg;
10356: } else {
10357: REG16(AX) = 0x08;
10358: REG16(BX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
10359: m_CF = 1;
10360: }
10361: } else if((malloc_strategy & 0xf0) == 0x80) {
10362: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
10363: REG16(AX) = seg;
10364: } else if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
10365: REG16(AX) = seg;
10366: } else {
10367: REG16(AX) = 0x08;
10368: REG16(BX) = max(msdos_mem_get_free(UMB_TOP >> 4, 0), msdos_mem_get_free(first_mcb, 0));
10369: m_CF = 1;
10370: }
1.1 root 10371: }
10372: }
10373:
10374: inline void msdos_int_21h_49h()
10375: {
1.1.1.14 root 10376: int mcb_seg = SREG(ES) - 1;
10377: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
10378:
10379: if(mcb->mz == 'M' || mcb->mz == 'Z') {
10380: msdos_mem_free(SREG(ES));
10381: } else {
1.1.1.33 root 10382: REG16(AX) = 0x09; // illegal memory block address
1.1.1.14 root 10383: m_CF = 1;
10384: }
1.1 root 10385: }
10386:
10387: inline void msdos_int_21h_4ah()
10388: {
1.1.1.14 root 10389: int mcb_seg = SREG(ES) - 1;
10390: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1 root 10391: int max_paragraphs;
10392:
1.1.1.14 root 10393: if(mcb->mz == 'M' || mcb->mz == 'Z') {
10394: if(msdos_mem_realloc(SREG(ES), REG16(BX), &max_paragraphs)) {
10395: REG16(AX) = 0x08;
10396: REG16(BX) = max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs;
10397: m_CF = 1;
10398: }
10399: } else {
1.1.1.33 root 10400: REG16(AX) = 0x09; // illegal memory block address
1.1.1.3 root 10401: m_CF = 1;
1.1 root 10402: }
10403: }
10404:
10405: inline void msdos_int_21h_4bh()
10406: {
1.1.1.3 root 10407: char *command = (char *)(mem + SREG_BASE(DS) + REG16(DX));
10408: param_block_t *param = (param_block_t *)(mem + SREG_BASE(ES) + REG16(BX));
1.1 root 10409:
10410: switch(REG8(AL)) {
10411: case 0x00:
10412: case 0x01:
10413: if(msdos_process_exec(command, param, REG8(AL))) {
10414: REG16(AX) = 0x02;
1.1.1.3 root 10415: m_CF = 1;
1.1 root 10416: }
10417: break;
1.1.1.14 root 10418: case 0x03:
10419: {
10420: int fd;
10421: if((fd = _open(command, _O_RDONLY | _O_BINARY)) == -1) {
10422: REG16(AX) = 0x02;
10423: m_CF = 1;
10424: break;
10425: }
10426: int size = _read(fd, file_buffer, sizeof(file_buffer));
10427: _close(fd);
10428:
10429: UINT16 *overlay = (UINT16 *)param;
10430:
10431: // check exe header
10432: exe_header_t *header = (exe_header_t *)file_buffer;
10433: int header_size = 0;
10434: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
10435: header_size = header->header_size * 16;
10436: // relocation
10437: int start_seg = overlay[1];
10438: for(int i = 0; i < header->relocations; i++) {
10439: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
10440: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
10441: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
10442: }
10443: }
10444: memcpy(mem + (overlay[0] << 4), file_buffer + header_size, size - header_size);
10445: }
10446: break;
1.1 root 10447: default:
1.1.1.22 root 10448: unimplemented_21h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x21, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
1.1 root 10449: REG16(AX) = 0x01;
1.1.1.3 root 10450: m_CF = 1;
1.1 root 10451: break;
10452: }
10453: }
10454:
10455: inline void msdos_int_21h_4ch()
10456: {
10457: msdos_process_terminate(current_psp, REG8(AL), 1);
10458: }
10459:
10460: inline void msdos_int_21h_4dh()
10461: {
10462: REG16(AX) = retval;
10463: }
10464:
10465: inline void msdos_int_21h_4eh()
10466: {
10467: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 10468: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
10469: find_t *find = (find_t *)(mem + dta_laddr);
1.1.1.3 root 10470: char *path = msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 10471: WIN32_FIND_DATA fd;
10472:
1.1.1.14 root 10473: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
10474: find->find_magic = FIND_MAGIC;
10475: find->dta_index = dtainfo - dtalist;
1.1 root 10476: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 10477: dtainfo->allowable_mask = REG8(CL);
10478: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 10479:
1.1.1.14 root 10480: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
10481: dtainfo->allowable_mask &= ~8;
1.1 root 10482: }
1.1.1.14 root 10483: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
10484: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 10485: !msdos_find_file_has_8dot3name(&fd)) {
10486: if(!FindNextFile(dtainfo->find_handle, &fd)) {
10487: FindClose(dtainfo->find_handle);
10488: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 10489: break;
10490: }
10491: }
10492: }
1.1.1.13 root 10493: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 10494: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
10495: msdos_find_file_conv_local_time(&fd);
10496: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
10497: find->size = fd.nFileSizeLow;
1.1.1.13 root 10498: strcpy(find->name, msdos_short_name(&fd));
1.1 root 10499: REG16(AX) = 0;
1.1.1.14 root 10500: } else if(dtainfo->allowable_mask & 8) {
1.1 root 10501: find->attrib = 8;
10502: find->size = 0;
10503: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 10504: dtainfo->allowable_mask &= ~8;
1.1 root 10505: REG16(AX) = 0;
10506: } else {
10507: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 10508: m_CF = 1;
1.1 root 10509: }
10510: }
10511:
10512: inline void msdos_int_21h_4fh()
10513: {
10514: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 10515: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
10516: find_t *find = (find_t *)(mem + dta_laddr);
1.1 root 10517: WIN32_FIND_DATA fd;
10518:
1.1.1.14 root 10519: if(find->find_magic != FIND_MAGIC || find->dta_index >= MAX_DTAINFO) {
10520: REG16(AX) = 0x12;
10521: m_CF = 1;
10522: return;
10523: }
10524: dtainfo_t *dtainfo = &dtalist[find->dta_index];
1.1.1.13 root 10525: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
10526: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 10527: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 10528: !msdos_find_file_has_8dot3name(&fd)) {
10529: if(!FindNextFile(dtainfo->find_handle, &fd)) {
10530: FindClose(dtainfo->find_handle);
10531: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 10532: break;
10533: }
10534: }
10535: } else {
1.1.1.13 root 10536: FindClose(dtainfo->find_handle);
10537: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 10538: }
10539: }
1.1.1.13 root 10540: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 10541: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
10542: msdos_find_file_conv_local_time(&fd);
10543: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
10544: find->size = fd.nFileSizeLow;
1.1.1.13 root 10545: strcpy(find->name, msdos_short_name(&fd));
1.1 root 10546: REG16(AX) = 0;
1.1.1.14 root 10547: } else if(dtainfo->allowable_mask & 8) {
1.1 root 10548: find->attrib = 8;
10549: find->size = 0;
10550: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 10551: dtainfo->allowable_mask &= ~8;
1.1 root 10552: REG16(AX) = 0;
10553: } else {
10554: REG16(AX) = 0x12;
1.1.1.3 root 10555: m_CF = 1;
1.1 root 10556: }
10557: }
10558:
10559: inline void msdos_int_21h_50h()
10560: {
1.1.1.8 root 10561: if(current_psp != REG16(BX)) {
10562: process_t *process = msdos_process_info_get(current_psp);
10563: if(process != NULL) {
10564: process->psp = REG16(BX);
10565: }
10566: current_psp = REG16(BX);
1.1.1.23 root 10567: msdos_sda_update(current_psp);
1.1.1.8 root 10568: }
1.1 root 10569: }
10570:
10571: inline void msdos_int_21h_51h()
10572: {
10573: REG16(BX) = current_psp;
10574: }
10575:
10576: inline void msdos_int_21h_52h()
10577: {
1.1.1.25 root 10578: SREG(ES) = DOS_INFO_TOP >> 4;
1.1.1.3 root 10579: i386_load_segment_descriptor(ES);
1.1.1.25 root 10580: REG16(BX) = offsetof(dos_info_t, first_dpb);
1.1 root 10581: }
10582:
10583: inline void msdos_int_21h_54h()
10584: {
10585: process_t *process = msdos_process_info_get(current_psp);
10586:
10587: REG8(AL) = process->verify;
10588: }
10589:
10590: inline void msdos_int_21h_55h()
10591: {
10592: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
10593:
10594: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
10595: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
10596: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
10597: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
10598: psp->parent_psp = current_psp;
10599: }
10600:
10601: inline void msdos_int_21h_56h(int lfn)
10602: {
10603: char src[MAX_PATH], dst[MAX_PATH];
1.1.1.3 root 10604: strcpy(src, msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn));
10605: strcpy(dst, msdos_trimmed_path((char *)(mem + SREG_BASE(ES) + REG16(DI)), lfn));
1.1 root 10606:
10607: if(rename(src, dst)) {
10608: REG16(AX) = errno;
1.1.1.3 root 10609: m_CF = 1;
1.1 root 10610: }
10611: }
10612:
10613: inline void msdos_int_21h_57h()
10614: {
10615: FILETIME time, local;
1.1.1.14 root 10616: FILETIME *ctime, *atime, *mtime;
1.1.1.21 root 10617: HANDLE hHandle;
1.1 root 10618:
1.1.1.21 root 10619: if((hHandle = (HANDLE)_get_osfhandle(REG16(BX))) == INVALID_HANDLE_VALUE) {
1.1.1.14 root 10620: REG16(AX) = (UINT16)GetLastError();
10621: m_CF = 1;
10622: return;
10623: }
10624: ctime = atime = mtime = NULL;
10625:
1.1 root 10626: switch(REG8(AL)) {
10627: case 0x00:
1.1.1.6 root 10628: case 0x01:
1.1.1.14 root 10629: mtime = &time;
1.1.1.6 root 10630: break;
10631: case 0x04:
10632: case 0x05:
1.1.1.14 root 10633: atime = &time;
1.1 root 10634: break;
1.1.1.6 root 10635: case 0x06:
10636: case 0x07:
1.1.1.14 root 10637: ctime = &time;
10638: break;
10639: default:
1.1.1.22 root 10640: 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 10641: REG16(AX) = 0x01;
10642: m_CF = 1;
10643: return;
10644: }
10645: if(REG8(AL) & 1) {
1.1 root 10646: DosDateTimeToFileTime(REG16(DX), REG16(CX), &local);
10647: LocalFileTimeToFileTime(&local, &time);
1.1.1.21 root 10648: if(!SetFileTime(hHandle, ctime, atime, mtime)) {
1.1 root 10649: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 10650: m_CF = 1;
1.1 root 10651: }
1.1.1.14 root 10652: } else {
1.1.1.21 root 10653: if(!GetFileTime(hHandle, ctime, atime, mtime)) {
1.1.1.14 root 10654: // assume a device and use the current time
10655: GetSystemTimeAsFileTime(&time);
10656: }
10657: FileTimeToLocalFileTime(&time, &local);
10658: FileTimeToDosDateTime(&local, ®16(DX), ®16(CX));
1.1 root 10659: }
10660: }
10661:
10662: inline void msdos_int_21h_58h()
10663: {
10664: switch(REG8(AL)) {
10665: case 0x00:
1.1.1.7 root 10666: REG16(AX) = malloc_strategy;
10667: break;
10668: case 0x01:
1.1.1.24 root 10669: // switch(REG16(BX)) {
10670: switch(REG8(BL)) {
1.1.1.7 root 10671: case 0x0000:
10672: case 0x0001:
10673: case 0x0002:
10674: case 0x0040:
10675: case 0x0041:
10676: case 0x0042:
10677: case 0x0080:
10678: case 0x0081:
10679: case 0x0082:
10680: malloc_strategy = REG16(BX);
1.1.1.23 root 10681: msdos_sda_update(current_psp);
1.1.1.7 root 10682: break;
10683: default:
1.1.1.22 root 10684: 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 10685: REG16(AX) = 0x01;
10686: m_CF = 1;
10687: break;
10688: }
10689: break;
10690: case 0x02:
1.1.1.19 root 10691: REG8(AL) = msdos_mem_get_umb_linked() ? 1 : 0;
1.1.1.7 root 10692: break;
10693: case 0x03:
1.1.1.24 root 10694: // switch(REG16(BX)) {
10695: switch(REG8(BL)) {
1.1.1.7 root 10696: case 0x0000:
1.1.1.19 root 10697: msdos_mem_unlink_umb();
10698: break;
1.1.1.7 root 10699: case 0x0001:
1.1.1.19 root 10700: msdos_mem_link_umb();
1.1.1.7 root 10701: break;
10702: default:
1.1.1.22 root 10703: 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 10704: REG16(AX) = 0x01;
10705: m_CF = 1;
10706: break;
10707: }
1.1 root 10708: break;
10709: default:
1.1.1.22 root 10710: 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 10711: REG16(AX) = 0x01;
1.1.1.3 root 10712: m_CF = 1;
1.1 root 10713: break;
10714: }
10715: }
10716:
10717: inline void msdos_int_21h_59h()
10718: {
1.1.1.23 root 10719: sda_t *sda = (sda_t *)(mem + SDA_TOP);
10720:
10721: REG16(AX) = sda->extended_error_code;
10722: REG8(BH) = sda->error_class;
10723: REG8(BL) = sda->suggested_action;
10724: REG8(CH) = sda->locus_of_last_error;
1.1 root 10725: }
10726:
10727: inline void msdos_int_21h_5ah()
10728: {
1.1.1.3 root 10729: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 10730: int len = strlen(path);
10731: char tmp[MAX_PATH];
10732:
10733: if(GetTempFileName(path, "TMP", 0, tmp)) {
10734: int fd = _open(tmp, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
10735:
10736: SetFileAttributes(tmp, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
10737: REG16(AX) = fd;
10738: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 10739: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 10740:
10741: strcpy(path, tmp);
10742: int dx = REG16(DX) + len;
1.1.1.3 root 10743: int ds = SREG(DS);
1.1 root 10744: while(dx > 0xffff) {
10745: dx -= 0x10;
10746: ds++;
10747: }
10748: REG16(DX) = dx;
1.1.1.3 root 10749: SREG(DS) = ds;
10750: i386_load_segment_descriptor(DS);
1.1 root 10751: } else {
10752: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 10753: m_CF = 1;
1.1 root 10754: }
10755: }
10756:
10757: inline void msdos_int_21h_5bh()
10758: {
1.1.1.3 root 10759: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 10760:
1.1.1.24 root 10761: if(msdos_is_existing_file(path)) {
1.1 root 10762: // already exists
10763: REG16(AX) = 0x50;
1.1.1.3 root 10764: m_CF = 1;
1.1 root 10765: } else {
10766: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
10767:
10768: if(fd != -1) {
10769: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
10770: REG16(AX) = fd;
10771: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 10772: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 10773: } else {
10774: REG16(AX) = errno;
1.1.1.3 root 10775: m_CF = 1;
1.1 root 10776: }
10777: }
10778: }
10779:
10780: inline void msdos_int_21h_5ch()
10781: {
10782: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 10783: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 10784:
1.1.1.20 root 10785: if(fd < process->max_files && file_handler[fd].valid) {
1.1 root 10786: if(REG8(AL) == 0 || REG8(AL) == 1) {
1.1.1.35 root 10787: static const int modes[2] = {_LK_LOCK, _LK_UNLCK};
1.1.1.20 root 10788: UINT32 pos = _tell(fd);
10789: _lseek(fd, (REG16(CX) << 16) | REG16(DX), SEEK_SET);
10790: if(_locking(fd, modes[REG8(AL)], (REG16(SI) << 16) | REG16(DI))) {
1.1 root 10791: REG16(AX) = errno;
1.1.1.3 root 10792: m_CF = 1;
1.1 root 10793: }
1.1.1.20 root 10794: _lseek(fd, pos, SEEK_SET);
1.1.1.26 root 10795:
1.1 root 10796: // some seconds may be passed in _locking()
1.1.1.35 root 10797: REQUEST_HARDWRE_UPDATE();
1.1 root 10798: } else {
10799: REG16(AX) = 0x01;
1.1.1.3 root 10800: m_CF = 1;
1.1 root 10801: }
10802: } else {
10803: REG16(AX) = 0x06;
1.1.1.3 root 10804: m_CF = 1;
1.1 root 10805: }
10806: }
10807:
1.1.1.22 root 10808: inline void msdos_int_21h_5dh()
10809: {
10810: switch(REG8(AL)) {
10811: case 0x06: // get address of dos swappable data area
1.1.1.23 root 10812: SREG(DS) = (SDA_TOP >> 4);
10813: i386_load_segment_descriptor(DS);
10814: REG16(SI) = offsetof(sda_t, crit_error_flag);
10815: REG16(CX) = 0x80;
10816: REG16(DX) = 0x1a;
10817: break;
10818: case 0x0b: // get dos swappable data areas
1.1.1.22 root 10819: REG16(AX) = 0x01;
10820: m_CF = 1;
10821: break;
10822: case 0x08: // set redirected printer mode
10823: case 0x09: // flush redirected printer output
10824: case 0x0a: // set extended error information
10825: break;
10826: default:
10827: 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));
10828: REG16(AX) = 0x01;
10829: m_CF = 1;
10830: break;
10831: }
10832: }
10833:
1.1.1.30 root 10834: inline void msdos_int_21h_5fh()
10835: {
10836: switch(REG8(AL)) {
10837: case 0x02:
10838: {
10839: DWORD drives = GetLogicalDrives();
10840: for(int i = 0, index = 0; i < 26; i++) {
10841: if(drives & (1 << i)) {
10842: char volume[] = "A:\\";
10843: volume[0] = 'A' + i;
10844: if(GetDriveType(volume) == DRIVE_REMOTE) {
10845: if(index == REG16(BX)) {
10846: DWORD dwSize = 128;
10847: volume[2] = '\0';
10848: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), volume);
10849: WNetGetConnection(volume, (char *)(mem + SREG_BASE(ES) + REG16(DI)), &dwSize);
10850: REG8(BH) = 0x00; // valid
10851: REG8(BL) = 0x04; // disk drive
10852: REG16(CX) = 0x00;
10853: return;
10854: }
10855: index++;
10856: }
10857: }
10858: }
10859: }
10860: REG16(AX) = 0x12; // no more files
10861: m_CF = 1;
10862: break;
10863: default:
10864: 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));
10865: REG16(AX) = 0x01;
10866: m_CF = 1;
10867: break;
10868: }
10869: }
10870:
1.1 root 10871: inline void msdos_int_21h_60h(int lfn)
10872: {
1.1.1.14 root 10873: char full[MAX_PATH], *path;
10874:
1.1 root 10875: if(lfn) {
1.1.1.14 root 10876: char *name;
10877: *full = '\0';
1.1.1.3 root 10878: GetFullPathName((char *)(mem + SREG_BASE(DS) + REG16(SI)), MAX_PATH, full, &name);
1.1.1.14 root 10879: switch(REG8(CL)) {
10880: case 1:
10881: GetShortPathName(full, full, MAX_PATH);
10882: my_strupr(full);
10883: break;
10884: case 2:
10885: GetLongPathName(full, full, MAX_PATH);
10886: break;
10887: }
10888: path = full;
10889: } else {
10890: path = msdos_short_full_path((char *)(mem + SREG_BASE(DS) + REG16(SI)));
10891: }
10892: if(*path != '\0') {
10893: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), path);
1.1 root 10894: } else {
1.1.1.14 root 10895: REG16(AX) = (UINT16)GetLastError();
10896: m_CF = 1;
1.1 root 10897: }
10898: }
10899:
10900: inline void msdos_int_21h_61h()
10901: {
10902: REG8(AL) = 0;
10903: }
10904:
10905: inline void msdos_int_21h_62h()
10906: {
10907: REG16(BX) = current_psp;
10908: }
10909:
10910: inline void msdos_int_21h_63h()
10911: {
10912: switch(REG8(AL)) {
10913: case 0x00:
1.1.1.3 root 10914: SREG(DS) = (DBCS_TABLE >> 4);
10915: i386_load_segment_descriptor(DS);
1.1 root 10916: REG16(SI) = (DBCS_TABLE & 0x0f);
10917: REG8(AL) = 0x00;
10918: break;
1.1.1.22 root 10919: case 0x01: // set korean input mode
10920: case 0x02: // get korean input mode
10921: REG8(AL) = 0xff; // not supported
10922: break;
1.1 root 10923: default:
1.1.1.22 root 10924: 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 10925: REG16(AX) = 0x01;
1.1.1.3 root 10926: m_CF = 1;
1.1 root 10927: break;
10928: }
10929: }
10930:
1.1.1.25 root 10931: UINT16 get_extended_country_info(UINT8 func)
1.1 root 10932: {
1.1.1.25 root 10933: switch(func) {
1.1.1.17 root 10934: case 0x01:
10935: if(REG16(CX) >= 5) {
1.1.1.19 root 10936: UINT8 data[1 + 2 + 2 + 2 + sizeof(country_info_t)];
1.1.1.17 root 10937: if(REG16(CX) > sizeof(data)) // cx = actual transfer size
10938: REG16(CX) = sizeof(data);
10939: ZeroMemory(data, sizeof(data));
10940: data[0] = 0x01;
10941: *(UINT16 *)(data + 1) = REG16(CX) - 3;
1.1.1.19 root 10942: *(UINT16 *)(data + 3) = get_country_info((country_info_t*)(data + 7));
1.1.1.17 root 10943: *(UINT16 *)(data + 5) = active_code_page;
10944: memcpy(mem + SREG_BASE(ES) + REG16(DI), data, REG16(CX));
1.1.1.25 root 10945: // REG16(AX) = active_code_page;
1.1.1.17 root 10946: } else {
1.1.1.25 root 10947: return(0x08); // insufficient memory
1.1.1.17 root 10948: }
10949: break;
10950: case 0x02:
10951: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x02;
10952: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (UPPERTABLE_TOP & 0x0f);
10953: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (UPPERTABLE_TOP >> 4);
1.1.1.25 root 10954: // REG16(AX) = active_code_page;
1.1.1.17 root 10955: REG16(CX) = 0x05;
10956: break;
1.1.1.23 root 10957: case 0x03:
10958: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x02;
10959: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (LOWERTABLE_TOP & 0x0f);
10960: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (LOWERTABLE_TOP >> 4);
1.1.1.25 root 10961: // REG16(AX) = active_code_page;
1.1.1.23 root 10962: REG16(CX) = 0x05;
10963: break;
1.1.1.17 root 10964: case 0x04:
10965: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x04;
10966: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_UPPERTABLE_TOP & 0x0f);
10967: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_UPPERTABLE_TOP >> 4);
1.1.1.25 root 10968: // REG16(AX) = active_code_page;
1.1.1.17 root 10969: REG16(CX) = 0x05;
10970: break;
10971: case 0x05:
10972: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x05;
10973: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_TERMINATOR_TOP & 0x0f);
10974: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_TERMINATOR_TOP >> 4);
1.1.1.25 root 10975: // REG16(AX) = active_code_page;
1.1.1.17 root 10976: REG16(CX) = 0x05;
10977: break;
10978: case 0x06:
10979: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x06;
10980: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (COLLATING_TABLE_TOP & 0x0f);
10981: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (COLLATING_TABLE_TOP >> 4);
1.1.1.25 root 10982: // REG16(AX) = active_code_page;
1.1.1.17 root 10983: REG16(CX) = 0x05;
10984: break;
1.1 root 10985: case 0x07:
1.1.1.3 root 10986: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x07;
10987: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (DBCS_TOP & 0x0f);
10988: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (DBCS_TOP >> 4);
1.1.1.25 root 10989: // REG16(AX) = active_code_page;
1.1 root 10990: REG16(CX) = 0x05;
10991: break;
1.1.1.25 root 10992: default:
10993: return(0x01); // function number invalid
10994: }
10995: return(0x00);
10996: }
10997:
10998: inline void msdos_int_21h_65h()
10999: {
11000: char tmp[0x10000];
11001:
11002: switch(REG8(AL)) {
11003: case 0x01:
11004: case 0x02:
11005: case 0x03:
11006: case 0x04:
11007: case 0x05:
11008: case 0x06:
11009: case 0x07:
11010: {
11011: UINT16 result = get_extended_country_info(REG8(AL));
11012: if(result) {
11013: REG16(AX) = result;
11014: m_CF = 1;
11015: } else {
11016: REG16(AX) = active_code_page; // FIXME: is this correct???
11017: }
11018: }
11019: break;
1.1 root 11020: case 0x20:
1.1.1.25 root 11021: case 0xa0:
1.1.1.19 root 11022: memset(tmp, 0, sizeof(tmp));
11023: tmp[0] = REG8(DL);
1.1 root 11024: my_strupr(tmp);
11025: REG8(DL) = tmp[0];
11026: break;
11027: case 0x21:
1.1.1.25 root 11028: case 0xa1:
1.1 root 11029: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 11030: memcpy(tmp, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 11031: my_strupr(tmp);
1.1.1.3 root 11032: memcpy(mem + SREG_BASE(DS) + REG16(DX), tmp, REG16(CX));
1.1 root 11033: break;
11034: case 0x22:
1.1.1.25 root 11035: case 0xa2:
1.1.1.3 root 11036: my_strupr((char *)(mem + SREG_BASE(DS) + REG16(DX)));
1.1 root 11037: break;
1.1.1.25 root 11038: case 0x23:
11039: // FIXME: need to check multi-byte (kanji) charactre?
11040: if(REG8(DL) == 'N' || REG8(DL) == 'n' || (REG8(DL) == 0x82 && REG8(DH) == 0x78) || (REG8(DL) == 0x82 && REG8(DH) == 0x99)) {
11041: // 8278h/8299h: multi-byte (kanji) Y and y
11042: REG16(AX) = 0x00;
11043: } else if(REG8(DL) == 'Y' || REG8(DL) == 'y' || (REG8(DL) == 0x82 && REG8(DH) == 0x6d) || (REG8(DL) == 0x82 && REG8(DH) == 0x8e)) {
11044: // 826dh/828eh: multi-byte (kanji) N and n
11045: REG16(AX) = 0x01;
11046: } else {
11047: REG16(AX) = 0x02;
11048: }
11049: break;
1.1 root 11050: default:
1.1.1.22 root 11051: 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 11052: REG16(AX) = 0x01;
1.1.1.3 root 11053: m_CF = 1;
1.1 root 11054: break;
11055: }
11056: }
11057:
11058: inline void msdos_int_21h_66h()
11059: {
11060: switch(REG8(AL)) {
11061: case 0x01:
11062: REG16(BX) = active_code_page;
11063: REG16(DX) = system_code_page;
11064: break;
11065: case 0x02:
11066: if(active_code_page == REG16(BX)) {
11067: REG16(AX) = 0xeb41;
11068: } else if(_setmbcp(REG16(BX)) == 0) {
11069: active_code_page = REG16(BX);
1.1.1.17 root 11070: msdos_nls_tables_update();
1.1 root 11071: REG16(AX) = 0xeb41;
1.1.1.32 root 11072: SetConsoleCP(active_code_page);
11073: SetConsoleOutputCP(active_code_page);
1.1 root 11074: } else {
11075: REG16(AX) = 0x25;
1.1.1.3 root 11076: m_CF = 1;
1.1 root 11077: }
11078: break;
11079: default:
1.1.1.22 root 11080: 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 11081: REG16(AX) = 0x01;
1.1.1.3 root 11082: m_CF = 1;
1.1 root 11083: break;
11084: }
11085: }
11086:
11087: inline void msdos_int_21h_67h()
11088: {
11089: process_t *process = msdos_process_info_get(current_psp);
11090:
11091: if(REG16(BX) <= MAX_FILES) {
11092: process->max_files = max(REG16(BX), 20);
11093: } else {
11094: REG16(AX) = 0x08;
1.1.1.3 root 11095: m_CF = 1;
1.1 root 11096: }
11097: }
11098:
11099: inline void msdos_int_21h_68h()
11100: {
11101: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 11102: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 11103:
1.1.1.20 root 11104: if(fd < process->max_files && file_handler[fd].valid) {
11105: // fflush(_fdopen(fd, ""));
1.1 root 11106: } else {
11107: REG16(AX) = 0x06;
1.1.1.3 root 11108: m_CF = 1;
1.1 root 11109: }
11110: }
11111:
11112: inline void msdos_int_21h_69h()
11113: {
1.1.1.3 root 11114: drive_info_t *info = (drive_info_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 11115: char path[] = "A:\\";
11116: char volume_label[MAX_PATH];
11117: DWORD serial_number = 0;
11118: char file_system[MAX_PATH];
11119:
11120: if(REG8(BL) == 0) {
11121: path[0] = 'A' + _getdrive() - 1;
11122: } else {
11123: path[0] = 'A' + REG8(BL) - 1;
11124: }
11125:
11126: switch(REG8(AL)) {
11127: case 0x00:
11128: if(GetVolumeInformation(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) {
11129: info->info_level = 0;
11130: info->serial_number = serial_number;
11131: memset(info->volume_label, 0x20, 11);
11132: memcpy(info->volume_label, volume_label, min(strlen(volume_label), 11));
11133: memset(info->file_system, 0x20, 8);
11134: memcpy(info->file_system, file_system, min(strlen(file_system), 8));
11135: } else {
11136: REG16(AX) = errno;
1.1.1.3 root 11137: m_CF = 1;
1.1 root 11138: }
11139: break;
11140: case 0x01:
11141: REG16(AX) = 0x03;
1.1.1.3 root 11142: m_CF = 1;
1.1 root 11143: }
11144: }
11145:
11146: inline void msdos_int_21h_6ah()
11147: {
11148: REG8(AH) = 0x68;
11149: msdos_int_21h_68h();
11150: }
11151:
11152: inline void msdos_int_21h_6bh()
11153: {
11154: REG8(AL) = 0;
11155: }
11156:
11157: inline void msdos_int_21h_6ch(int lfn)
11158: {
1.1.1.3 root 11159: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn);
1.1 root 11160: int mode = REG8(BL) & 0x03;
11161:
11162: if(mode < 0x03) {
1.1.1.29 root 11163: if(msdos_is_device_path(path) || msdos_is_existing_file(path)) {
1.1 root 11164: // file exists
11165: if(REG8(DL) & 1) {
1.1.1.37 root 11166: int fd = -1;
1.1.1.11 root 11167: UINT16 info;
1.1.1.37 root 11168: int sio_port = 0;
11169: int lpt_port = 0;
1.1 root 11170:
1.1.1.11 root 11171: if(msdos_is_con_path(path)) {
1.1.1.13 root 11172: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 11173: info = 0x80d3;
1.1.1.37 root 11174: } else if((sio_port = msdos_is_comm_path(path)) != 0) {
11175: fd = msdos_open("NUL", file_mode[mode].mode);
1.1.1.14 root 11176: info = 0x80d3;
1.1.1.37 root 11177: msdos_set_comm_params(sio_port, path);
11178: } else if((lpt_port = msdos_is_prn_path(path)) != 0) {
11179: fd = msdos_open("NUL", file_mode[mode].mode);
11180: info = 0xa8c0;
1.1.1.29 root 11181: } else if(msdos_is_device_path(path)) {
1.1.1.20 root 11182: fd = msdos_open("NUL", file_mode[mode].mode);
11183: info = 0x80d3;
1.1.1.11 root 11184: } else {
1.1.1.13 root 11185: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 11186: info = msdos_drive_number(path);
11187: }
1.1 root 11188: if(fd != -1) {
11189: REG16(AX) = fd;
11190: REG16(CX) = 1;
1.1.1.37 root 11191: msdos_file_handler_open(fd, path, _isatty(fd), mode, info, current_psp, sio_port, lpt_port);
1.1.1.20 root 11192: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 11193: } else {
11194: REG16(AX) = errno;
1.1.1.3 root 11195: m_CF = 1;
1.1 root 11196: }
11197: } else if(REG8(DL) & 2) {
11198: int attr = GetFileAttributes(path);
1.1.1.37 root 11199: int fd = -1;
1.1.1.11 root 11200: UINT16 info;
1.1.1.37 root 11201: int sio_port = 0;
11202: int lpt_port = 0;
1.1 root 11203:
1.1.1.11 root 11204: if(msdos_is_con_path(path)) {
1.1.1.13 root 11205: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 11206: info = 0x80d3;
1.1.1.37 root 11207: } else if((sio_port = msdos_is_comm_path(path)) != 0) {
11208: fd = msdos_open("NUL", file_mode[mode].mode);
1.1.1.14 root 11209: info = 0x80d3;
1.1.1.37 root 11210: msdos_set_comm_params(sio_port, path);
11211: } else if((lpt_port = msdos_is_prn_path(path)) != 0) {
11212: fd = msdos_open("NUL", file_mode[mode].mode);
11213: info = 0xa8c0;
1.1.1.29 root 11214: } else if(msdos_is_device_path(path)) {
1.1.1.20 root 11215: fd = msdos_open("NUL", file_mode[mode].mode);
11216: info = 0x80d3;
1.1 root 11217: } else {
11218: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
1.1.1.11 root 11219: info = msdos_drive_number(path);
1.1 root 11220: }
11221: if(fd != -1) {
11222: if(attr == -1) {
11223: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
11224: }
11225: SetFileAttributes(path, attr);
11226: REG16(AX) = fd;
11227: REG16(CX) = 3;
1.1.1.37 root 11228: msdos_file_handler_open(fd, path, _isatty(fd), 2, info, current_psp, sio_port, lpt_port);
1.1.1.20 root 11229: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 11230: } else {
11231: REG16(AX) = errno;
1.1.1.3 root 11232: m_CF = 1;
1.1 root 11233: }
11234: } else {
11235: REG16(AX) = 0x50;
1.1.1.3 root 11236: m_CF = 1;
1.1 root 11237: }
11238: } else {
11239: // file not exists
11240: if(REG8(DL) & 0x10) {
11241: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
11242:
11243: if(fd != -1) {
11244: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
11245: REG16(AX) = fd;
11246: REG16(CX) = 2;
11247: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 11248: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 11249: } else {
11250: REG16(AX) = errno;
1.1.1.3 root 11251: m_CF = 1;
1.1 root 11252: }
11253: } else {
11254: REG16(AX) = 0x02;
1.1.1.3 root 11255: m_CF = 1;
1.1 root 11256: }
11257: }
11258: } else {
11259: REG16(AX) = 0x0c;
1.1.1.3 root 11260: m_CF = 1;
1.1 root 11261: }
11262: }
11263:
11264: inline void msdos_int_21h_710dh()
11265: {
11266: // reset drive
11267: }
11268:
1.1.1.17 root 11269: inline void msdos_int_21h_7141h(int lfn)
11270: {
11271: if(REG16(SI) == 0) {
11272: msdos_int_21h_41h(lfn);
11273: return;
11274: }
11275: if(REG16(SI) != 1) {
11276: REG16(AX) = 5;
11277: m_CF = 1;
11278: }
11279: /* wild card and matching attributes... */
11280: char tmp[MAX_PATH * 2];
11281: // copy search pathname (and quick check overrun)
11282: ZeroMemory(tmp, sizeof(tmp));
11283: tmp[MAX_PATH - 1] = '\0';
11284: tmp[MAX_PATH] = 1;
11285: strncpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(DX)), MAX_PATH);
11286:
11287: if(tmp[MAX_PATH - 1] != '\0' || tmp[MAX_PATH] != 1) {
11288: REG16(AX) = 1;
11289: m_CF = 1;
11290: return;
11291: }
11292: for(char *s = tmp; *s; ++s) {
11293: if(*s == '/') {
11294: *s = '\\';
11295: }
11296: }
11297: char *tmp_name = (char *)_mbsrchr((unsigned char *)tmp, '\\');
11298: if(tmp_name) {
11299: ++tmp_name;
11300: } else {
11301: tmp_name = strchr(tmp, ':');
11302: tmp_name = tmp_name ? tmp_name + 1 : tmp;
11303: }
11304:
11305: WIN32_FIND_DATAA fd;
11306: HANDLE fh = FindFirstFileA(tmp, &fd);
11307: if(fh == INVALID_HANDLE_VALUE) {
11308: REG16(AX) = 2;
11309: m_CF = 1;
11310: return;
11311: }
11312: do {
11313: if(msdos_find_file_check_attribute(fd.dwFileAttributes, REG8(CL), REG8(CH)) && msdos_find_file_has_8dot3name(&fd)) {
11314: strcpy(tmp_name, fd.cFileName);
11315: if(remove(msdos_trimmed_path(tmp, lfn))) {
11316: REG16(AX) = 5;
11317: m_CF = 1;
11318: break;
11319: }
11320: }
11321: } while(FindNextFileA(fh, &fd));
11322: if(!m_CF) {
11323: if(GetLastError() != ERROR_NO_MORE_FILES) {
11324: m_CF = 1;
11325: REG16(AX) = 2;
11326: }
11327: }
11328: FindClose(fh);
11329: }
11330:
1.1 root 11331: inline void msdos_int_21h_714eh()
11332: {
11333: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 11334: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
11335: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 11336: WIN32_FIND_DATA fd;
11337:
1.1.1.13 root 11338: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
11339: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
11340: FindClose(dtainfo->find_handle);
11341: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 11342: }
11343: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 11344: dtainfo->allowable_mask = REG8(CL);
11345: dtainfo->required_mask = REG8(CH);
11346: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 11347:
1.1.1.14 root 11348: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
11349: dtainfo->allowable_mask &= ~8;
1.1 root 11350: }
1.1.1.14 root 11351: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
11352: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 11353: if(!FindNextFile(dtainfo->find_handle, &fd)) {
11354: FindClose(dtainfo->find_handle);
11355: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 11356: break;
11357: }
11358: }
11359: }
1.1.1.13 root 11360: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 11361: find->attrib = fd.dwFileAttributes;
11362: msdos_find_file_conv_local_time(&fd);
11363: if(REG16(SI) == 0) {
11364: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
11365: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
11366: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
11367: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
11368: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
11369: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
11370: } else {
11371: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
11372: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
11373: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
11374: }
11375: find->size_hi = fd.nFileSizeHigh;
11376: find->size_lo = fd.nFileSizeLow;
11377: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 11378: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14 root 11379: REG16(AX) = dtainfo - dtalist + 1;
11380: } else if(dtainfo->allowable_mask & 8) {
1.1 root 11381: // volume label
11382: find->attrib = 8;
11383: find->size_hi = find->size_lo = 0;
11384: strcpy(find->full_name, process->volume_label);
11385: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 11386: dtainfo->allowable_mask &= ~8;
11387: REG16(AX) = dtainfo - dtalist + 1;
1.1 root 11388: } else {
11389: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 11390: m_CF = 1;
1.1 root 11391: }
11392: }
11393:
11394: inline void msdos_int_21h_714fh()
11395: {
11396: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 11397: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 11398: WIN32_FIND_DATA fd;
11399:
1.1.1.14 root 11400: if(REG16(BX) - 1u >= MAX_DTAINFO) {
11401: REG16(AX) = 6;
1.1.1.13 root 11402: m_CF = 1;
11403: return;
11404: }
1.1.1.14 root 11405: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 11406: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
11407: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 11408: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 11409: if(!FindNextFile(dtainfo->find_handle, &fd)) {
11410: FindClose(dtainfo->find_handle);
11411: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 11412: break;
11413: }
11414: }
11415: } else {
1.1.1.13 root 11416: FindClose(dtainfo->find_handle);
11417: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 11418: }
11419: }
1.1.1.13 root 11420: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 11421: find->attrib = fd.dwFileAttributes;
11422: msdos_find_file_conv_local_time(&fd);
11423: if(REG16(SI) == 0) {
11424: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
11425: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
11426: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
11427: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
11428: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
11429: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
11430: } else {
11431: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
11432: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
11433: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
11434: }
11435: find->size_hi = fd.nFileSizeHigh;
11436: find->size_lo = fd.nFileSizeLow;
11437: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 11438: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14 root 11439: } else if(dtainfo->allowable_mask & 8) {
1.1 root 11440: // volume label
11441: find->attrib = 8;
11442: find->size_hi = find->size_lo = 0;
11443: strcpy(find->full_name, process->volume_label);
11444: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 11445: dtainfo->allowable_mask &= ~8;
1.1 root 11446: } else {
11447: REG16(AX) = 0x12;
1.1.1.3 root 11448: m_CF = 1;
1.1 root 11449: }
11450: }
11451:
11452: inline void msdos_int_21h_71a0h()
11453: {
11454: DWORD max_component_len, file_sys_flag;
11455:
1.1.1.14 root 11456: 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))) {
11457: REG16(BX) = (UINT16)file_sys_flag & (FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK | FILE_VOLUME_IS_COMPRESSED);
11458: REG16(BX) |= 0x4000; // supports LFN functions
1.1 root 11459: REG16(CX) = (UINT16)max_component_len; // 255
11460: REG16(DX) = (UINT16)max_component_len + 5; // 260
11461: } else {
11462: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 11463: m_CF = 1;
1.1 root 11464: }
11465: }
11466:
11467: inline void msdos_int_21h_71a1h()
11468: {
1.1.1.14 root 11469: if(REG16(BX) - 1u >= MAX_DTAINFO) {
11470: REG16(AX) = 6;
1.1.1.13 root 11471: m_CF = 1;
11472: return;
11473: }
1.1.1.14 root 11474: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 11475: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
11476: FindClose(dtainfo->find_handle);
11477: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 11478: }
11479: }
11480:
11481: inline void msdos_int_21h_71a6h()
11482: {
11483: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 11484: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
11485:
1.1.1.3 root 11486: UINT8 *buffer = (UINT8 *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 11487: struct _stat64 status;
11488: DWORD serial_number = 0;
11489:
1.1.1.20 root 11490: if(fd < process->max_files && file_handler[fd].valid) {
11491: if(_fstat64(fd, &status) == 0) {
11492: if(file_handler[fd].path[1] == ':') {
1.1 root 11493: // NOTE: we need to consider the network file path "\\host\share\"
11494: char volume[] = "A:\\";
1.1.1.20 root 11495: volume[0] = file_handler[fd].path[1];
1.1 root 11496: GetVolumeInformation(volume, NULL, 0, &serial_number, NULL, NULL, NULL, 0);
11497: }
1.1.1.20 root 11498: *(UINT32 *)(buffer + 0x00) = GetFileAttributes(file_handler[fd].path);
1.1 root 11499: *(UINT32 *)(buffer + 0x04) = (UINT32)(status.st_ctime & 0xffffffff);
11500: *(UINT32 *)(buffer + 0x08) = (UINT32)((status.st_ctime >> 32) & 0xffffffff);
11501: *(UINT32 *)(buffer + 0x0c) = (UINT32)(status.st_atime & 0xffffffff);
11502: *(UINT32 *)(buffer + 0x10) = (UINT32)((status.st_atime >> 32) & 0xffffffff);
11503: *(UINT32 *)(buffer + 0x14) = (UINT32)(status.st_mtime & 0xffffffff);
11504: *(UINT32 *)(buffer + 0x18) = (UINT32)((status.st_mtime >> 32) & 0xffffffff);
11505: *(UINT32 *)(buffer + 0x1c) = serial_number;
11506: *(UINT32 *)(buffer + 0x20) = (UINT32)((status.st_size >> 32) & 0xffffffff);
11507: *(UINT32 *)(buffer + 0x24) = (UINT32)(status.st_size & 0xffffffff);
11508: *(UINT32 *)(buffer + 0x28) = status.st_nlink;
1.1.1.14 root 11509: // this is dummy id and it will be changed when it is reopened...
1.1 root 11510: *(UINT32 *)(buffer + 0x2c) = 0;
1.1.1.20 root 11511: *(UINT32 *)(buffer + 0x30) = file_handler[fd].id;
1.1 root 11512: } else {
11513: REG16(AX) = errno;
1.1.1.3 root 11514: m_CF = 1;
1.1 root 11515: }
11516: } else {
11517: REG16(AX) = 0x06;
1.1.1.3 root 11518: m_CF = 1;
1.1 root 11519: }
11520: }
11521:
11522: inline void msdos_int_21h_71a7h()
11523: {
11524: switch(REG8(BL)) {
11525: case 0x00:
1.1.1.3 root 11526: if(!FileTimeToDosDateTime((FILETIME *)(mem + SREG_BASE(DS) + REG16(SI)), ®16(DX), ®16(CX))) {
1.1 root 11527: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 11528: m_CF = 1;
1.1 root 11529: }
11530: break;
11531: case 0x01:
11532: // NOTE: we need to check BH that shows 10-millisecond untils past time in CX
1.1.1.3 root 11533: if(!DosDateTimeToFileTime(REG16(DX), REG16(CX), (FILETIME *)(mem + SREG_BASE(ES) + REG16(DI)))) {
1.1 root 11534: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 11535: m_CF = 1;
1.1 root 11536: }
11537: break;
11538: default:
1.1.1.22 root 11539: 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 11540: REG16(AX) = 0x01;
1.1.1.3 root 11541: m_CF = 1;
1.1 root 11542: break;
11543: }
11544: }
11545:
11546: inline void msdos_int_21h_71a8h()
11547: {
11548: if(REG8(DH) == 0) {
11549: char tmp[MAX_PATH], fcb[MAX_PATH];
1.1.1.3 root 11550: strcpy(tmp, msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 11551: memset(fcb, 0x20, sizeof(fcb));
11552: int len = strlen(tmp);
1.1.1.21 root 11553: for(int i = 0, pos = 0; i < len; i++) {
1.1 root 11554: if(tmp[i] == '.') {
11555: pos = 8;
11556: } else {
11557: if(msdos_lead_byte_check(tmp[i])) {
11558: fcb[pos++] = tmp[i++];
11559: }
11560: fcb[pos++] = tmp[i];
11561: }
11562: }
1.1.1.3 root 11563: memcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), fcb, 11);
1.1 root 11564: } else {
1.1.1.3 root 11565: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 11566: }
11567: }
11568:
1.1.1.22 root 11569: inline void msdos_int_21h_71aah()
11570: {
11571: char drv[] = "A:", path[MAX_PATH];
11572: char *hoge=(char *)(mem + SREG_BASE(DS) + REG16(DX));
11573:
11574: if(REG8(BL) == 0) {
11575: drv[0] = 'A' + _getdrive() - 1;
11576: } else {
11577: drv[0] = 'A' + REG8(BL) - 1;
11578: }
11579: switch(REG8(BH)) {
11580: case 0x00:
11581: if(DefineDosDevice(0, drv, (char *)(mem + SREG_BASE(DS) + REG16(DX))) == 0) {
11582: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
11583: if(GetLogicalDrives() & bits) {
11584: REG16(AX) = 0x0f; // invalid drive
11585: } else {
11586: REG16(AX) = 0x03; // path not found
11587: }
11588: m_CF = 1;
11589: }
11590: break;
11591: case 0x01:
11592: if(DefineDosDevice(DDD_REMOVE_DEFINITION, drv, NULL) == 0) {
11593: REG16(AX) = 0x0f; // invalid drive
11594: m_CF = 1;
11595: }
11596: break;
11597: case 0x02:
11598: if(QueryDosDevice(drv, path, MAX_PATH) == 0) {
11599: REG16(AX) = 0x0f; // invalid drive
11600: m_CF = 1;
11601: } else if(strncmp(path, "\\??\\", 4) != 0) {
11602: REG16(AX) = 0x0f; // invalid drive
11603: m_CF = 1;
11604: } else {
11605: strcpy((char *)(mem + SREG_BASE(DS) + REG16(DX)), path + 4);
11606: }
11607: break;
11608: default:
11609: 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));
11610: REG16(AX) = 0x01;
11611: m_CF = 1;
11612: break;
11613: }
11614: }
11615:
1.1.1.14 root 11616: inline void msdos_int_21h_7300h()
11617: {
11618: if(REG8(AL) == 0) {
11619: REG8(AL) = REG8(CL);
11620: REG8(AH) = 0;
11621: } else {
11622: REG16(AX) = 0x01;
11623: m_CF = 1;
11624: }
11625: }
11626:
11627: inline void msdos_int_21h_7302h()
11628: {
11629: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
11630: UINT16 seg, ofs;
11631:
11632: if(REG16(CX) < 0x3f) {
11633: REG8(AL) = 0x18;
11634: m_CF = 1;
11635: } else if(!msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
11636: REG8(AL) = 0xff;
11637: m_CF = 1;
11638: } else {
11639: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 2, mem + (seg << 4) + ofs, sizeof(dpb_t));
11640: }
11641: }
11642:
1.1 root 11643: inline void msdos_int_21h_7303h()
11644: {
1.1.1.3 root 11645: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
11646: ext_space_info_t *info = (ext_space_info_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 11647: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
11648:
11649: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
11650: info->size_of_structure = sizeof(ext_space_info_t);
11651: info->structure_version = 0;
11652: info->sectors_per_cluster = sectors_per_cluster;
11653: info->bytes_per_sector = bytes_per_sector;
11654: info->available_clusters_on_drive = free_clusters;
11655: info->total_clusters_on_drive = total_clusters;
11656: info->available_sectors_on_drive = sectors_per_cluster * free_clusters;
11657: info->total_sectors_on_drive = sectors_per_cluster * total_clusters;
11658: info->available_allocation_units = free_clusters; // ???
11659: info->total_allocation_units = total_clusters; // ???
11660: } else {
11661: REG16(AX) = errno;
1.1.1.3 root 11662: m_CF = 1;
1.1 root 11663: }
11664: }
11665:
1.1.1.30 root 11666: inline void msdos_int_21h_dbh()
11667: {
11668: // Novell NetWare - Workstation - Get Number of Local Drives
11669: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
11670: REG8(AL) = dos_info->last_drive;
11671: }
11672:
11673: inline void msdos_int_21h_dch()
11674: {
11675: // Novell NetWare - Connection Services - Get Connection Number
11676: REG8(AL) = 0x00;
11677: }
11678:
1.1.1.32 root 11679: inline void msdos_int_24h()
11680: {
11681: const char *message = NULL;
11682: int key = 0;
11683:
11684: for(int i = 0; i < array_length(critical_error_table); i++) {
11685: if(critical_error_table[i].code == (REG16(DI) & 0xff) || critical_error_table[i].code == (UINT16)-1) {
11686: if(active_code_page == 932) {
11687: message = critical_error_table[i].message_japanese;
11688: }
11689: if(message == NULL) {
11690: message = critical_error_table[i].message_english;
11691: }
11692: *(UINT8 *)(mem + WORK_TOP) = strlen(message);
11693: strcpy((char *)(mem + WORK_TOP + 1), message);
11694:
11695: SREG(ES) = WORK_TOP >> 4;
11696: i386_load_segment_descriptor(ES);
11697: REG16(DI) = 0x0000;
11698: break;
11699: }
11700: }
11701: fprintf(stderr, "\n%s", message);
11702: if(!(REG8(AH) & 0x80)) {
11703: if(REG8(AH) & 0x01) {
11704: fprintf(stderr, " %s %c", (active_code_page == 932) ? "�������ݒ� �h���C�u" : "writing drive", 'A' + REG8(AL));
11705: } else {
11706: fprintf(stderr, " %s %c", (active_code_page == 932) ? "�ǂݎ�蒆 �h���C�u" : "reading drive", 'A' + REG8(AL));
11707: }
11708: }
11709: fprintf(stderr, "\n");
11710:
1.1.1.33 root 11711: {
1.1.1.32 root 11712: fprintf(stderr, "%s", (active_code_page == 932) ? "���~ (A)" : "Abort");
1.1.1.33 root 11713: }
1.1.1.32 root 11714: if(REG8(AH) & 0x10) {
11715: fprintf(stderr, ", %s", (active_code_page == 932) ? "���s (R)" : "Retry");
11716: }
11717: if(REG8(AH) & 0x20) {
11718: fprintf(stderr, ", %s", (active_code_page == 932) ? "���� (I)" : "Ignore");
11719: }
11720: if(REG8(AH) & 0x08) {
11721: fprintf(stderr, ", %s", (active_code_page == 932) ? "���s (F)" : "Fail");
11722: }
11723: fprintf(stderr, "? ");
11724:
11725: while(1) {
11726: while(!_kbhit()) {
11727: Sleep(10);
11728: }
11729: key = _getch();
11730:
11731: if(key == 'I' || key == 'i') {
11732: if(REG8(AH) & 0x20) {
11733: REG8(AL) = 0;
11734: break;
11735: }
11736: } else if(key == 'R' || key == 'r') {
11737: if(REG8(AH) & 0x10) {
11738: REG8(AL) = 1;
11739: break;
11740: }
11741: } else if(key == 'A' || key == 'a') {
11742: REG8(AL) = 2;
11743: break;
11744: } else if(key == 'F' || key == 'f') {
11745: if(REG8(AH) & 0x08) {
11746: REG8(AL) = 3;
11747: break;
11748: }
11749: }
11750: }
11751: fprintf(stderr, "%c\n", key);
11752: }
11753:
1.1 root 11754: inline void msdos_int_25h()
11755: {
11756: UINT16 seg, ofs;
11757: DWORD dwSize;
11758:
1.1.1.3 root 11759: #if defined(HAS_I386)
11760: I386OP(pushf)();
11761: #else
11762: PREFIX86(_pushf());
11763: #endif
1.1 root 11764:
11765: if(!(REG8(AL) < 26)) {
11766: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 11767: m_CF = 1;
1.1 root 11768: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
11769: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 11770: m_CF = 1;
1.1 root 11771: } else {
11772: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
11773: char dev[64];
11774: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
11775:
11776: HANDLE hFile = CreateFile(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
11777: if(hFile == INVALID_HANDLE_VALUE) {
11778: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 11779: m_CF = 1;
1.1 root 11780: } else {
1.1.1.19 root 11781: UINT32 top_sector = REG16(DX);
11782: UINT16 sector_num = REG16(CX);
11783: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX);
11784:
11785: if(sector_num == 0xffff) {
11786: top_sector = *(UINT32 *)(mem + buffer_addr + 0);
11787: sector_num = *(UINT16 *)(mem + buffer_addr + 4);
11788: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6);
11789: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8);
11790: buffer_addr = (seg << 4) + ofs;
11791: }
11792: // if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
11793: // REG8(AL) = 0x02; // drive not ready
11794: // m_CF = 1;
11795: // } else
11796: if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1.1 root 11797: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 11798: m_CF = 1;
1.1.1.19 root 11799: } else if(ReadFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 11800: REG8(AL) = 0x0b; // read error
1.1.1.3 root 11801: m_CF = 1;
1.1 root 11802: }
11803: CloseHandle(hFile);
11804: }
11805: }
11806: }
11807:
11808: inline void msdos_int_26h()
11809: {
11810: // this operation may cause serious damage for drives, so always returns error...
11811: UINT16 seg, ofs;
11812: DWORD dwSize;
11813:
1.1.1.3 root 11814: #if defined(HAS_I386)
11815: I386OP(pushf)();
11816: #else
11817: PREFIX86(_pushf());
11818: #endif
1.1 root 11819:
11820: if(!(REG8(AL) < 26)) {
11821: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 11822: m_CF = 1;
1.1 root 11823: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
11824: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 11825: m_CF = 1;
1.1 root 11826: } else {
11827: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
11828: char dev[64];
11829: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
11830:
11831: if(dpb->media_type == 0xf8) {
11832: // this drive is not a floppy
1.1.1.6 root 11833: // if(!(((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag & 0x40)) {
11834: // fatalerror("This application tried the absolute disk write to drive %c:\n", 'A' + REG8(AL));
11835: // }
1.1 root 11836: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 11837: m_CF = 1;
1.1 root 11838: } else {
11839: HANDLE hFile = CreateFile(dev, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
11840: if(hFile == INVALID_HANDLE_VALUE) {
11841: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 11842: m_CF = 1;
1.1 root 11843: } else {
1.1.1.19 root 11844: UINT32 top_sector = REG16(DX);
11845: UINT16 sector_num = REG16(CX);
11846: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX);
11847:
11848: if(sector_num == 0xffff) {
11849: top_sector = *(UINT32 *)(mem + buffer_addr + 0);
11850: sector_num = *(UINT16 *)(mem + buffer_addr + 4);
11851: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6);
11852: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8);
11853: buffer_addr = (seg << 4) + ofs;
11854: }
1.1 root 11855: if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
11856: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 11857: m_CF = 1;
1.1.1.19 root 11858: } else if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1.1 root 11859: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 11860: m_CF = 1;
1.1.1.19 root 11861: } else if(WriteFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 11862: REG8(AL) = 0x0a; // write error
1.1.1.3 root 11863: m_CF = 1;
1.1 root 11864: }
11865: CloseHandle(hFile);
11866: }
11867: }
11868: }
11869: }
11870:
11871: inline void msdos_int_27h()
11872: {
1.1.1.29 root 11873: int paragraphs = (min(REG16(DX), 0xfff0) + 15) >> 4;
11874: try {
11875: msdos_mem_realloc(SREG(CS), paragraphs, NULL);
11876: } catch(...) {
11877: // recover the broken mcb
11878: int mcb_seg = SREG(CS) - 1;
11879: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1.1.33 root 11880:
1.1.1.29 root 11881: if(mcb_seg < (MEMORY_END >> 4)) {
1.1.1.33 root 11882: mcb->mz = 'M';
11883: mcb->paragraphs = (MEMORY_END >> 4) - mcb_seg - 2;
11884:
1.1.1.29 root 11885: if(((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked & 0x01) {
1.1.1.39 root 11886: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', PSP_SYSTEM, (UMB_TOP >> 4) - (MEMORY_END >> 4), "SC");
1.1.1.29 root 11887: } else {
1.1.1.39 root 11888: msdos_mcb_create((MEMORY_END >> 4) - 1, 'Z', PSP_SYSTEM, 0, "SC");
1.1.1.29 root 11889: }
11890: } else {
11891: mcb->mz = 'Z';
1.1.1.30 root 11892: mcb->paragraphs = (UMB_END >> 4) - mcb_seg - 1;
1.1.1.29 root 11893: }
11894: msdos_mem_realloc(SREG(CS), paragraphs, NULL);
11895: }
1.1.1.3 root 11896: msdos_process_terminate(SREG(CS), retval | 0x300, 0);
1.1 root 11897: }
11898:
11899: inline void msdos_int_29h()
11900: {
1.1.1.14 root 11901: #if 1
11902: // need to check escape sequences
1.1 root 11903: msdos_putch(REG8(AL));
1.1.1.14 root 11904: #else
11905: DWORD num;
11906: vram_flush();
1.1.1.23 root 11907: WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ®8(AL), 1, &num, NULL);
1.1.1.14 root 11908: cursor_moved = true;
11909: #endif
1.1 root 11910: }
11911:
11912: inline void msdos_int_2eh()
11913: {
11914: char tmp[MAX_PATH], command[MAX_PATH], opt[MAX_PATH];
11915: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 11916: strcpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(SI)));
1.1 root 11917: char *token = my_strtok(tmp, " ");
11918: strcpy(command, token);
11919: strcpy(opt, token + strlen(token) + 1);
11920:
11921: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
11922: param->env_seg = 0;
11923: param->cmd_line.w.l = 44;
11924: param->cmd_line.w.h = (WORK_TOP >> 4);
11925: param->fcb1.w.l = 24;
11926: param->fcb1.w.h = (WORK_TOP >> 4);
11927: param->fcb2.w.l = 24;
11928: param->fcb2.w.h = (WORK_TOP >> 4);
11929:
11930: memset(mem + WORK_TOP + 24, 0x20, 20);
11931:
11932: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
11933: cmd_line->len = strlen(opt);
11934: strcpy(cmd_line->cmd, opt);
11935: cmd_line->cmd[cmd_line->len] = 0x0d;
11936:
1.1.1.28 root 11937: try {
11938: if(msdos_process_exec(command, param, 0)) {
11939: REG16(AX) = 0xffff; // error before processing command
11940: } else {
11941: // set flag to set retval to ax when the started process is terminated
11942: process_t *process = msdos_process_info_get(current_psp);
11943: process->called_by_int2eh = true;
11944: }
11945: } catch(...) {
11946: REG16(AX) = 0xffff; // error before processing command
11947: }
1.1 root 11948: }
11949:
1.1.1.29 root 11950: inline void msdos_int_2fh_05h()
11951: {
11952: switch(REG8(AL)) {
11953: case 0x00:
1.1.1.32 root 11954: REG8(AL) = 0xff;
11955: break;
11956: case 0x01:
11957: case 0x02:
11958: for(int i = 0; i < array_length(standard_error_table); i++) {
11959: if(standard_error_table[i].code == REG16(BX) || standard_error_table[i].code == (UINT16)-1) {
11960: const char *message = NULL;
11961: if(active_code_page == 932) {
11962: message = standard_error_table[i].message_japanese;
11963: }
11964: if(message == NULL) {
11965: message = standard_error_table[i].message_english;
11966: }
11967: strcpy((char *)(mem + WORK_TOP), message);
11968:
11969: SREG(ES) = WORK_TOP >> 4;
11970: i386_load_segment_descriptor(ES);
11971: REG16(DI) = 0x0000;
11972: REG8(AL) = 0x01;
11973: break;
11974: }
11975: }
1.1.1.29 root 11976: break;
11977: default:
11978: 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));
11979: m_CF = 1;
11980: }
11981: }
11982:
1.1.1.22 root 11983: inline void msdos_int_2fh_11h()
11984: {
11985: switch(REG8(AL)) {
11986: case 0x00:
1.1.1.29 root 11987: if(i386_read_stack() == 0xdada) {
11988: // MSCDEX is not installed
11989: // REG8(AL) = 0x00;
11990: } else {
11991: // Network Redirector is not installed
11992: // REG8(AL) = 0x00;
11993: }
1.1.1.22 root 11994: break;
11995: default:
11996: 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 11997: REG16(AX) = 0x49; // network software not installed
1.1.1.22 root 11998: m_CF = 1;
11999: break;
12000: }
12001: }
12002:
1.1.1.21 root 12003: inline void msdos_int_2fh_12h()
12004: {
12005: switch(REG8(AL)) {
1.1.1.22 root 12006: case 0x00:
1.1.1.29 root 12007: // DOS 3.0+ internal functions are installed
1.1.1.22 root 12008: REG8(AL) = 0xff;
12009: break;
1.1.1.29 root 12010: // case 0x01: // DOS 3.0+ internal - Close Current File
12011: case 0x02:
12012: {
12013: UINT16 stack = i386_read_stack();
12014: REG16(BX) = *(UINT16 *)(mem + 4 * stack + 0);
12015: SREG(ES) = *(UINT16 *)(mem + 4 * stack + 2);
12016: i386_load_segment_descriptor(ES);
12017: }
12018: break;
1.1.1.30 root 12019: case 0x03:
12020: SREG(DS) = (DEVICE_TOP >> 4);
12021: i386_load_segment_descriptor(DS);
12022: break;
1.1.1.29 root 12023: case 0x04:
12024: {
12025: UINT16 stack = i386_read_stack();
12026: REG8(AL) = (stack == '/') ? '\\' : stack;
12027: #if defined(HAS_I386)
12028: m_ZF = (REG8(AL) == '\\');
12029: #else
12030: m_ZeroVal = (REG8(AL) != '\\');
12031: #endif
12032: }
12033: break;
12034: case 0x05:
12035: msdos_putch(i386_read_stack());
12036: break;
12037: // case 0x06: // DOS 3.0+ internal - Invole Critical Error
12038: // case 0x07: // DOS 3.0+ internal - Make Disk Buffer Most Recentry Used
12039: // case 0x08: // DOS 3.0+ internal - Decrement SFT Reference Count
12040: // case 0x09: // DOS 3.0+ internal - Flush and FREE Disk Buffer
12041: // case 0x0a: // DOS 3.0+ internal - Perform Critical Error Interrupt
12042: // case 0x0b: // DOS 3.0+ internal - Signal Sharing Violation to User
12043: // case 0x0c: // DOS 3.0+ internal - Open Device and Set SFT Owner/Mode
12044: case 0x0d:
12045: {
12046: SYSTEMTIME time;
12047: FILETIME file_time;
12048: WORD dos_date, dos_time;
12049: GetLocalTime(&time);
12050: SystemTimeToFileTime(&time, &file_time);
12051: FileTimeToDosDateTime(&file_time, &dos_date, &dos_time);
12052: REG16(AX) = dos_date;
12053: REG16(DX) = dos_time;
12054: }
12055: break;
12056: // case 0x0e: // DOS 3.0+ internal - Mark All Disk Buffers Unreferenced
12057: // case 0x0f: // DOS 3.0+ internal - Make Buffer Most Recentry Used
12058: // case 0x10: // DOS 3.0+ internal - Find Unreferenced Disk Buffer
12059: case 0x11:
12060: {
12061: char path[MAX_PATH], *p;
12062: strcpy(path, (char *)(mem + SREG_BASE(DS) + REG16(SI)));
12063: my_strupr(path);
12064: while((p = my_strchr(path, '/')) != NULL) {
12065: *p = '\\';
12066: }
12067: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), path);
12068: }
12069: break;
12070: case 0x12:
12071: REG16(CX) = strlen((char *)(mem + SREG_BASE(ES) + REG16(DI)));
12072: break;
12073: case 0x13:
12074: {
12075: char tmp[2] = {0};
12076: tmp[0] = i386_read_stack();
12077: my_strupr(tmp);
12078: REG8(AL) = tmp[0];
12079: }
12080: break;
12081: case 0x14:
12082: #if defined(HAS_I386)
12083: m_ZF = (SREG_BASE(DS) + REG16(SI) == SREG_BASE(ES) + REG16(DI));
12084: #else
12085: m_ZeroVal = (SREG_BASE(DS) + REG16(SI) != SREG_BASE(ES) + REG16(DI));
12086: #endif
12087: m_CF = (SREG_BASE(DS) + REG16(SI) != SREG_BASE(ES) + REG16(DI));
12088: break;
12089: // case 0x15: // DOS 3.0+ internal - Flush Buffer
1.1.1.21 root 12090: case 0x16:
12091: if(REG16(BX) < 20) {
12092: SREG(ES) = SFT_TOP >> 4;
12093: i386_load_segment_descriptor(ES);
12094: REG16(DI) = 6 + 0x3b * REG16(BX);
12095:
12096: // update system file table
12097: UINT8* sft = mem + SFT_TOP + 6 + 0x3b * REG16(BX);
12098: if(file_handler[REG16(BX)].valid) {
12099: int count = 0;
12100: for(int i = 0; i < 20; i++) {
12101: if(msdos_psp_get_file_table(i, current_psp) == REG16(BX)) {
12102: count++;
12103: }
12104: }
12105: *(UINT16 *)(sft + 0x00) = count ? count : 0xffff;
12106: *(UINT32 *)(sft + 0x15) = _tell(REG16(BX));
12107: _lseek(REG16(BX), 0, SEEK_END);
12108: *(UINT32 *)(sft + 0x11) = _tell(REG16(BX));
12109: _lseek(REG16(BX), *(UINT32 *)(sft + 0x15), SEEK_SET);
12110: } else {
12111: memset(sft, 0, 0x3b);
12112: }
12113: } else {
12114: REG16(AX) = 0x06;
12115: m_CF = 1;
12116: }
12117: break;
1.1.1.29 root 12118: // case 0x17: // DOS 3.0+ internal - Get Current Directory Structure for Drive
12119: // case 0x18: // DOS 3.0+ internal - Get Caller's Registers
12120: // case 0x19: // DOS 3.0+ internal - Set Drive???
12121: case 0x1a:
12122: {
12123: char *path = (char *)(mem + SREG_BASE(DS) + REG16(SI)), full[MAX_PATH];
12124: if(path[1] == ':') {
12125: if(path[0] >= 'a' && path[0] <= 'z') {
12126: REG8(AL) = path[0] - 'a' + 1;
12127: } else if(path[0] >= 'A' && path[0] <= 'Z') {
12128: REG8(AL) = path[0] - 'A' + 1;
12129: } else {
12130: REG8(AL) = 0xff; // invalid
12131: }
12132: strcpy(full, path);
12133: strcpy(path, full + 2);
12134: } else if(GetFullPathName(path, MAX_PATH, full, NULL) != 0 && full[1] == ':') {
12135: if(full[0] >= 'a' && full[0] <= 'z') {
12136: REG8(AL) = full[0] - 'a' + 1;
12137: } else if(full[0] >= 'A' && full[0] <= 'Z') {
12138: REG8(AL) = full[0] - 'A' + 1;
12139: } else {
12140: REG8(AL) = 0xff; // invalid
12141: }
12142: } else {
12143: REG8(AL) = 0x00; // default
12144: }
12145: }
12146: break;
12147: case 0x1b:
12148: {
12149: int year = REG16(CX) + 1980;
12150: REG8(AL) = ((year % 4) == 0 && (year % 100) != 0 && (year % 400) == 0) ? 29 : 28;
12151: }
12152: break;
12153: // case 0x1c: // DOS 3.0+ internal - Check Sum Memory
12154: // case 0x1d: // DOS 3.0+ internal - Sum Memory
12155: case 0x1e:
12156: {
12157: char *path_1st = (char *)(mem + SREG_BASE(DS) + REG16(SI)), full_1st[MAX_PATH];
12158: char *path_2nd = (char *)(mem + SREG_BASE(ES) + REG16(DI)), full_2nd[MAX_PATH];
12159: if(GetFullPathName(path_1st, MAX_PATH, full_1st, NULL) != 0 && GetFullPathName(path_2nd, MAX_PATH, full_2nd, NULL) != 0) {
12160: #if defined(HAS_I386)
12161: m_ZF = (strcmp(full_1st, full_2nd) == 0);
12162: #else
12163: m_ZeroVal = (strcmp(full_1st, full_2nd) != 0);
12164: #endif
12165: } else {
12166: #if defined(HAS_I386)
12167: m_ZF = (strcmp(path_1st, path_2nd) == 0);
12168: #else
12169: m_ZeroVal = (strcmp(path_1st, path_2nd) != 0);
12170: #endif
12171: }
12172: }
12173: break;
12174: // case 0x1f: // DOS 3.0+ internal - Build Current Directory Structure
1.1.1.21 root 12175: case 0x20:
12176: {
12177: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
12178:
12179: if(fd < 20) {
12180: SREG(ES) = current_psp;
12181: i386_load_segment_descriptor(ES);
12182: REG16(DI) = offsetof(psp_t, file_table) + fd;
12183: } else {
12184: REG16(AX) = 0x06;
12185: m_CF = 1;
12186: }
12187: }
12188: break;
1.1.1.29 root 12189: case 0x21:
12190: msdos_int_21h_60h(0);
12191: break;
12192: // case 0x22: // DOS 3.0+ internal - Set Extended Error Info
12193: // case 0x23: // DOS 3.0+ internal - Check If Character Device
12194: // case 0x24: // DOS 3.0+ internal - Sharing Retry Delay
12195: case 0x25:
12196: REG16(CX) = strlen((char *)(mem + SREG_BASE(DS) + REG16(SI)));
12197: break;
12198: case 0x26:
12199: REG8(AL) = REG8(CL);
12200: msdos_int_21h_3dh();
12201: break;
12202: case 0x27:
12203: msdos_int_21h_3eh();
12204: break;
12205: case 0x28:
12206: REG16(AX) = REG16(BP);
12207: msdos_int_21h_42h();
12208: break;
12209: case 0x29:
12210: msdos_int_21h_3fh();
12211: break;
12212: // case 0x2a: // DOS 3.0+ internal - Set Fast Open Entry Point
12213: case 0x2b:
12214: REG16(AX) = REG16(BP);
12215: msdos_int_21h_44h();
12216: break;
12217: case 0x2c:
12218: REG16(BX) = DEVICE_TOP >> 4;
12219: REG16(AX) = 22;
12220: break;
12221: case 0x2d:
12222: {
12223: sda_t *sda = (sda_t *)(mem + SDA_TOP);
12224: REG16(AX) = sda->extended_error_code;
12225: }
12226: break;
12227: case 0x2e:
12228: if(REG8(DL) == 0x00 || REG8(DL) == 0x02 || REG8(DL) == 0x04 || REG8(DL) == 0x06) {
1.1.1.32 root 12229: SREG(ES) = 0x0001;
12230: i386_load_segment_descriptor(ES);
12231: REG16(DI) = 0x00;
12232: } else if(REG8(DL) == 0x08) {
12233: // dummy parameter error message read routine is at fffd:0010
12234: SREG(ES) = 0xfffd;
1.1.1.22 root 12235: i386_load_segment_descriptor(ES);
1.1.1.32 root 12236: REG16(DI) = 0x0010;
1.1.1.22 root 12237: }
12238: break;
1.1.1.29 root 12239: case 0x2f:
12240: if(REG16(DX) != 0) {
1.1.1.30 root 12241: dos_major_version = REG8(DL);
12242: dos_minor_version = REG8(DH);
1.1.1.29 root 12243: } else {
12244: REG8(DL) = 7;
12245: REG8(DH) = 10;
12246: }
12247: break;
12248: // case 0x30: // Windows95 - Find SFT Entry in Internal File Tables
12249: // case 0x31: // Windows95 - Set/Clear "Report Windows to DOS Programs" Flag
1.1.1.22 root 12250: default:
12251: 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));
12252: REG16(AX) = 0x01;
12253: m_CF = 1;
12254: break;
12255: }
12256: }
12257:
1.1.1.30 root 12258: inline void msdos_int_2fh_13h()
12259: {
12260: static UINT16 prevDS = 0, prevDX = 0;
12261: static UINT16 prevES = 0, prevBX = 0;
12262: UINT16 tmp;
12263:
12264: tmp = SREG(DS); SREG(DS) = prevDS; prevDS = tmp;
12265: i386_load_segment_descriptor(DS);
12266: tmp = REG16(DX); REG16(DX) = prevDX; prevDX = tmp;
12267:
12268: tmp = SREG(ES); SREG(ES) = prevES; prevES = tmp;
12269: i386_load_segment_descriptor(ES);
12270: tmp = REG16(BX); REG16(BX) = prevBX; prevBX = tmp;
12271: }
12272:
1.1.1.22 root 12273: inline void msdos_int_2fh_14h()
12274: {
12275: switch(REG8(AL)) {
12276: case 0x00:
1.1.1.29 root 12277: // NLSFUNC.COM is installed
12278: REG8(AL) = 0xff;
1.1.1.25 root 12279: break;
12280: case 0x01:
12281: case 0x03:
12282: REG8(AL) = 0x00;
12283: active_code_page = REG16(BX);
12284: msdos_nls_tables_update();
12285: break;
12286: case 0x02:
12287: REG8(AL) = get_extended_country_info(REG16(BP));
12288: break;
12289: case 0x04:
12290: REG8(AL) = 0x00;
12291: get_country_info((country_info_t *)(mem + SREG_BASE(ES) + REG16(DI)));
1.1.1.22 root 12292: break;
12293: default:
12294: 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));
12295: REG16(AX) = 0x01;
12296: m_CF = 1;
12297: break;
12298: }
12299: }
12300:
12301: inline void msdos_int_2fh_15h()
12302: {
12303: switch(REG8(AL)) {
1.1.1.29 root 12304: case 0x00: // CD-ROM - Installation Check
12305: if(REG16(BX) == 0x0000) {
12306: // MSCDEX is not installed
12307: // REG8(AL) = 0x00;
12308: } else {
12309: // GRAPHICS.COM is not installed
12310: // REG8(AL) = 0x00;
12311: }
1.1.1.22 root 12312: break;
12313: case 0xff:
1.1.1.29 root 12314: if(REG16(BX) == 0x0000) {
12315: // CORELCDX is not installed
12316: } else {
12317: 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));
12318: REG16(AX) = 0x01;
12319: m_CF = 1;
12320: }
1.1.1.22 root 12321: break;
1.1.1.21 root 12322: default:
1.1.1.22 root 12323: 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 12324: REG16(AX) = 0x01;
12325: m_CF = 1;
12326: break;
12327: }
12328: }
12329:
1.1 root 12330: inline void msdos_int_2fh_16h()
12331: {
12332: switch(REG8(AL)) {
12333: case 0x00:
1.1.1.14 root 12334: if(no_windows) {
1.1.1.29 root 12335: // neither Windows 3.x enhanced mode nor Windows/386 2.x running
12336: // REG8(AL) = 0x00;
1.1.1.14 root 12337: } else {
1.1.1.30 root 12338: REG8(AL) = win_major_version;
12339: REG8(AH) = win_minor_version;
1.1 root 12340: }
12341: break;
1.1.1.30 root 12342: case 0x05:
12343: // from DOSBox
12344: i386_set_a20_line(1);
12345: break;
1.1.1.22 root 12346: case 0x0a:
12347: if(!no_windows) {
12348: REG16(AX) = 0x0000;
1.1.1.30 root 12349: REG8(BH) = win_major_version;
12350: REG8(BL) = win_minor_version;
1.1.1.22 root 12351: REG16(CX) = 0x0003; // enhanced
12352: }
12353: break;
1.1.1.30 root 12354: case 0x0b:
12355: // no TRS, keep ES:DI = 0000h:0000h
1.1.1.22 root 12356: case 0x0e:
12357: case 0x0f:
1.1.1.30 root 12358: case 0x10:
1.1.1.22 root 12359: case 0x11:
12360: case 0x12:
12361: case 0x13:
12362: case 0x14:
1.1.1.30 root 12363: case 0x15:
1.1.1.33 root 12364: case 0x86:
1.1.1.22 root 12365: case 0x87:
1.1.1.30 root 12366: case 0x89:
1.1.1.33 root 12367: case 0x8a:
1.1.1.22 root 12368: // function not supported, do not clear AX
12369: break;
1.1.1.14 root 12370: case 0x80:
12371: Sleep(10);
1.1.1.35 root 12372: REQUEST_HARDWRE_UPDATE();
1.1.1.29 root 12373: REG8(AL) = 0x00;
1.1.1.14 root 12374: break;
1.1.1.33 root 12375: case 0x83:
12376: REG16(BX) = 0x01; // system vm id
12377: break;
1.1.1.22 root 12378: case 0x8e:
12379: REG16(AX) = 0x00; // failed
12380: break;
1.1.1.20 root 12381: case 0x8f:
12382: switch(REG8(DH)) {
12383: case 0x00:
12384: case 0x02:
12385: case 0x03:
12386: REG16(AX) = 0x00;
12387: break;
12388: case 0x01:
12389: REG16(AX) = 0x168f;
12390: break;
12391: }
12392: break;
1.1 root 12393: default:
1.1.1.22 root 12394: 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));
12395: REG16(AX) = 0x01;
12396: m_CF = 1;
12397: break;
12398: }
12399: }
12400:
12401: inline void msdos_int_2fh_19h()
12402: {
12403: switch(REG8(AL)) {
12404: case 0x00:
1.1.1.29 root 12405: // SHELLB.COM is not installed
12406: // REG8(AL) = 0x00;
1.1.1.22 root 12407: break;
12408: case 0x01:
12409: case 0x02:
12410: case 0x03:
12411: case 0x04:
12412: REG16(AX) = 0x01;
12413: m_CF = 1;
12414: break;
1.1.1.29 root 12415: case 0x80:
12416: // IBM ROM-DOS v4.0 is not installed
12417: // REG8(AL) = 0x00;
12418: break;
1.1.1.22 root 12419: default:
12420: 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 12421: REG16(AX) = 0x01;
1.1.1.3 root 12422: m_CF = 1;
1.1 root 12423: break;
12424: }
12425: }
12426:
12427: inline void msdos_int_2fh_1ah()
12428: {
12429: switch(REG8(AL)) {
12430: case 0x00:
1.1.1.29 root 12431: // ANSI.SYS is installed
1.1 root 12432: REG8(AL) = 0xff;
12433: break;
12434: default:
1.1.1.22 root 12435: 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));
12436: REG16(AX) = 0x01;
12437: m_CF = 1;
12438: break;
12439: }
12440: }
12441:
1.1.1.30 root 12442: inline void msdos_int_2fh_40h()
1.1.1.22 root 12443: {
12444: switch(REG8(AL)) {
12445: case 0x00:
1.1.1.30 root 12446: // Windows 3+ - Get Virtual Device Driver (VDD) Capabilities
12447: REG8(AL) = 0x01; // does not virtualize video access
1.1.1.22 root 12448: break;
12449: default:
12450: 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 12451: REG16(AX) = 0x01;
1.1.1.3 root 12452: m_CF = 1;
1.1 root 12453: break;
12454: }
12455: }
12456:
12457: inline void msdos_int_2fh_43h()
12458: {
12459: switch(REG8(AL)) {
12460: case 0x00:
1.1.1.29 root 12461: // XMS is installed ?
1.1.1.19 root 12462: #ifdef SUPPORT_XMS
12463: if(support_xms) {
12464: REG8(AL) = 0x80;
12465: } else
12466: #endif
12467: REG8(AL) = 0x00;
12468: break;
12469: case 0x10:
12470: SREG(ES) = XMS_TOP >> 4;
12471: i386_load_segment_descriptor(ES);
1.1.1.26 root 12472: REG16(BX) = 0x15;
1.1 root 12473: break;
12474: default:
1.1.1.22 root 12475: 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));
12476: REG16(AX) = 0x01;
12477: m_CF = 1;
12478: break;
12479: }
12480: }
12481:
12482: inline void msdos_int_2fh_46h()
12483: {
12484: switch(REG8(AL)) {
12485: case 0x80:
1.1.1.29 root 12486: // Windows v3.0 is not installed
12487: // REG8(AL) = 0x00;
1.1.1.22 root 12488: break;
12489: default:
12490: 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));
12491: REG16(AX) = 0x01;
12492: m_CF = 1;
12493: break;
12494: }
12495: }
12496:
12497: inline void msdos_int_2fh_48h()
12498: {
12499: switch(REG8(AL)) {
12500: case 0x00:
1.1.1.29 root 12501: // DOSKEY is not installed
12502: // REG8(AL) = 0x00;
1.1.1.22 root 12503: break;
12504: case 0x10:
12505: msdos_int_21h_0ah();
12506: REG16(AX) = 0x00;
12507: break;
12508: default:
12509: 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 12510: REG16(AX) = 0x01;
1.1.1.3 root 12511: m_CF = 1;
1.1 root 12512: break;
12513: }
12514: }
12515:
12516: inline void msdos_int_2fh_4ah()
12517: {
12518: switch(REG8(AL)) {
1.1.1.29 root 12519: #ifdef SUPPORT_HMA
12520: case 0x01: // DOS 5.0+ - Query Free HMA Space
12521: if(!is_hma_used_by_xms && !is_hma_used_by_int_2fh) {
12522: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
12523: // restore first free mcb in high memory area
12524: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
12525: }
12526: int offset = 0xffff;
12527: if((REG16(BX) = msdos_hma_mem_get_free(&offset)) != 0) {
12528: REG16(DI) = offset + 0x10;
12529: } else {
12530: REG16(DI) = 0xffff;
12531: }
12532: } else {
12533: // HMA is already used
12534: REG16(BX) = 0;
12535: REG16(DI) = 0xffff;
12536: }
12537: SREG(ES) = 0xffff;
12538: i386_load_segment_descriptor(ES);
12539: break;
12540: case 0x02: // DOS 5.0+ - Allocate HMA Space
12541: if(!is_hma_used_by_xms && !is_hma_used_by_int_2fh) {
12542: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
12543: // restore first free mcb in high memory area
12544: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
12545: }
12546: int size = REG16(BX), offset;
12547: if((size % 16) != 0) {
12548: size &= ~15;
12549: size += 16;
12550: }
12551: if((offset = msdos_hma_mem_alloc(size, current_psp)) != -1) {
12552: REG16(BX) = size;
12553: REG16(DI) = offset + 0x10;
12554: is_hma_used_by_int_2fh = true;
12555: } else {
12556: REG16(BX) = 0;
12557: REG16(DI) = 0xffff;
12558: }
12559: } else {
12560: // HMA is already used
12561: REG16(BX) = 0;
12562: REG16(DI) = 0xffff;
12563: }
12564: SREG(ES) = 0xffff;
12565: i386_load_segment_descriptor(ES);
12566: break;
12567: case 0x03: // Windows95 - (De)Allocate HMA Memory Block
12568: if(REG8(DL) == 0x00) {
12569: if(!is_hma_used_by_xms) {
12570: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
12571: // restore first free mcb in high memory area
12572: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
12573: is_hma_used_by_int_2fh = false;
12574: }
12575: int size = REG16(BX), offset;
12576: if((size % 16) != 0) {
12577: size &= ~15;
12578: size += 16;
12579: }
12580: if((offset = msdos_hma_mem_alloc(size, REG16(CX))) != -1) {
12581: // REG16(BX) = size;
12582: SREG(ES) = 0xffff;
12583: i386_load_segment_descriptor(ES);
12584: REG16(DI) = offset + 0x10;
12585: is_hma_used_by_int_2fh = true;
12586: } else {
12587: REG16(DI) = 0xffff;
12588: }
12589: } else {
12590: REG16(DI) = 0xffff;
12591: }
12592: } else if(REG8(DL) == 0x01) {
12593: if(!is_hma_used_by_xms) {
12594: int size = REG16(BX);
12595: if((size % 16) != 0) {
12596: size &= ~15;
12597: size += 16;
12598: }
12599: if(msdos_hma_mem_realloc(SREG_BASE(ES) + REG16(DI) - 0xffff0 - 0x10, size) != -1) {
12600: // memory block address is not changed
12601: } else {
12602: REG16(DI) = 0xffff;
12603: }
12604: } else {
12605: REG16(DI) = 0xffff;
12606: }
12607: } else if(REG8(DL) == 0x02) {
12608: if(!is_hma_used_by_xms) {
12609: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
12610: // restore first free mcb in high memory area
12611: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
12612: is_hma_used_by_int_2fh = false;
12613: } else {
12614: msdos_hma_mem_free(SREG_BASE(ES) + REG16(DI) - 0xffff0 - 0x10);
12615: if(msdos_hma_mem_get_free(NULL) == 0xffe0) {
12616: is_hma_used_by_int_2fh = false;
12617: }
12618: }
12619: }
12620: } else {
12621: 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));
12622: REG16(AX) = 0x01;
12623: m_CF = 1;
12624: }
12625: break;
12626: case 0x04: // Windows95 - Get Start of HMA Memory Chain
12627: if(!is_hma_used_by_xms) {
12628: if(!msdos_is_hma_mcb_valid((hma_mcb_t *)(mem + 0xffff0 + 0x10))) {
12629: // restore first free mcb in high memory area
12630: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
12631: is_hma_used_by_int_2fh = false;
12632: }
12633: REG16(AX) = 0x0000;
12634: SREG(ES) = 0xffff;
12635: i386_load_segment_descriptor(ES);
12636: REG16(DI) = 0x10;
12637: }
12638: break;
12639: #else
1.1 root 12640: case 0x01:
12641: case 0x02:
1.1.1.29 root 12642: // HMA is already used
1.1.1.27 root 12643: REG16(BX) = 0x0000;
1.1.1.3 root 12644: SREG(ES) = 0xffff;
12645: i386_load_segment_descriptor(ES);
1.1 root 12646: REG16(DI) = 0xffff;
12647: break;
1.1.1.19 root 12648: case 0x03:
12649: // unable to allocate
12650: REG16(DI) = 0xffff;
12651: break;
12652: case 0x04:
12653: // function not supported, do not clear AX
12654: break;
1.1.1.29 root 12655: #endif
12656: case 0x10:
12657: if(REG16(BX) == 0x0000) {
12658: // SMARTDRV is not installed
12659: } else {
12660: 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));
12661: REG16(AX) = 0x01;
12662: m_CF = 1;
12663: }
12664: break;
12665: case 0x11:
12666: if(REG16(BX) == 0x0000) {
12667: // DBLSPACE.BIN is not installed
12668: } else {
12669: 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));
12670: REG16(AX) = 0x01;
12671: m_CF = 1;
12672: }
1.1.1.22 root 12673: break;
12674: default:
12675: 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));
12676: REG16(AX) = 0x01;
12677: m_CF = 1;
12678: break;
12679: }
12680: }
12681:
12682: inline void msdos_int_2fh_4bh()
12683: {
12684: switch(REG8(AL)) {
1.1.1.24 root 12685: case 0x01:
1.1.1.22 root 12686: case 0x02:
1.1.1.29 root 12687: // Task Switcher is not installed
1.1.1.24 root 12688: break;
12689: case 0x03:
12690: // this call is available from within DOSSHELL even if the task switcher is not installed
12691: REG16(AX) = REG16(BX) = 0x0000; // no more avaiable switcher id
1.1.1.22 root 12692: break;
1.1.1.30 root 12693: case 0x04:
12694: REG16(BX) = 0x0000; // free switcher id successfully
12695: break;
1.1 root 12696: default:
1.1.1.22 root 12697: 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 12698: REG16(AX) = 0x01;
1.1.1.3 root 12699: m_CF = 1;
1.1 root 12700: break;
12701: }
12702: }
12703:
12704: inline void msdos_int_2fh_4fh()
12705: {
12706: switch(REG8(AL)) {
12707: case 0x00:
1.1.1.29 root 12708: // BILING is installed
1.1.1.27 root 12709: REG16(AX) = 0x0000;
12710: REG8(DL) = 0x01; // major version
12711: REG8(DH) = 0x00; // minor version
1.1 root 12712: break;
12713: case 0x01:
1.1.1.27 root 12714: REG16(AX) = 0x0000;
1.1 root 12715: REG16(BX) = active_code_page;
12716: break;
12717: default:
1.1.1.22 root 12718: 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));
12719: REG16(AX) = 0x01;
12720: m_CF = 1;
12721: break;
12722: }
12723: }
12724:
12725: inline void msdos_int_2fh_55h()
12726: {
12727: switch(REG8(AL)) {
12728: case 0x00:
12729: case 0x01:
12730: // 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));
12731: break;
12732: default:
12733: 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 12734: REG16(AX) = 0x01;
1.1.1.3 root 12735: m_CF = 1;
1.1 root 12736: break;
12737: }
12738: }
12739:
1.1.1.24 root 12740: inline void msdos_int_2fh_adh()
12741: {
12742: switch(REG8(AL)) {
12743: case 0x00:
1.1.1.29 root 12744: // DISPLAY.SYS is installed
1.1.1.24 root 12745: REG8(AL) = 0xff;
12746: REG16(BX) = 0x100; // ???
12747: break;
12748: case 0x01:
12749: active_code_page = REG16(BX);
12750: msdos_nls_tables_update();
12751: REG16(AX) = 0x01;
12752: break;
12753: case 0x02:
12754: REG16(BX) = active_code_page;
12755: break;
12756: case 0x03:
12757: // FIXME
12758: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 1;
12759: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2) = 3;
12760: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4) = 1;
12761: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 6) = active_code_page;
12762: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 8) = active_code_page;
12763: break;
12764: case 0x80:
12765: break; // keyb.com is not installed
12766: default:
12767: 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));
12768: REG16(AX) = 0x01;
12769: m_CF = 1;
12770: break;
12771: }
12772: }
12773:
1.1 root 12774: inline void msdos_int_2fh_aeh()
12775: {
12776: switch(REG8(AL)) {
12777: case 0x00:
1.1.1.28 root 12778: // FIXME: we need to check the given command line
12779: REG8(AL) = 0x00; // the command should be executed as usual
12780: // REG8(AL) = 0xff; // this command is a TSR extension to COMMAND.COM
1.1 root 12781: break;
12782: case 0x01:
12783: {
12784: char command[MAX_PATH];
12785: memset(command, 0, sizeof(command));
1.1.1.3 root 12786: memcpy(command, mem + SREG_BASE(DS) + REG16(SI) + 1, mem[SREG_BASE(DS) + REG16(SI)]);
1.1 root 12787:
12788: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
12789: param->env_seg = 0;
12790: param->cmd_line.w.l = 44;
12791: param->cmd_line.w.h = (WORK_TOP >> 4);
12792: param->fcb1.w.l = 24;
12793: param->fcb1.w.h = (WORK_TOP >> 4);
12794: param->fcb2.w.l = 24;
12795: param->fcb2.w.h = (WORK_TOP >> 4);
12796:
12797: memset(mem + WORK_TOP + 24, 0x20, 20);
12798:
12799: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
1.1.1.3 root 12800: cmd_line->len = mem[SREG_BASE(DS) + REG16(BX) + 1];
12801: memcpy(cmd_line->cmd, mem + SREG_BASE(DS) + REG16(BX) + 2, cmd_line->len);
1.1 root 12802: cmd_line->cmd[cmd_line->len] = 0x0d;
12803:
1.1.1.28 root 12804: try {
12805: msdos_process_exec(command, param, 0);
12806: } catch(...) {
12807: fatalerror("failed to start '%s' by int 2Fh, AX=AE01h\n", command);
1.1 root 12808: }
12809: }
12810: break;
12811: default:
1.1.1.22 root 12812: 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 12813: REG16(AX) = 0x01;
1.1.1.3 root 12814: m_CF = 1;
1.1 root 12815: break;
12816: }
12817: }
12818:
1.1.1.34 root 12819: inline void msdos_int_2fh_b7h()
12820: {
12821: switch(REG8(AL)) {
12822: case 0x00:
12823: // APPEND is not installed
12824: // REG8(AL) = 0x00;
12825: break;
12826: case 0x07:
12827: // COMMAND.COM calls this service without checking APPEND is installed
12828: break;
12829: default:
12830: 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));
12831: REG16(AX) = 0x01;
12832: m_CF = 1;
12833: break;
12834: }
12835: }
12836:
1.1.1.24 root 12837: inline void msdos_int_33h_0000h()
12838: {
12839: REG16(AX) = 0xffff; // hardware/driver installed
12840: REG16(BX) = MAX_MOUSE_BUTTONS;
12841: }
12842:
12843: inline void msdos_int_33h_0001h()
12844: {
1.1.1.34 root 12845: if(mouse.hidden > 0) {
12846: mouse.hidden--;
12847: }
12848: if(mouse.hidden == 0) {
1.1.1.24 root 12849: if(!(dwConsoleMode & ENABLE_MOUSE_INPUT)) {
12850: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode | ENABLE_MOUSE_INPUT);
12851: }
12852: pic[1].imr &= ~0x10; // enable irq12
12853: }
12854: }
12855:
12856: inline void msdos_int_33h_0002h()
12857: {
1.1.1.34 root 12858: mouse.hidden++;
12859: // SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode & ~ENABLE_MOUSE_INPUT);
12860: pic[1].imr |= 0x10; // enable irq12
1.1.1.24 root 12861: }
12862:
12863: inline void msdos_int_33h_0003h()
12864: {
1.1.1.34 root 12865: // if(mouse.hidden > 0) {
12866: update_console_input();
12867: // }
1.1.1.24 root 12868: REG16(BX) = mouse.get_buttons();
1.1.1.34 root 12869: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.position.x));
12870: REG16(DX) = max(mouse.min_position.y & ~7, min(mouse.max_position.y & ~7, mouse.position.y));
12871: }
12872:
12873: inline void msdos_int_33h_0004h()
12874: {
12875: mouse.position.x = REG16(CX);
12876: mouse.position.x = REG16(DX);
1.1.1.24 root 12877: }
12878:
12879: inline void msdos_int_33h_0005h()
12880: {
1.1.1.34 root 12881: // if(mouse.hidden > 0) {
12882: update_console_input();
12883: // }
1.1.1.24 root 12884: if(REG16(BX) < MAX_MOUSE_BUTTONS) {
12885: int idx = REG16(BX);
1.1.1.34 root 12886: REG16(BX) = min(mouse.buttons[idx].pressed_times, 0x7fff);
12887: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.buttons[idx].pressed_position.x));
12888: 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 12889: mouse.buttons[idx].pressed_times = 0;
12890: } else {
12891: REG16(BX) = REG16(CX) = REG16(DX) = 0x0000;
12892: }
12893: REG16(AX) = mouse.get_buttons();
12894: }
12895:
12896: inline void msdos_int_33h_0006h()
12897: {
1.1.1.34 root 12898: // if(mouse.hidden > 0) {
12899: update_console_input();
12900: // }
1.1.1.24 root 12901: if(REG16(BX) < MAX_MOUSE_BUTTONS) {
12902: int idx = REG16(BX);
1.1.1.34 root 12903: REG16(BX) = min(mouse.buttons[idx].released_times, 0x7fff);
12904: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.buttons[idx].released_position.x));
12905: 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 12906: mouse.buttons[idx].released_times = 0;
12907: } else {
12908: REG16(BX) = REG16(CX) = REG16(DX) = 0x0000;
12909: }
12910: REG16(AX) = mouse.get_buttons();
12911: }
12912:
12913: inline void msdos_int_33h_0007h()
12914: {
12915: mouse.min_position.x = min(REG16(CX), REG16(DX));
12916: mouse.max_position.x = max(REG16(CX), REG16(DX));
12917: }
12918:
12919: inline void msdos_int_33h_0008h()
12920: {
12921: mouse.min_position.y = min(REG16(CX), REG16(DX));
12922: mouse.max_position.y = max(REG16(CX), REG16(DX));
12923: }
12924:
12925: inline void msdos_int_33h_0009h()
12926: {
12927: mouse.hot_spot[0] = REG16(BX);
12928: mouse.hot_spot[1] = REG16(CX);
12929: }
12930:
12931: inline void msdos_int_33h_000bh()
12932: {
1.1.1.34 root 12933: // if(mouse.hidden > 0) {
12934: update_console_input();
12935: // }
1.1.1.24 root 12936: int dx = (mouse.position.x - mouse.prev_position.x) * mouse.mickey.x / 8;
12937: int dy = (mouse.position.y - mouse.prev_position.y) * mouse.mickey.y / 8;
12938: mouse.prev_position.x = mouse.position.x;
12939: mouse.prev_position.y = mouse.position.y;
12940: REG16(CX) = dx;
12941: REG16(DX) = dy;
12942: }
12943:
12944: inline void msdos_int_33h_000ch()
12945: {
12946: mouse.call_mask = REG16(CX);
12947: mouse.call_addr.w.l = REG16(DX);
12948: mouse.call_addr.w.h = SREG(ES);
12949: }
12950:
12951: inline void msdos_int_33h_000fh()
12952: {
12953: mouse.mickey.x = REG16(CX);
12954: mouse.mickey.y = REG16(DX);
12955: }
12956:
12957: inline void msdos_int_33h_0011h()
12958: {
12959: REG16(AX) = 0xffff;
12960: REG16(BX) = MAX_MOUSE_BUTTONS;
12961: }
12962:
12963: inline void msdos_int_33h_0014h()
12964: {
12965: UINT16 old_mask = mouse.call_mask;
12966: UINT16 old_ofs = mouse.call_addr.w.l;
12967: UINT16 old_seg = mouse.call_addr.w.h;
12968:
12969: mouse.call_mask = REG16(CX);
12970: mouse.call_addr.w.l = REG16(DX);
12971: mouse.call_addr.w.h = SREG(ES);
12972:
12973: REG16(CX) = old_mask;
12974: REG16(DX) = old_ofs;
12975: SREG(ES) = old_seg;
12976: i386_load_segment_descriptor(ES);
12977: }
12978:
12979: inline void msdos_int_33h_0015h()
12980: {
12981: REG16(BX) = sizeof(mouse);
12982: }
12983:
12984: inline void msdos_int_33h_0016h()
12985: {
12986: memcpy(mem + SREG_BASE(ES) + REG16(DX), &mouse, sizeof(mouse));
12987: }
12988:
12989: inline void msdos_int_33h_0017h()
12990: {
12991: memcpy(&mouse, mem + SREG_BASE(ES) + REG16(DX), sizeof(mouse));
12992: }
12993:
12994: inline void msdos_int_33h_001ah()
12995: {
12996: mouse.sensitivity[0] = REG16(BX);
12997: mouse.sensitivity[1] = REG16(CX);
12998: mouse.sensitivity[2] = REG16(DX);
12999: }
13000:
13001: inline void msdos_int_33h_001bh()
13002: {
13003: REG16(BX) = mouse.sensitivity[0];
13004: REG16(CX) = mouse.sensitivity[1];
13005: REG16(DX) = mouse.sensitivity[2];
13006: }
13007:
13008: inline void msdos_int_33h_001dh()
13009: {
13010: mouse.display_page = REG16(BX);
13011: }
13012:
13013: inline void msdos_int_33h_001eh()
13014: {
13015: REG16(BX) = mouse.display_page;
13016: }
13017:
1.1.1.34 root 13018: inline void msdos_int_33h_001fh()
13019: {
13020: // from DOSBox
13021: REG16(BX) = 0x0000;
13022: SREG(ES) = 0x0000;
13023: i386_load_segment_descriptor(ES);
13024: mouse.enabled = false;
13025: mouse.old_hidden = mouse.hidden;
13026: mouse.hidden = 1;
13027: }
13028:
13029: inline void msdos_int_33h_0020h()
13030: {
13031: // from DOSBox
13032: mouse.enabled = true;
13033: mouse.hidden = mouse.old_hidden;
13034: }
13035:
1.1.1.24 root 13036: inline void msdos_int_33h_0021h()
13037: {
13038: REG16(AX) = 0xffff;
13039: REG16(BX) = MAX_MOUSE_BUTTONS;
13040: }
13041:
13042: inline void msdos_int_33h_0022h()
13043: {
13044: mouse.language = REG16(BX);
13045: }
13046:
13047: inline void msdos_int_33h_0023h()
13048: {
13049: REG16(BX) = mouse.language;
13050: }
13051:
13052: inline void msdos_int_33h_0024h()
13053: {
13054: REG16(BX) = 0x0805; // V8.05
13055: REG16(CX) = 0x0400; // PS/2
13056: }
13057:
13058: inline void msdos_int_33h_0026h()
13059: {
13060: REG16(BX) = 0x0000;
13061: REG16(CX) = mouse.max_position.x;
13062: REG16(DX) = mouse.max_position.y;
13063: }
13064:
13065: inline void msdos_int_33h_002ah()
13066: {
1.1.1.34 root 13067: REG16(AX) = -mouse.hidden;
1.1.1.24 root 13068: REG16(BX) = mouse.hot_spot[0];
13069: REG16(CX) = mouse.hot_spot[1];
13070: REG16(DX) = 4; // PS/2
13071: }
13072:
13073: inline void msdos_int_33h_0031h()
13074: {
13075: REG16(AX) = mouse.min_position.x;
13076: REG16(BX) = mouse.min_position.y;
13077: REG16(CX) = mouse.max_position.x;
13078: REG16(DX) = mouse.max_position.y;
13079: }
13080:
13081: inline void msdos_int_33h_0032h()
13082: {
13083: REG16(AX) = 0;
13084: // REG16(AX) |= 0x8000; // 0025h
13085: REG16(AX) |= 0x4000; // 0026h
13086: // REG16(AX) |= 0x2000; // 0027h
13087: // REG16(AX) |= 0x1000; // 0028h
13088: // REG16(AX) |= 0x0800; // 0029h
13089: REG16(AX) |= 0x0400; // 002ah
13090: // REG16(AX) |= 0x0200; // 002bh
13091: // REG16(AX) |= 0x0100; // 002ch
13092: // REG16(AX) |= 0x0080; // 002dh
13093: // REG16(AX) |= 0x0040; // 002eh
13094: REG16(AX) |= 0x0020; // 002fh
13095: // REG16(AX) |= 0x0010; // 0030h
13096: REG16(AX) |= 0x0008; // 0031h
13097: REG16(AX) |= 0x0004; // 0032h
13098: // REG16(AX) |= 0x0002; // 0033h
13099: // REG16(AX) |= 0x0001; // 0034h
13100: }
13101:
1.1.1.19 root 13102: inline void msdos_int_67h_40h()
13103: {
13104: if(!support_ems) {
13105: REG8(AH) = 0x84;
13106: } else {
13107: REG8(AH) = 0x00;
13108: }
13109: }
13110:
13111: inline void msdos_int_67h_41h()
13112: {
13113: if(!support_ems) {
13114: REG8(AH) = 0x84;
13115: } else {
13116: REG8(AH) = 0x00;
13117: REG16(BX) = EMS_TOP >> 4;
13118: }
13119: }
13120:
13121: inline void msdos_int_67h_42h()
13122: {
13123: if(!support_ems) {
13124: REG8(AH) = 0x84;
13125: } else {
13126: REG8(AH) = 0x00;
13127: REG16(BX) = free_ems_pages;
13128: REG16(DX) = MAX_EMS_PAGES;
13129: }
13130: }
13131:
13132: inline void msdos_int_67h_43h()
13133: {
13134: if(!support_ems) {
13135: REG8(AH) = 0x84;
13136: } else if(REG16(BX) > MAX_EMS_PAGES) {
13137: REG8(AH) = 0x87;
13138: } else if(REG16(BX) > free_ems_pages) {
13139: REG8(AH) = 0x88;
13140: } else if(REG16(BX) == 0) {
13141: REG8(AH) = 0x89;
13142: } else {
1.1.1.31 root 13143: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 13144: if(!ems_handles[i].allocated) {
13145: ems_allocate_pages(i, REG16(BX));
13146: REG8(AH) = 0x00;
13147: REG16(DX) = i;
13148: return;
13149: }
13150: }
13151: REG8(AH) = 0x85;
13152: }
13153: }
13154:
13155: inline void msdos_int_67h_44h()
13156: {
13157: if(!support_ems) {
13158: REG8(AH) = 0x84;
1.1.1.31 root 13159: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 13160: REG8(AH) = 0x83;
13161: } else if(!(REG16(BX) == 0xffff || REG16(BX) < ems_handles[REG16(DX)].pages)) {
13162: REG8(AH) = 0x8a;
13163: // } else if(!(REG8(AL) < 4)) {
13164: // REG8(AH) = 0x8b;
13165: } else if(REG16(BX) == 0xffff) {
13166: ems_unmap_page(REG8(AL) & 3);
13167: REG8(AH) = 0x00;
13168: } else {
13169: ems_map_page(REG8(AL) & 3, REG16(DX), REG16(BX));
13170: REG8(AH) = 0x00;
13171: }
13172: }
13173:
13174: inline void msdos_int_67h_45h()
13175: {
13176: if(!support_ems) {
13177: REG8(AH) = 0x84;
1.1.1.31 root 13178: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 13179: REG8(AH) = 0x83;
13180: } else {
13181: ems_release_pages(REG16(DX));
13182: REG8(AH) = 0x00;
13183: }
13184: }
13185:
13186: inline void msdos_int_67h_46h()
13187: {
13188: if(!support_ems) {
13189: REG8(AH) = 0x84;
13190: } else {
1.1.1.29 root 13191: // REG16(AX) = 0x0032; // EMS 3.2
13192: REG16(AX) = 0x0040; // EMS 4.0
1.1.1.19 root 13193: }
13194: }
13195:
13196: inline void msdos_int_67h_47h()
13197: {
13198: // NOTE: the map data should be stored in the specified ems page, not process data
13199: process_t *process = msdos_process_info_get(current_psp);
13200:
13201: if(!support_ems) {
13202: REG8(AH) = 0x84;
1.1.1.31 root 13203: // } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 13204: // REG8(AH) = 0x83;
13205: } else if(process->ems_pages_stored) {
13206: REG8(AH) = 0x8d;
13207: } else {
13208: for(int i = 0; i < 4; i++) {
13209: process->ems_pages[i].handle = ems_pages[i].handle;
13210: process->ems_pages[i].page = ems_pages[i].page;
13211: process->ems_pages[i].mapped = ems_pages[i].mapped;
13212: }
13213: process->ems_pages_stored = true;
13214: REG8(AH) = 0x00;
13215: }
13216: }
13217:
13218: inline void msdos_int_67h_48h()
13219: {
13220: // NOTE: the map data should be restored from the specified ems page, not process data
13221: process_t *process = msdos_process_info_get(current_psp);
13222:
13223: if(!support_ems) {
13224: REG8(AH) = 0x84;
1.1.1.31 root 13225: // } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 13226: // REG8(AH) = 0x83;
13227: } else if(!process->ems_pages_stored) {
13228: REG8(AH) = 0x8e;
13229: } else {
13230: for(int i = 0; i < 4; i++) {
13231: if(process->ems_pages[i].mapped) {
13232: ems_map_page(i, process->ems_pages[i].handle, process->ems_pages[i].page);
13233: } else {
13234: ems_unmap_page(i);
13235: }
13236: }
13237: process->ems_pages_stored = false;
13238: REG8(AH) = 0x00;
13239: }
13240: }
13241:
13242: inline void msdos_int_67h_4bh()
13243: {
13244: if(!support_ems) {
13245: REG8(AH) = 0x84;
13246: } else {
13247: REG8(AH) = 0x00;
13248: REG16(BX) = 0;
1.1.1.31 root 13249: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 13250: if(ems_handles[i].allocated) {
13251: REG16(BX)++;
13252: }
13253: }
13254: }
13255: }
13256:
13257: inline void msdos_int_67h_4ch()
13258: {
13259: if(!support_ems) {
13260: REG8(AH) = 0x84;
1.1.1.31 root 13261: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 13262: REG8(AH) = 0x83;
13263: } else {
13264: REG8(AH) = 0x00;
13265: REG16(BX) = ems_handles[REG16(DX)].pages;
13266: }
13267: }
13268:
13269: inline void msdos_int_67h_4dh()
13270: {
13271: if(!support_ems) {
13272: REG8(AH) = 0x84;
13273: } else {
13274: REG8(AH) = 0x00;
13275: REG16(BX) = 0;
1.1.1.31 root 13276: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 13277: if(ems_handles[i].allocated) {
13278: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 0) = i;
13279: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 2) = ems_handles[i].pages;
13280: REG16(BX)++;
13281: }
13282: }
13283: }
13284: }
13285:
1.1.1.20 root 13286: inline void msdos_int_67h_4eh()
13287: {
13288: if(!support_ems) {
13289: REG8(AH) = 0x84;
13290: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01 || REG8(AL) == 0x02) {
13291: if(REG8(AL) == 0x00 || REG8(AL) == 0x02) {
13292: // save page map
13293: for(int i = 0; i < 4; i++) {
13294: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = ems_pages[i].mapped ? ems_pages[i].handle : 0xffff;
13295: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = ems_pages[i].mapped ? ems_pages[i].page : 0xffff;
13296: }
13297: }
13298: if(REG8(AL) == 0x01 || REG8(AL) == 0x02) {
13299: // restore page map
13300: for(int i = 0; i < 4; i++) {
13301: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0);
13302: UINT16 page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2);
13303:
1.1.1.31 root 13304: if(handle >= 1 && handle <= MAX_EMS_HANDLES && ems_handles[handle].allocated && page < ems_handles[handle].pages) {
1.1.1.20 root 13305: ems_map_page(i, handle, page);
13306: } else {
13307: ems_unmap_page(i);
13308: }
13309: }
13310: }
13311: REG8(AH) = 0x00;
13312: } else if(REG8(AL) == 0x03) {
13313: REG8(AH) = 0x00;
1.1.1.21 root 13314: REG8(AL) = 4 * 4;
13315: } else {
1.1.1.22 root 13316: 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 13317: REG8(AH) = 0x8f;
13318: }
13319: }
13320:
13321: inline void msdos_int_67h_4fh()
13322: {
13323: if(!support_ems) {
13324: REG8(AH) = 0x84;
13325: } else if(REG8(AL) == 0x00) {
13326: int count = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI));
13327:
13328: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI)) = count;
13329: for(int i = 0; i < count; i++) {
13330: UINT16 segment = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 2 * i);
13331: UINT16 physical = ((segment << 4) - EMS_TOP) / 0x4000;
13332:
13333: // if(!(physical < 4)) {
13334: // REG8(AH) = 0x8b;
13335: // return;
13336: // }
13337: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 0) = segment;
1.1.1.41! root 13338: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 2) = ems_pages[physical & 3].mapped ? ems_pages[physical & 3].handle : 0xffff;
! 13339: *(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 13340: }
13341: REG8(AH) = 0x00;
13342: } else if(REG8(AL) == 0x01) {
13343: int count = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI));
13344:
13345: for(int i = 0; i < count; i++) {
13346: UINT16 segment = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 0);
13347: UINT16 physical = ((segment << 4) - EMS_TOP) / 0x4000;
13348: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 2);
13349: UINT16 logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 4);
13350:
13351: // if(!(physical < 4)) {
13352: // REG8(AH) = 0x8b;
13353: // return;
13354: // } else
1.1.1.41! root 13355: if(handle >= 1 && handle <= MAX_EMS_HANDLES && ems_handles[handle].allocated && logical < ems_handles[handle].pages) {
1.1.1.21 root 13356: ems_map_page(physical & 3, handle, logical);
13357: } else {
1.1.1.41! root 13358: ems_unmap_page(physical & 3);
1.1.1.21 root 13359: }
13360: }
13361: REG8(AH) = 0x00;
13362: } else if(REG8(AL) == 0x02) {
13363: REG8(AH) = 0x00;
13364: REG8(AL) = 2 + REG16(BX) * 6;
1.1.1.20 root 13365: } else {
1.1.1.22 root 13366: 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 13367: REG8(AH) = 0x8f;
13368: }
13369: }
13370:
13371: inline void msdos_int_67h_50h()
13372: {
13373: if(!support_ems) {
13374: REG8(AH) = 0x84;
1.1.1.31 root 13375: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.20 root 13376: REG8(AH) = 0x83;
13377: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
13378: for(int i = 0; i < REG16(CX); i++) {
13379: int logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0);
13380: int physical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2);
13381:
13382: if(REG8(AL) == 0x01) {
13383: physical = ((physical << 4) - EMS_TOP) / 0x4000;
13384: }
13385: // if(!(physical < 4)) {
13386: // REG8(AH) = 0x8b;
13387: // return;
13388: // } else
13389: if(logical == 0xffff) {
13390: ems_unmap_page(physical & 3);
13391: } else if(logical < ems_handles[REG16(DX)].pages) {
13392: ems_map_page(physical & 3, REG16(DX), logical);
13393: } else {
13394: REG8(AH) = 0x8a;
13395: return;
13396: }
13397: }
13398: REG8(AH) = 0x00;
13399: } else {
1.1.1.22 root 13400: 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 13401: REG8(AH) = 0x8f;
13402: }
13403: }
13404:
1.1.1.19 root 13405: inline void msdos_int_67h_51h()
13406: {
13407: if(!support_ems) {
13408: REG8(AH) = 0x84;
1.1.1.31 root 13409: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 13410: REG8(AH) = 0x83;
13411: } else if(REG16(BX) > MAX_EMS_PAGES) {
13412: REG8(AH) = 0x87;
13413: } else if(REG16(BX) > free_ems_pages + ems_handles[REG16(DX)].pages) {
13414: REG8(AH) = 0x88;
13415: } else {
13416: ems_reallocate_pages(REG16(DX), REG16(BX));
13417: REG8(AH) = 0x00;
13418: }
13419: }
13420:
1.1.1.20 root 13421: inline void msdos_int_67h_52h()
13422: {
13423: if(!support_ems) {
13424: REG8(AH) = 0x84;
1.1.1.31 root 13425: // } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
13426: // REG8(AH) = 0x83;
1.1.1.20 root 13427: } else if(REG8(AL) == 0x00) {
13428: REG8(AL) = 0x00; // handle is volatile
13429: REG8(AH) = 0x00;
13430: } else if(REG8(AL) == 0x01) {
13431: if(REG8(BL) == 0x00) {
13432: REG8(AH) = 0x00;
13433: } else {
13434: REG8(AH) = 0x90; // undefined attribute type
13435: }
13436: } else if(REG8(AL) == 0x02) {
13437: REG8(AL) = 0x00; // only volatile handles supported
13438: REG8(AH) = 0x00;
13439: } else {
1.1.1.22 root 13440: 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 13441: REG8(AH) = 0x8f;
13442: }
13443: }
13444:
1.1.1.19 root 13445: inline void msdos_int_67h_53h()
13446: {
13447: if(!support_ems) {
13448: REG8(AH) = 0x84;
1.1.1.31 root 13449: } else if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
1.1.1.19 root 13450: REG8(AH) = 0x83;
13451: } else if(REG8(AL) == 0x00) {
13452: memcpy(mem + SREG_BASE(ES) + REG16(DI), ems_handles[REG16(DX)].name, 8);
13453: REG8(AH) = 0x00;
13454: } else if(REG8(AL) == 0x01) {
1.1.1.31 root 13455: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 13456: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) {
13457: REG8(AH) = 0xa1;
13458: return;
13459: }
13460: }
13461: REG8(AH) = 0x00;
13462: memcpy(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8);
13463: } else {
1.1.1.22 root 13464: 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 13465: REG8(AH) = 0x8f;
1.1.1.19 root 13466: }
13467: }
13468:
13469: inline void msdos_int_67h_54h()
13470: {
13471: if(!support_ems) {
13472: REG8(AH) = 0x84;
13473: } else if(REG8(AL) == 0x00) {
1.1.1.31 root 13474: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 13475: if(ems_handles[i].allocated) {
13476: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, ems_handles[i].name, 10);
13477: } else {
13478: memset(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, 0, 10);
13479: }
13480: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 0) = i;
13481: }
13482: REG8(AH) = 0x00;
13483: REG8(AL) = MAX_EMS_HANDLES;
13484: } else if(REG8(AL) == 0x01) {
13485: REG8(AH) = 0xa0; // not found
1.1.1.31 root 13486: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.19 root 13487: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) {
13488: REG8(AH) = 0x00;
13489: REG16(DX) = i;
13490: break;
13491: }
13492: }
13493: } else if(REG8(AL) == 0x02) {
13494: REG8(AH) = 0x00;
13495: REG16(BX) = MAX_EMS_HANDLES;
13496: } else {
1.1.1.22 root 13497: 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 13498: REG8(AH) = 0x8f;
13499: }
13500: }
13501:
13502: inline void msdos_int_67h_57h_tmp()
13503: {
13504: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00);
13505: UINT8 src_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04);
13506: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x05);
13507: UINT16 src_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07);
13508: UINT16 src_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x09);
13509: UINT8 dest_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0b);
13510: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c);
13511: UINT16 dest_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0e);
13512: UINT16 dest_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x10);
13513:
1.1.1.32 root 13514: UINT8 *src_buffer = NULL, *dest_buffer = NULL;
1.1.1.20 root 13515: UINT32 src_addr, dest_addr;
13516: UINT32 src_addr_max, dest_addr_max;
13517:
13518: if(src_type == 0) {
13519: src_buffer = mem;
13520: src_addr = (src_seg << 4) + src_ofs;
13521: src_addr_max = MAX_MEM;
13522: } else {
1.1.1.31 root 13523: if(!(src_handle >= 1 && src_handle <= MAX_EMS_HANDLES && ems_handles[src_handle].allocated)) {
1.1.1.20 root 13524: REG8(AH) = 0x83;
13525: return;
13526: } else if(!(src_seg < ems_handles[src_handle].pages)) {
13527: REG8(AH) = 0x8a;
13528: return;
13529: }
1.1.1.32 root 13530: if(ems_handles[src_handle].buffer != NULL) {
13531: src_buffer = ems_handles[src_handle].buffer + 0x4000 * src_seg;
13532: }
1.1.1.20 root 13533: src_addr = src_ofs;
1.1.1.32 root 13534: src_addr_max = 0x4000 * (ems_handles[src_handle].pages - src_seg);
1.1.1.20 root 13535: }
13536: if(dest_type == 0) {
13537: dest_buffer = mem;
13538: dest_addr = (dest_seg << 4) + dest_ofs;
13539: dest_addr_max = MAX_MEM;
13540: } else {
1.1.1.31 root 13541: if(!(dest_handle >= 1 && dest_handle <= MAX_EMS_HANDLES && ems_handles[dest_handle].allocated)) {
1.1.1.20 root 13542: REG8(AH) = 0x83;
13543: return;
13544: } else if(!(dest_seg < ems_handles[dest_handle].pages)) {
13545: REG8(AH) = 0x8a;
13546: return;
13547: }
1.1.1.32 root 13548: if(ems_handles[dest_handle].buffer != NULL) {
13549: dest_buffer = ems_handles[dest_handle].buffer + 0x4000 * dest_seg;
13550: }
1.1.1.20 root 13551: dest_addr = dest_ofs;
1.1.1.32 root 13552: dest_addr_max = 0x4000 * (ems_handles[dest_handle].pages - dest_seg);
1.1.1.20 root 13553: }
1.1.1.32 root 13554: if(src_buffer != NULL && dest_buffer != NULL) {
13555: for(int i = 0; i < copy_length; i++) {
13556: if(src_addr < src_addr_max && dest_addr < dest_addr_max) {
13557: if(REG8(AL) == 0x00) {
13558: dest_buffer[dest_addr++] = src_buffer[src_addr++];
13559: } else if(REG8(AL) == 0x01) {
13560: UINT8 tmp = dest_buffer[dest_addr];
13561: dest_buffer[dest_addr++] = src_buffer[src_addr];
13562: src_buffer[src_addr++] = tmp;
13563: }
13564: } else {
13565: REG8(AH) = 0x93;
13566: return;
1.1.1.20 root 13567: }
13568: }
1.1.1.32 root 13569: REG8(AH) = 0x00;
13570: } else {
13571: REG8(AH) = 0x80;
1.1.1.20 root 13572: }
13573: }
13574:
13575: inline void msdos_int_67h_57h()
13576: {
13577: if(!support_ems) {
13578: REG8(AH) = 0x84;
13579: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
13580: struct {
13581: UINT16 handle;
13582: UINT16 page;
13583: bool mapped;
13584: } tmp_pages[4];
13585:
13586: // unmap pages to copy memory data to ems buffer
13587: for(int i = 0; i < 4; i++) {
13588: tmp_pages[i].handle = ems_pages[i].handle;
13589: tmp_pages[i].page = ems_pages[i].page;
13590: tmp_pages[i].mapped = ems_pages[i].mapped;
13591: ems_unmap_page(i);
13592: }
13593:
13594: // run move/exchange operation
13595: msdos_int_67h_57h_tmp();
13596:
13597: // restore unmapped pages
13598: for(int i = 0; i < 4; i++) {
13599: if(tmp_pages[i].mapped) {
13600: ems_map_page(i, tmp_pages[i].handle, tmp_pages[i].page);
13601: }
13602: }
13603: } else {
1.1.1.22 root 13604: 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 13605: REG8(AH) = 0x8f;
13606: }
13607: }
13608:
13609: inline void msdos_int_67h_58h()
13610: {
13611: if(!support_ems) {
13612: REG8(AH) = 0x84;
13613: } else if(REG8(AL) == 0x00) {
13614: for(int i = 0; i < 4; i++) {
1.1.1.30 root 13615: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = (EMS_TOP + 0x4000 * i) >> 4;
13616: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = i;
1.1.1.20 root 13617: }
13618: REG8(AH) = 0x00;
13619: REG16(CX) = 4;
13620: } else if(REG8(AL) == 0x01) {
13621: REG8(AH) = 0x00;
13622: REG16(CX) = 4;
13623: } else {
1.1.1.22 root 13624: 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 13625: REG8(AH) = 0x8f;
13626: }
13627: }
13628:
13629: inline void msdos_int_67h_5ah()
13630: {
13631: if(!support_ems) {
1.1.1.19 root 13632: REG8(AH) = 0x84;
1.1.1.20 root 13633: } else if(REG16(BX) > MAX_EMS_PAGES) {
13634: REG8(AH) = 0x87;
13635: } else if(REG16(BX) > free_ems_pages) {
13636: REG8(AH) = 0x88;
13637: // } else if(REG16(BX) == 0) {
13638: // REG8(AH) = 0x89;
13639: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
1.1.1.31 root 13640: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.20 root 13641: if(!ems_handles[i].allocated) {
13642: ems_allocate_pages(i, REG16(BX));
13643: REG8(AH) = 0x00;
13644: REG16(DX) = i;
13645: return;
13646: }
13647: }
13648: REG8(AH) = 0x85;
13649: } else {
1.1.1.22 root 13650: 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 13651: REG8(AH) = 0x8f;
1.1.1.19 root 13652: }
13653: }
13654:
1.1.1.30 root 13655: inline void msdos_int_67h_deh()
13656: {
13657: REG8(AH) = 0x84;
13658: }
13659:
1.1.1.19 root 13660: #ifdef SUPPORT_XMS
13661:
1.1.1.32 root 13662: void msdos_xms_init()
1.1.1.26 root 13663: {
1.1.1.30 root 13664: emb_handle_top = (emb_handle_t *)calloc(1, sizeof(emb_handle_t));
13665: emb_handle_top->address = EMB_TOP;
13666: emb_handle_top->size_kb = (EMB_END - EMB_TOP) >> 10;
1.1.1.26 root 13667: xms_a20_local_enb_count = 0;
13668: }
13669:
1.1.1.32 root 13670: void msdos_xms_finish()
13671: {
13672: msdos_xms_release();
13673: }
13674:
13675: void msdos_xms_release()
1.1.1.30 root 13676: {
13677: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL;) {
13678: emb_handle_t *next_handle = emb_handle->next;
13679: free(emb_handle);
13680: emb_handle = next_handle;
13681: }
13682: }
13683:
13684: emb_handle_t *msdos_xms_get_emb_handle(int handle)
13685: {
13686: if(handle != 0) {
13687: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
13688: if(emb_handle->handle == handle) {
13689: return(emb_handle);
13690: }
13691: }
13692: }
13693: return(NULL);
13694: }
13695:
13696: int msdos_xms_get_unused_emb_handle_id()
13697: {
13698: for(int handle = 1;; handle++) {
13699: if(msdos_xms_get_emb_handle(handle) == NULL) {
13700: return(handle);
13701: }
13702: }
13703: return(0);
13704: }
13705:
13706: int msdos_xms_get_unused_emb_handle_count()
13707: {
13708: int count = 64; //255;
13709:
13710: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
13711: if(emb_handle->handle != 0) {
13712: if(--count == 1) {
13713: break;
13714: }
13715: }
13716: }
13717: return(count);
13718: }
13719:
13720: void msdos_xms_split_emb_handle(emb_handle_t *emb_handle, int size_kb)
13721: {
13722: if(emb_handle->size_kb > size_kb) {
13723: emb_handle_t *new_handle = (emb_handle_t *)calloc(1, sizeof(emb_handle_t));
13724:
13725: new_handle->address = emb_handle->address + size_kb * 1024;
13726: new_handle->size_kb = emb_handle->size_kb - size_kb;
13727: emb_handle->size_kb = size_kb;
13728:
13729: new_handle->prev = emb_handle;
13730: new_handle->next = emb_handle->next;
13731: if(emb_handle->next != NULL) {
13732: emb_handle->next->prev = new_handle;
13733: }
13734: emb_handle->next = new_handle;
13735: }
13736: }
13737:
13738: void msdos_xms_combine_emb_handles(emb_handle_t *emb_handle)
13739: {
13740: emb_handle_t *next_handle = emb_handle->next;
13741:
13742: if(next_handle != NULL) {
13743: emb_handle->size_kb += next_handle->size_kb;
13744:
13745: if(next_handle->next != NULL) {
13746: next_handle->next->prev = emb_handle;
13747: }
13748: emb_handle->next = next_handle->next;
13749: free(next_handle);
13750: }
13751: }
13752:
13753: emb_handle_t *msdos_xms_alloc_emb_handle(int size_kb)
13754: {
13755: emb_handle_t *target_handle = NULL;
13756:
13757: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
13758: if(emb_handle->handle == 0 && emb_handle->size_kb >= size_kb) {
13759: if(target_handle == NULL || target_handle->size_kb > emb_handle->size_kb) {
13760: target_handle = emb_handle;
13761: }
13762: }
13763: }
13764: if(target_handle != NULL) {
13765: if(target_handle->size_kb > size_kb) {
13766: msdos_xms_split_emb_handle(target_handle, size_kb);
13767: }
13768: // target_handle->handle = msdos_xms_get_unused_emb_handle_id();
13769: return(target_handle);
13770: }
13771: return(NULL);
13772: }
13773:
13774: void msdos_xms_free_emb_handle(emb_handle_t *emb_handle)
13775: {
13776: emb_handle_t *prev_handle = emb_handle->prev;
13777: emb_handle_t *next_handle = emb_handle->next;
13778:
13779: if(prev_handle != NULL && prev_handle->handle == 0) {
13780: msdos_xms_combine_emb_handles(prev_handle);
13781: emb_handle = prev_handle;
13782: }
13783: if(next_handle != NULL && next_handle->handle == 0) {
13784: msdos_xms_combine_emb_handles(emb_handle);
13785: }
13786: emb_handle->handle = 0;
13787: }
13788:
1.1.1.19 root 13789: inline void msdos_call_xms_00h()
13790: {
1.1.1.29 root 13791: #if defined(HAS_I386)
13792: REG16(AX) = 0x0300; // V3.00 (XMS Version)
13793: REG16(BX) = 0x035f; // V3.95 (Driver Revision)
13794: #else
13795: REG16(AX) = 0x0200; // V2.00 (XMS Version)
13796: REG16(BX) = 0x0270; // V2.70 (Driver Revision)
13797: #endif
13798: // REG16(DX) = 0x0000; // HMA does not exist
13799: REG16(DX) = 0x0001; // HMA does exist
1.1.1.19 root 13800: }
13801:
13802: inline void msdos_call_xms_01h()
13803: {
1.1.1.29 root 13804: if(REG8(AL) == 0x40) {
13805: // HIMEM.SYS will fail function 01h with error code 91h if AL=40h and
13806: // DX=KB free extended memory returned by last call of function 08h
13807: REG16(AX) = 0x0000;
13808: REG8(BL) = 0x91;
13809: REG16(DX) = xms_dx_after_call_08h;
13810: } else if(memcmp(mem + 0x100003, "VDISK", 5) == 0) {
13811: REG16(AX) = 0x0000;
13812: REG8(BL) = 0x81; // Vdisk was detected
13813: #ifdef SUPPORT_HMA
13814: } else if(is_hma_used_by_int_2fh) {
13815: REG16(AX) = 0x0000;
13816: REG8(BL) = 0x90; // HMA does not exist or is not managed by XMS provider
13817: } else if(is_hma_used_by_xms) {
13818: REG16(AX) = 0x0000;
13819: REG8(BL) = 0x91; // HMA is already in use
13820: } else {
13821: REG16(AX) = 0x0001;
13822: is_hma_used_by_xms = true;
13823: #else
13824: } else {
13825: REG16(AX) = 0x0000;
13826: REG8(BL) = 0x91; // HMA is already in use
13827: #endif
13828: }
1.1.1.19 root 13829: }
13830:
13831: inline void msdos_call_xms_02h()
13832: {
1.1.1.29 root 13833: if(memcmp(mem + 0x100003, "VDISK", 5) == 0) {
13834: REG16(AX) = 0x0000;
13835: REG8(BL) = 0x81; // Vdisk was detected
13836: #ifdef SUPPORT_HMA
13837: } else if(is_hma_used_by_int_2fh) {
13838: REG16(AX) = 0x0000;
13839: REG8(BL) = 0x90; // HMA does not exist or is not managed by XMS provider
13840: } else if(!is_hma_used_by_xms) {
13841: REG16(AX) = 0x0000;
13842: REG8(BL) = 0x93; // HMA is not allocated
13843: } else {
13844: REG16(AX) = 0x0001;
13845: is_hma_used_by_xms = false;
13846: // restore first free mcb in high memory area
13847: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
13848: #else
13849: } else {
13850: REG16(AX) = 0x0000;
13851: REG8(BL) = 0x91; // HMA is already in use
13852: #endif
13853: }
1.1.1.19 root 13854: }
13855:
13856: inline void msdos_call_xms_03h()
13857: {
13858: i386_set_a20_line(1);
13859: REG16(AX) = 0x0001;
13860: REG8(BL) = 0x00;
13861: }
13862:
13863: inline void msdos_call_xms_04h()
13864: {
1.1.1.21 root 13865: i386_set_a20_line(0);
13866: REG16(AX) = 0x0001;
13867: REG8(BL) = 0x00;
1.1.1.19 root 13868: }
13869:
13870: inline void msdos_call_xms_05h()
13871: {
13872: i386_set_a20_line(1);
13873: REG16(AX) = 0x0001;
13874: REG8(BL) = 0x00;
1.1.1.21 root 13875: xms_a20_local_enb_count++;
1.1.1.19 root 13876: }
13877:
13878: void msdos_call_xms_06h()
13879: {
1.1.1.21 root 13880: if(xms_a20_local_enb_count > 0) {
13881: xms_a20_local_enb_count--;
13882: }
13883: if(xms_a20_local_enb_count == 0) {
1.1.1.19 root 13884: i386_set_a20_line(0);
1.1.1.21 root 13885: }
13886: if((m_a20_mask >> 20) & 1) {
1.1.1.19 root 13887: REG16(AX) = 0x0000;
13888: REG8(BL) = 0x94;
1.1.1.21 root 13889: } else {
13890: REG16(AX) = 0x0001;
13891: REG8(BL) = 0x00;
1.1.1.19 root 13892: }
13893: }
13894:
13895: inline void msdos_call_xms_07h()
13896: {
13897: REG16(AX) = (m_a20_mask >> 20) & 1;
13898: REG8(BL) = 0x00;
13899: }
13900:
13901: inline void msdos_call_xms_08h()
13902: {
13903: REG16(AX) = REG16(DX) = 0x0000;
13904:
1.1.1.30 root 13905: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
13906: if(emb_handle->handle == 0) {
13907: if(REG16(AX) < emb_handle->size_kb) {
13908: REG16(AX) = emb_handle->size_kb;
1.1.1.19 root 13909: }
1.1.1.30 root 13910: REG16(DX) += emb_handle->size_kb;
1.1.1.19 root 13911: }
13912: }
13913:
13914: if(REG16(AX) == 0 && REG16(DX) == 0) {
13915: REG8(BL) = 0xa0;
13916: } else {
13917: REG8(BL) = 0x00;
13918: }
1.1.1.29 root 13919: xms_dx_after_call_08h = REG16(DX);
1.1.1.19 root 13920: }
13921:
1.1.1.30 root 13922: void msdos_call_xms_09h(int size_kb)
1.1.1.19 root 13923: {
1.1.1.30 root 13924: emb_handle_t *emb_handle = msdos_xms_alloc_emb_handle(size_kb);
13925:
13926: if(emb_handle != NULL) {
13927: emb_handle->handle = msdos_xms_get_unused_emb_handle_id();
13928:
13929: REG16(AX) = 0x0001;
13930: REG16(DX) = emb_handle->handle;
13931: REG8(BL) = 0x00;
13932: } else {
13933: REG16(AX) = REG16(DX) = 0x0000;
13934: REG8(BL) = 0xa0;
1.1.1.19 root 13935: }
1.1.1.30 root 13936: }
13937:
13938: inline void msdos_call_xms_09h()
13939: {
13940: msdos_call_xms_09h(REG16(DX));
1.1.1.19 root 13941: }
13942:
13943: inline void msdos_call_xms_0ah()
13944: {
1.1.1.30 root 13945: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
13946:
13947: if(emb_handle == NULL) {
1.1.1.19 root 13948: REG16(AX) = 0x0000;
13949: REG8(BL) = 0xa2;
1.1.1.30 root 13950: } else if(emb_handle->lock > 0) {
1.1.1.19 root 13951: REG16(AX) = 0x0000;
13952: REG8(BL) = 0xab;
13953: } else {
1.1.1.30 root 13954: msdos_xms_free_emb_handle(emb_handle);
1.1.1.19 root 13955:
13956: REG16(AX) = 0x0001;
13957: REG8(BL) = 0x00;
13958: }
13959: }
13960:
13961: inline void msdos_call_xms_0bh()
13962: {
13963: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00);
13964: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04);
13965: UINT32 src_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06);
13966: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0a);
13967: UINT32 dest_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c);
13968:
13969: UINT8 *src_buffer, *dest_buffer;
13970: UINT32 src_addr_max, dest_addr_max;
1.1.1.30 root 13971: emb_handle_t *emb_handle;
1.1.1.19 root 13972:
13973: if(src_handle == 0) {
13974: src_buffer = mem;
13975: src_addr = (((src_addr >> 16) & 0xffff) << 4) + (src_addr & 0xffff);
13976: src_addr_max = MAX_MEM;
1.1.1.30 root 13977:
1.1.1.19 root 13978: } else {
1.1.1.30 root 13979: if((emb_handle = msdos_xms_get_emb_handle(src_handle)) == NULL) {
1.1.1.19 root 13980: REG16(AX) = 0x0000;
13981: REG8(BL) = 0xa3;
13982: return;
13983: }
1.1.1.30 root 13984: src_buffer = mem + emb_handle->address;
13985: src_addr_max = emb_handle->size_kb * 1024;
1.1.1.19 root 13986: }
13987: if(dest_handle == 0) {
13988: dest_buffer = mem;
13989: dest_addr = (((dest_addr >> 16) & 0xffff) << 4) + (dest_addr & 0xffff);
13990: dest_addr_max = MAX_MEM;
13991: } else {
1.1.1.30 root 13992: if((emb_handle = msdos_xms_get_emb_handle(dest_handle)) == NULL) {
1.1.1.19 root 13993: REG16(AX) = 0x0000;
13994: REG8(BL) = 0xa5;
13995: return;
13996: }
1.1.1.30 root 13997: dest_buffer = mem + emb_handle->address;
13998: dest_addr_max = emb_handle->size_kb * 1024;
1.1.1.19 root 13999: }
14000: for(int i = 0; i < copy_length; i++) {
14001: if(src_addr < src_addr_max && dest_addr < dest_addr_max) {
14002: dest_buffer[dest_addr++] = src_buffer[src_addr++];
14003: } else {
14004: break;
14005: }
14006: }
14007: REG16(AX) = 0x0001;
14008: REG8(BL) = 0x00;
14009: }
14010:
14011: inline void msdos_call_xms_0ch()
14012: {
1.1.1.30 root 14013: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
14014:
14015: if(emb_handle == NULL) {
1.1.1.19 root 14016: REG16(AX) = 0x0000;
14017: REG8(BL) = 0xa2;
14018: } else {
1.1.1.30 root 14019: emb_handle->lock++;
1.1.1.19 root 14020: REG16(AX) = 0x0001;
14021: REG8(BL) = 0x00;
1.1.1.30 root 14022: REG16(DX) = (emb_handle->address >> 16) & 0xffff;
14023: REG16(BX) = (emb_handle->address ) & 0xffff;
1.1.1.19 root 14024: }
14025: }
14026:
14027: inline void msdos_call_xms_0dh()
14028: {
1.1.1.30 root 14029: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
14030:
14031: if(emb_handle == NULL) {
1.1.1.19 root 14032: REG16(AX) = 0x0000;
14033: REG8(BL) = 0xa2;
1.1.1.30 root 14034: } else if(!(emb_handle->lock > 0)) {
1.1.1.19 root 14035: REG16(AX) = 0x0000;
14036: REG8(BL) = 0xaa;
14037: } else {
1.1.1.30 root 14038: emb_handle->lock--;
1.1.1.19 root 14039: REG16(AX) = 0x0001;
14040: REG8(BL) = 0x00;
14041: }
14042: }
14043:
14044: inline void msdos_call_xms_0eh()
14045: {
1.1.1.30 root 14046: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
14047:
14048: if(emb_handle == NULL) {
1.1.1.19 root 14049: REG16(AX) = 0x0000;
14050: REG8(BL) = 0xa2;
14051: } else {
14052: REG16(AX) = 0x0001;
1.1.1.30 root 14053: REG8(BH) = emb_handle->lock;
14054: REG8(BL) = msdos_xms_get_unused_emb_handle_count();
14055: REG16(DX) = emb_handle->size_kb;
1.1.1.19 root 14056: }
14057: }
14058:
1.1.1.30 root 14059: void msdos_call_xms_0fh(int size_kb)
1.1.1.19 root 14060: {
1.1.1.30 root 14061: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
14062:
14063: if(emb_handle == NULL) {
1.1.1.19 root 14064: REG16(AX) = 0x0000;
14065: REG8(BL) = 0xa2;
1.1.1.30 root 14066: } else if(emb_handle->lock > 0) {
1.1.1.19 root 14067: REG16(AX) = 0x0000;
14068: REG8(BL) = 0xab;
14069: } else {
1.1.1.30 root 14070: if(emb_handle->size_kb < size_kb) {
14071: if(emb_handle->next != NULL && emb_handle->next->handle == 0 && (emb_handle->size_kb + emb_handle->next->size_kb) >= size_kb) {
14072: msdos_xms_combine_emb_handles(emb_handle);
14073: if(emb_handle->size_kb > size_kb) {
14074: msdos_xms_split_emb_handle(emb_handle, size_kb);
14075: }
14076: } else {
14077: int old_handle = emb_handle->handle;
14078: int old_size_kb = emb_handle->size_kb;
14079: UINT8 *buffer = (UINT8 *)malloc(old_size_kb * 1024);
14080:
14081: memcpy(buffer, mem + emb_handle->address, old_size_kb * 1024);
14082: msdos_xms_free_emb_handle(emb_handle);
14083:
14084: if((emb_handle = msdos_xms_alloc_emb_handle(size_kb)) == NULL) {
14085: emb_handle = msdos_xms_alloc_emb_handle(old_size_kb); // should be always successed
14086: }
14087: emb_handle->handle = old_handle;
14088: memcpy(mem + emb_handle->address, buffer, old_size_kb * 1024);
14089: free(buffer);
14090: }
14091: } else if(emb_handle->size_kb > size_kb) {
14092: msdos_xms_split_emb_handle(emb_handle, size_kb);
14093: }
14094: if(emb_handle->size_kb != size_kb) {
14095: REG16(AX) = 0x0000;
14096: REG8(BL) = 0xa0;
14097: } else {
14098: REG16(AX) = 0x0001;
14099: REG8(BL) = 0x00;
14100: }
1.1.1.19 root 14101: }
14102: }
14103:
1.1.1.30 root 14104: inline void msdos_call_xms_0fh()
14105: {
14106: msdos_call_xms_0fh(REG16(BX));
14107: }
14108:
1.1.1.19 root 14109: inline void msdos_call_xms_10h()
14110: {
14111: int seg;
14112:
14113: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(DX), 0)) != -1) {
14114: REG16(AX) = 0x0001;
14115: REG16(BX) = seg;
14116: } else {
14117: REG16(AX) = 0x0000;
14118: REG8(BL) = 0xb0;
14119: REG16(DX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
14120: }
14121: }
14122:
14123: inline void msdos_call_xms_11h()
14124: {
14125: int mcb_seg = REG16(DX) - 1;
14126: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
14127:
14128: if(mcb->mz == 'M' || mcb->mz == 'Z') {
14129: msdos_mem_free(REG16(DX));
14130: REG16(AX) = 0x0001;
14131: REG8(BL) = 0x00;
14132: } else {
14133: REG16(AX) = 0x0000;
14134: REG8(BL) = 0xb2;
14135: }
14136: }
14137:
14138: inline void msdos_call_xms_12h()
14139: {
14140: int mcb_seg = REG16(DX) - 1;
14141: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
14142: int max_paragraphs;
14143:
14144: if(mcb->mz == 'M' || mcb->mz == 'Z') {
14145: if(!msdos_mem_realloc(REG16(DX), REG16(BX), &max_paragraphs)) {
14146: REG16(AX) = 0x0001;
14147: REG8(BL) = 0x00;
14148: } else {
14149: REG16(AX) = 0x0000;
14150: REG8(BL) = 0xb0;
14151: REG16(DX) = max_paragraphs;
14152: }
14153: } else {
14154: REG16(AX) = 0x0000;
14155: REG8(BL) = 0xb2;
14156: }
14157: }
14158:
1.1.1.29 root 14159: #if defined(HAS_I386)
14160:
14161: inline void msdos_call_xms_88h()
14162: {
14163: REG32(EAX) = REG32(EDX) = 0x0000;
14164:
1.1.1.30 root 14165: for(emb_handle_t *emb_handle = emb_handle_top; emb_handle != NULL; emb_handle = emb_handle->next) {
14166: if(emb_handle->handle == 0) {
14167: if(REG32(EAX) < emb_handle->size_kb) {
14168: REG32(EAX) = emb_handle->size_kb;
1.1.1.29 root 14169: }
1.1.1.30 root 14170: REG32(EDX) += emb_handle->size_kb;
1.1.1.29 root 14171: }
14172: }
14173:
14174: if(REG32(EAX) == 0 && REG32(EDX) == 0) {
14175: REG8(BL) = 0xa0;
14176: } else {
14177: REG8(BL) = 0x00;
14178: }
14179: REG32(ECX) = EMB_END - 1;
14180: }
14181:
14182: inline void msdos_call_xms_89h()
14183: {
1.1.1.30 root 14184: msdos_call_xms_09h(REG32(EDX));
1.1.1.29 root 14185: }
14186:
14187: inline void msdos_call_xms_8eh()
14188: {
1.1.1.30 root 14189: emb_handle_t *emb_handle = msdos_xms_get_emb_handle(REG16(DX));
14190:
14191: if(emb_handle == NULL) {
1.1.1.29 root 14192: REG16(AX) = 0x0000;
14193: REG8(BL) = 0xa2;
14194: } else {
14195: REG16(AX) = 0x0001;
1.1.1.30 root 14196: REG8(BH) = emb_handle->lock;
14197: REG16(CX) = msdos_xms_get_unused_emb_handle_count();
14198: REG32(EDX) = emb_handle->size_kb;
1.1.1.29 root 14199: }
14200: }
14201:
14202: inline void msdos_call_xms_8fh()
14203: {
1.1.1.30 root 14204: msdos_call_xms_0fh(REG32(EBX));
1.1.1.29 root 14205: }
14206:
14207: #endif
1.1.1.19 root 14208: #endif
14209:
1.1.1.26 root 14210: UINT16 msdos_get_equipment()
14211: {
14212: static UINT16 equip = 0;
14213:
14214: if(equip == 0) {
14215: #ifdef SUPPORT_FPU
14216: equip |= (1 << 1); // 80x87 coprocessor installed
14217: #endif
14218: equip |= (1 << 2); // pointing device installed (PS/2)
14219: equip |= (2 << 4); // initial video mode (80x25 color)
14220: // equip |= (1 << 8); // 0 if DMA installed
14221: equip |= (2 << 9); // number of serial ports
14222: 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 14223:
14224: // check only A: and B: if it is floppy drive
14225: DWORD dwDrives = GetLogicalDrives();
14226: int n = 0;
14227: for(int i = 0; i < 2; i++) {
14228: if(dwDrives & (1 << i)) {
14229: char volume[] = "A:\\";
14230: volume[0] = 'A' + i;
14231: if(GetDriveType(volume) == DRIVE_REMOVABLE) {
14232: n++;
14233: }
14234: }
14235: }
14236: if(n != 0) {
14237: equip |= (1 << 0); // floppy disk(s) installed
14238: n--;
14239: equip |= (n << 6); // number of floppies installed less 1
14240: }
14241: // if(joyGetNumDevs() != 0) {
14242: // equip |= (1 << 12); // game port installed
14243: // }
1.1.1.26 root 14244: }
14245: return(equip);
14246: }
14247:
1.1 root 14248: void msdos_syscall(unsigned num)
14249: {
1.1.1.22 root 14250: #ifdef ENABLE_DEBUG_SYSCALL
14251: if(num == 0x68) {
14252: // dummy interrupt for EMS (int 67h)
1.1.1.33 root 14253: 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 14254: } else if(num == 0x69) {
14255: // dummy interrupt for XMS (call far)
1.1.1.33 root 14256: 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 14257: } else if(num == 0x6a) {
14258: // dummy interrupt for case map routine pointed in the country info
14259: } else {
1.1.1.33 root 14260: 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 14261: }
14262: #endif
1.1.1.36 root 14263: // update cursor position
14264: if(cursor_moved) {
14265: pcbios_update_cursor_position();
14266: cursor_moved = false;
14267: }
1.1.1.33 root 14268: ctrl_break_detected = ctrl_break_pressed = ctrl_c_pressed = false;
1.1.1.22 root 14269:
1.1 root 14270: switch(num) {
14271: case 0x00:
1.1.1.28 root 14272: try {
14273: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
14274: error("division by zero\n");
14275: } catch(...) {
14276: fatalerror("division by zero detected, and failed to terminate current process\n");
14277: }
1.1 root 14278: break;
14279: case 0x04:
1.1.1.28 root 14280: try {
14281: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
14282: error("overflow\n");
14283: } catch(...) {
14284: fatalerror("overflow detected, and failed to terminate current process\n");
14285: }
1.1 root 14286: break;
14287: case 0x06:
14288: // NOTE: ish.com has illegal instruction...
1.1.1.14 root 14289: if(!ignore_illegal_insn) {
1.1.1.28 root 14290: try {
14291: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
14292: error("illegal instruction\n");
14293: } catch(...) {
14294: fatalerror("illegal instruction detected, and failed to terminate current process\n");
14295: }
1.1.1.14 root 14296: } else {
14297: #if defined(HAS_I386)
1.1.1.39 root 14298: m_eip = m_int6h_skip_eip;
14299: #elif defined(HAS_I286)
14300: m_pc = m_int6h_skip_pc;
1.1.1.14 root 14301: #else
1.1.1.39 root 14302: // 8086/80186 ignore an invalid opcode
1.1.1.14 root 14303: #endif
14304: }
1.1 root 14305: break;
1.1.1.33 root 14306: case 0x09:
14307: // ctrl-break is pressed
14308: if(raise_int_1bh) {
14309: #if defined(HAS_I386)
14310: m_ext = 0; // not an external interrupt
14311: i386_trap(0x1b, 1, 0);
14312: m_ext = 1;
14313: #else
14314: PREFIX86(_interrupt)(0x1b);
14315: #endif
14316: raise_int_1bh = false;
14317: }
1.1.1.8 root 14318: case 0x08:
1.1.1.14 root 14319: // pcbios_irq0(); // this causes too slow emulation...
1.1.1.8 root 14320: case 0x0b:
14321: case 0x0c:
14322: case 0x0d:
14323: case 0x0e:
14324: case 0x0f:
14325: // EOI
14326: pic[0].isr &= ~(1 << (num - 0x08));
14327: pic_update();
14328: break;
1.1 root 14329: case 0x10:
14330: // PC BIOS - Video
1.1.1.14 root 14331: if(!restore_console_on_exit) {
1.1.1.15 root 14332: change_console_size(scr_width, scr_height);
1.1 root 14333: }
1.1.1.3 root 14334: m_CF = 0;
1.1 root 14335: switch(REG8(AH)) {
1.1.1.16 root 14336: case 0x00: pcbios_int_10h_00h(); break;
1.1 root 14337: case 0x01: pcbios_int_10h_01h(); break;
14338: case 0x02: pcbios_int_10h_02h(); break;
14339: case 0x03: pcbios_int_10h_03h(); break;
14340: case 0x05: pcbios_int_10h_05h(); break;
14341: case 0x06: pcbios_int_10h_06h(); break;
14342: case 0x07: pcbios_int_10h_07h(); break;
14343: case 0x08: pcbios_int_10h_08h(); break;
14344: case 0x09: pcbios_int_10h_09h(); break;
14345: case 0x0a: pcbios_int_10h_0ah(); break;
14346: case 0x0b: break;
1.1.1.40 root 14347: case 0x0c: pcbios_int_10h_0ch(); break;
14348: case 0x0d: pcbios_int_10h_0dh(); break;
1.1 root 14349: case 0x0e: pcbios_int_10h_0eh(); break;
14350: case 0x0f: pcbios_int_10h_0fh(); break;
14351: case 0x10: break;
1.1.1.14 root 14352: case 0x11: pcbios_int_10h_11h(); break;
14353: case 0x12: pcbios_int_10h_12h(); break;
1.1 root 14354: case 0x13: pcbios_int_10h_13h(); break;
1.1.1.30 root 14355: case 0x18: pcbios_int_10h_18h(); break;
1.1.1.14 root 14356: case 0x1a: pcbios_int_10h_1ah(); break;
1.1.1.24 root 14357: case 0x1b: REG8(AL) = 0x00; break; // functionality/state information is not supported
14358: case 0x1c: REG8(AL) = 0x00; break; // save/restore video state is not supported
1.1 root 14359: case 0x1d: pcbios_int_10h_1dh(); break;
1.1.1.24 root 14360: case 0x1e: REG8(AL) = 0x00; break; // flat-panel functions are not supported
14361: case 0x1f: REG8(AL) = 0x00; break; // xga functions are not supported
1.1.1.22 root 14362: case 0x4f: pcbios_int_10h_4fh(); break;
1.1.1.30 root 14363: case 0x6f: break;
1.1.1.22 root 14364: case 0x80: m_CF = 1; break; // unknown
14365: case 0x81: m_CF = 1; break; // unknown
1.1 root 14366: case 0x82: pcbios_int_10h_82h(); break;
1.1.1.22 root 14367: case 0x83: pcbios_int_10h_83h(); break;
14368: case 0x8b: break;
14369: case 0x8c: m_CF = 1; break; // unknown
14370: case 0x8d: m_CF = 1; break; // unknown
14371: case 0x8e: m_CF = 1; break; // unknown
14372: case 0x90: pcbios_int_10h_90h(); break;
14373: case 0x91: pcbios_int_10h_91h(); break;
14374: case 0x92: break;
14375: case 0x93: break;
14376: case 0xef: pcbios_int_10h_efh(); break;
1.1.1.24 root 14377: case 0xfa: break; // ega register interface library is not installed
1.1 root 14378: case 0xfe: pcbios_int_10h_feh(); break;
14379: case 0xff: pcbios_int_10h_ffh(); break;
14380: default:
1.1.1.22 root 14381: 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));
14382: m_CF = 1;
1.1 root 14383: break;
14384: }
14385: break;
14386: case 0x11:
14387: // PC BIOS - Get Equipment List
1.1.1.26 root 14388: REG16(AX) = msdos_get_equipment();
1.1 root 14389: break;
14390: case 0x12:
14391: // PC BIOS - Get Memory Size
1.1.1.33 root 14392: REG16(AX) = *(UINT16 *)(mem + 0x413);
1.1 root 14393: break;
14394: case 0x13:
14395: // PC BIOS - Disk
1.1.1.22 root 14396: // 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 14397: REG8(AH) = 0xff;
1.1.1.3 root 14398: m_CF = 1;
1.1 root 14399: break;
14400: case 0x14:
14401: // PC BIOS - Serial I/O
1.1.1.25 root 14402: switch(REG8(AH)) {
14403: case 0x00: pcbios_int_14h_00h(); break;
14404: case 0x01: pcbios_int_14h_01h(); break;
14405: case 0x02: pcbios_int_14h_02h(); break;
14406: case 0x03: pcbios_int_14h_03h(); break;
14407: case 0x04: pcbios_int_14h_04h(); break;
14408: case 0x05: pcbios_int_14h_05h(); break;
14409: default:
14410: 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));
14411: break;
14412: }
1.1 root 14413: break;
14414: case 0x15:
14415: // PC BIOS
1.1.1.3 root 14416: m_CF = 0;
1.1 root 14417: switch(REG8(AH)) {
1.1.1.14 root 14418: case 0x10: pcbios_int_15h_10h(); break;
1.1 root 14419: case 0x23: pcbios_int_15h_23h(); break;
14420: case 0x24: pcbios_int_15h_24h(); break;
1.1.1.24 root 14421: case 0x41: break;
1.1 root 14422: case 0x49: pcbios_int_15h_49h(); break;
1.1.1.22 root 14423: case 0x50: pcbios_int_15h_50h(); break;
1.1.1.30 root 14424: case 0x53: pcbios_int_15h_53h(); break;
1.1 root 14425: case 0x86: pcbios_int_15h_86h(); break;
14426: case 0x87: pcbios_int_15h_87h(); break;
14427: case 0x88: pcbios_int_15h_88h(); break;
14428: case 0x89: pcbios_int_15h_89h(); break;
1.1.1.21 root 14429: case 0x8a: pcbios_int_15h_8ah(); break;
1.1.1.22 root 14430: case 0xc0: // PS/2 ???
14431: case 0xc1:
14432: case 0xc2:
1.1.1.30 root 14433: case 0xc3: // PS50+ ???
14434: case 0xc4:
1.1.1.22 root 14435: REG8(AH) = 0x86;
14436: m_CF = 1;
14437: break;
1.1.1.3 root 14438: #if defined(HAS_I386)
1.1 root 14439: case 0xc9: pcbios_int_15h_c9h(); break;
1.1.1.3 root 14440: #endif
1.1 root 14441: case 0xca: pcbios_int_15h_cah(); break;
1.1.1.22 root 14442: case 0xe8: pcbios_int_15h_e8h(); break;
1.1 root 14443: default:
1.1.1.22 root 14444: 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));
14445: REG8(AH) = 0x86;
1.1.1.3 root 14446: m_CF = 1;
1.1 root 14447: break;
14448: }
14449: break;
14450: case 0x16:
14451: // PC BIOS - Keyboard
1.1.1.3 root 14452: m_CF = 0;
1.1 root 14453: switch(REG8(AH)) {
14454: case 0x00: pcbios_int_16h_00h(); break;
14455: case 0x01: pcbios_int_16h_01h(); break;
14456: case 0x02: pcbios_int_16h_02h(); break;
14457: case 0x03: pcbios_int_16h_03h(); break;
14458: case 0x05: pcbios_int_16h_05h(); break;
14459: case 0x10: pcbios_int_16h_00h(); break;
14460: case 0x11: pcbios_int_16h_01h(); break;
14461: case 0x12: pcbios_int_16h_12h(); break;
14462: case 0x13: pcbios_int_16h_13h(); break;
14463: case 0x14: pcbios_int_16h_14h(); break;
1.1.1.24 root 14464: case 0x55: pcbios_int_16h_55h(); break;
1.1.1.30 root 14465: case 0x6f: pcbios_int_16h_6fh(); break;
1.1.1.22 root 14466: case 0xda: break; // unknown
14467: case 0xff: break; // unknown
1.1 root 14468: default:
1.1.1.22 root 14469: 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 14470: break;
14471: }
14472: break;
14473: case 0x17:
14474: // PC BIOS - Printer
1.1.1.37 root 14475: m_CF = 0;
14476: switch(REG8(AH)) {
14477: case 0x00: pcbios_int_17h_00h(); break;
14478: case 0x01: pcbios_int_17h_01h(); break;
14479: case 0x02: pcbios_int_17h_02h(); break;
14480: case 0x03: pcbios_int_17h_03h(); break;
14481: case 0x50: pcbios_int_17h_50h(); break;
14482: case 0x51: pcbios_int_17h_51h(); break;
14483: case 0x52: pcbios_int_17h_52h(); break;
14484: case 0x84: pcbios_int_17h_84h(); break;
14485: case 0x85: pcbios_int_17h_85h(); break;
14486: default:
14487: 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));
14488: break;
14489: }
1.1 root 14490: break;
14491: case 0x1a:
14492: // PC BIOS - Timer
1.1.1.3 root 14493: m_CF = 0;
1.1 root 14494: switch(REG8(AH)) {
14495: case 0x00: pcbios_int_1ah_00h(); break;
14496: case 0x01: break;
14497: case 0x02: pcbios_int_1ah_02h(); break;
14498: case 0x03: break;
14499: case 0x04: pcbios_int_1ah_04h(); break;
14500: case 0x05: break;
14501: case 0x0a: pcbios_int_1ah_0ah(); break;
14502: case 0x0b: break;
1.1.1.14 root 14503: case 0x35: break; // Word Perfect Third Party Interface?
14504: case 0x36: break; // Word Perfect Third Party Interface
14505: case 0x70: break; // SNAP? (Simple Network Application Protocol)
1.1 root 14506: default:
1.1.1.22 root 14507: 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 14508: break;
14509: }
14510: break;
1.1.1.33 root 14511: case 0x1b:
14512: mem[0x471] = 0x00;
14513: break;
1.1 root 14514: case 0x20:
1.1.1.28 root 14515: try {
14516: msdos_process_terminate(SREG(CS), retval, 1);
14517: } catch(...) {
14518: fatalerror("failed to terminate the process (PSP=%04X) by int 20h\n", SREG(CS));
14519: }
1.1 root 14520: break;
14521: case 0x21:
14522: // MS-DOS System Call
1.1.1.3 root 14523: m_CF = 0;
1.1.1.28 root 14524: try {
14525: switch(REG8(AH)) {
14526: case 0x00: msdos_int_21h_00h(); break;
14527: case 0x01: msdos_int_21h_01h(); break;
14528: case 0x02: msdos_int_21h_02h(); break;
14529: case 0x03: msdos_int_21h_03h(); break;
14530: case 0x04: msdos_int_21h_04h(); break;
14531: case 0x05: msdos_int_21h_05h(); break;
14532: case 0x06: msdos_int_21h_06h(); break;
14533: case 0x07: msdos_int_21h_07h(); break;
14534: case 0x08: msdos_int_21h_08h(); break;
14535: case 0x09: msdos_int_21h_09h(); break;
14536: case 0x0a: msdos_int_21h_0ah(); break;
14537: case 0x0b: msdos_int_21h_0bh(); break;
14538: case 0x0c: msdos_int_21h_0ch(); break;
14539: case 0x0d: msdos_int_21h_0dh(); break;
14540: case 0x0e: msdos_int_21h_0eh(); break;
14541: case 0x0f: msdos_int_21h_0fh(); break;
14542: case 0x10: msdos_int_21h_10h(); break;
14543: case 0x11: msdos_int_21h_11h(); break;
14544: case 0x12: msdos_int_21h_12h(); break;
14545: case 0x13: msdos_int_21h_13h(); break;
14546: case 0x14: msdos_int_21h_14h(); break;
14547: case 0x15: msdos_int_21h_15h(); break;
14548: case 0x16: msdos_int_21h_16h(); break;
14549: case 0x17: msdos_int_21h_17h(); break;
14550: case 0x18: msdos_int_21h_18h(); break;
14551: case 0x19: msdos_int_21h_19h(); break;
14552: case 0x1a: msdos_int_21h_1ah(); break;
14553: case 0x1b: msdos_int_21h_1bh(); break;
14554: case 0x1c: msdos_int_21h_1ch(); break;
14555: case 0x1d: msdos_int_21h_1dh(); break;
14556: case 0x1e: msdos_int_21h_1eh(); break;
14557: case 0x1f: msdos_int_21h_1fh(); break;
14558: case 0x20: msdos_int_21h_20h(); break;
14559: case 0x21: msdos_int_21h_21h(); break;
14560: case 0x22: msdos_int_21h_22h(); break;
14561: case 0x23: msdos_int_21h_23h(); break;
14562: case 0x24: msdos_int_21h_24h(); break;
14563: case 0x25: msdos_int_21h_25h(); break;
14564: case 0x26: msdos_int_21h_26h(); break;
14565: case 0x27: msdos_int_21h_27h(); break;
14566: case 0x28: msdos_int_21h_28h(); break;
14567: case 0x29: msdos_int_21h_29h(); break;
14568: case 0x2a: msdos_int_21h_2ah(); break;
14569: case 0x2b: msdos_int_21h_2bh(); break;
14570: case 0x2c: msdos_int_21h_2ch(); break;
14571: case 0x2d: msdos_int_21h_2dh(); break;
14572: case 0x2e: msdos_int_21h_2eh(); break;
14573: case 0x2f: msdos_int_21h_2fh(); break;
14574: case 0x30: msdos_int_21h_30h(); break;
14575: case 0x31: msdos_int_21h_31h(); break;
14576: case 0x32: msdos_int_21h_32h(); break;
14577: case 0x33: msdos_int_21h_33h(); break;
14578: case 0x34: msdos_int_21h_34h(); break;
14579: case 0x35: msdos_int_21h_35h(); break;
14580: case 0x36: msdos_int_21h_36h(); break;
14581: case 0x37: msdos_int_21h_37h(); break;
14582: case 0x38: msdos_int_21h_38h(); break;
14583: case 0x39: msdos_int_21h_39h(0); break;
14584: case 0x3a: msdos_int_21h_3ah(0); break;
14585: case 0x3b: msdos_int_21h_3bh(0); break;
14586: case 0x3c: msdos_int_21h_3ch(); break;
14587: case 0x3d: msdos_int_21h_3dh(); break;
14588: case 0x3e: msdos_int_21h_3eh(); break;
14589: case 0x3f: msdos_int_21h_3fh(); break;
14590: case 0x40: msdos_int_21h_40h(); break;
14591: case 0x41: msdos_int_21h_41h(0); break;
14592: case 0x42: msdos_int_21h_42h(); break;
14593: case 0x43: msdos_int_21h_43h(0); break;
14594: case 0x44: msdos_int_21h_44h(); break;
14595: case 0x45: msdos_int_21h_45h(); break;
14596: case 0x46: msdos_int_21h_46h(); break;
14597: case 0x47: msdos_int_21h_47h(0); break;
14598: case 0x48: msdos_int_21h_48h(); break;
14599: case 0x49: msdos_int_21h_49h(); break;
14600: case 0x4a: msdos_int_21h_4ah(); break;
14601: case 0x4b: msdos_int_21h_4bh(); break;
14602: case 0x4c: msdos_int_21h_4ch(); break;
14603: case 0x4d: msdos_int_21h_4dh(); break;
14604: case 0x4e: msdos_int_21h_4eh(); break;
14605: case 0x4f: msdos_int_21h_4fh(); break;
14606: case 0x50: msdos_int_21h_50h(); break;
14607: case 0x51: msdos_int_21h_51h(); break;
14608: case 0x52: msdos_int_21h_52h(); break;
1.1.1.33 root 14609: // 0x53: Translate BIOS Parameter Block to Drive Param Bock
1.1.1.28 root 14610: case 0x54: msdos_int_21h_54h(); break;
14611: case 0x55: msdos_int_21h_55h(); break;
14612: case 0x56: msdos_int_21h_56h(0); break;
14613: case 0x57: msdos_int_21h_57h(); break;
14614: case 0x58: msdos_int_21h_58h(); break;
14615: case 0x59: msdos_int_21h_59h(); break;
14616: case 0x5a: msdos_int_21h_5ah(); break;
14617: case 0x5b: msdos_int_21h_5bh(); break;
14618: case 0x5c: msdos_int_21h_5ch(); break;
14619: case 0x5d: msdos_int_21h_5dh(); break;
1.1.1.33 root 14620: // 0x5e: MS-Network
1.1.1.30 root 14621: case 0x5f: msdos_int_21h_5fh(); break;
1.1.1.28 root 14622: case 0x60: msdos_int_21h_60h(0); break;
14623: case 0x61: msdos_int_21h_61h(); break;
14624: case 0x62: msdos_int_21h_62h(); break;
14625: case 0x63: msdos_int_21h_63h(); break;
1.1.1.33 root 14626: // 0x64: Set Device Driver Lockahead Flag
1.1.1.28 root 14627: case 0x65: msdos_int_21h_65h(); break;
14628: case 0x66: msdos_int_21h_66h(); break;
14629: case 0x67: msdos_int_21h_67h(); break;
14630: case 0x68: msdos_int_21h_68h(); break;
14631: case 0x69: msdos_int_21h_69h(); break;
14632: case 0x6a: msdos_int_21h_6ah(); break;
14633: case 0x6b: msdos_int_21h_6bh(); break;
14634: case 0x6c: msdos_int_21h_6ch(0); break;
1.1.1.33 root 14635: // 0x6d: Find First ROM Program
14636: // 0x6e: Find Next ROM Program
14637: // 0x6f: Get/Set ROM Scan Start Address
14638: // 0x70: Windows95 - Get/Set Internationalization Information
1.1.1.28 root 14639: case 0x71:
1.1.1.33 root 14640: // Windows95 - Long Filename Functions
1.1.1.28 root 14641: switch(REG8(AL)) {
14642: case 0x0d: msdos_int_21h_710dh(); break;
14643: case 0x39: msdos_int_21h_39h(1); break;
14644: case 0x3a: msdos_int_21h_3ah(1); break;
14645: case 0x3b: msdos_int_21h_3bh(1); break;
14646: case 0x41: msdos_int_21h_7141h(1); break;
14647: case 0x43: msdos_int_21h_43h(1); break;
14648: case 0x47: msdos_int_21h_47h(1); break;
14649: case 0x4e: msdos_int_21h_714eh(); break;
14650: case 0x4f: msdos_int_21h_714fh(); break;
14651: case 0x56: msdos_int_21h_56h(1); break;
14652: case 0x60: msdos_int_21h_60h(1); break;
14653: case 0x6c: msdos_int_21h_6ch(1); break;
14654: case 0xa0: msdos_int_21h_71a0h(); break;
14655: case 0xa1: msdos_int_21h_71a1h(); break;
14656: case 0xa6: msdos_int_21h_71a6h(); break;
14657: case 0xa7: msdos_int_21h_71a7h(); break;
14658: case 0xa8: msdos_int_21h_71a8h(); break;
1.1.1.33 root 14659: // 0xa9: Server Create/Open File
1.1.1.28 root 14660: case 0xaa: msdos_int_21h_71aah(); break;
14661: default:
14662: 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));
14663: REG16(AX) = 0x7100;
14664: m_CF = 1;
14665: break;
14666: }
14667: break;
14668: // 0x72: Windows95 beta - LFN FindClose
14669: case 0x73:
1.1.1.33 root 14670: // Windows95 - FAT32 Functions
1.1.1.28 root 14671: switch(REG8(AL)) {
14672: case 0x00: msdos_int_21h_7300h(); break;
1.1.1.33 root 14673: // 0x01: Set Drive Locking ???
1.1.1.28 root 14674: case 0x02: msdos_int_21h_7302h(); break;
14675: case 0x03: msdos_int_21h_7303h(); break;
1.1.1.33 root 14676: // 0x04: Set DPB to Use for Formatting
14677: // 0x05: Extended Absolute Disk Read/Write
1.1.1.28 root 14678: default:
14679: 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));
14680: REG16(AX) = 0x7300;
14681: m_CF = 1;
14682: break;
14683: }
1.1 root 14684: break;
1.1.1.30 root 14685: case 0xdb: msdos_int_21h_dbh(); break;
14686: case 0xdc: msdos_int_21h_dch(); break;
1.1 root 14687: default:
1.1.1.22 root 14688: 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 14689: REG16(AX) = 0x01;
1.1.1.3 root 14690: m_CF = 1;
1.1 root 14691: break;
14692: }
1.1.1.28 root 14693: } catch(int error) {
14694: REG16(AX) = error;
14695: m_CF = 1;
14696: } catch(...) {
14697: REG16(AX) = 0x1f; // general failure
1.1.1.3 root 14698: m_CF = 1;
1.1 root 14699: }
1.1.1.3 root 14700: if(m_CF) {
1.1.1.23 root 14701: sda_t *sda = (sda_t *)(mem + SDA_TOP);
14702: sda->extended_error_code = REG16(AX);
14703: switch(sda->extended_error_code) {
14704: case 4: // Too many open files
14705: case 8: // Insufficient memory
14706: sda->error_class = 1; // Out of resource
14707: break;
14708: case 5: // Access denied
14709: sda->error_class = 3; // Authorization
14710: break;
14711: case 7: // Memory control block destroyed
14712: sda->error_class = 4; // Internal
14713: break;
14714: case 2: // File not found
14715: case 3: // Path not found
14716: case 15: // Invaid drive specified
14717: case 18: // No more files
14718: sda->error_class = 8; // Not found
14719: break;
14720: case 32: // Sharing violation
14721: case 33: // Lock violation
14722: sda->error_class = 10; // Locked
14723: break;
14724: // case 16: // Removal of current directory attempted
14725: case 19: // Attempted write on protected disk
14726: case 21: // Drive not ready
14727: // case 29: // Write failure
14728: // case 30: // Read failure
14729: // case 82: // Cannot create subdirectory
14730: sda->error_class = 11; // Media
14731: break;
14732: case 80: // File already exists
14733: sda->error_class = 12; // Already exist
14734: break;
14735: default:
14736: sda->error_class = 13; // Unknown
14737: break;
14738: }
14739: sda->suggested_action = 1; // Retry
14740: sda->locus_of_last_error = 1; // Unknown
1.1 root 14741: }
1.1.1.33 root 14742: if(ctrl_break_checking && ctrl_break_detected) {
1.1.1.26 root 14743: // raise int 23h
14744: #if defined(HAS_I386)
14745: m_ext = 0; // not an external interrupt
14746: i386_trap(0x23, 1, 0);
14747: m_ext = 1;
14748: #else
14749: PREFIX86(_interrupt)(0x23);
14750: #endif
14751: }
1.1 root 14752: break;
14753: case 0x22:
14754: fatalerror("int 22h (terminate address)\n");
14755: case 0x23:
1.1.1.28 root 14756: try {
14757: msdos_process_terminate(current_psp, (retval & 0xff) | 0x100, 1);
14758: } catch(...) {
14759: fatalerror("failed to terminate the current process by int 23h\n");
14760: }
1.1 root 14761: break;
14762: case 0x24:
1.1.1.32 root 14763: /*
1.1.1.28 root 14764: try {
14765: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
14766: } catch(...) {
14767: fatalerror("failed to terminate the current process by int 24h\n");
14768: }
1.1.1.32 root 14769: */
14770: msdos_int_24h();
1.1 root 14771: break;
14772: case 0x25:
14773: msdos_int_25h();
14774: break;
14775: case 0x26:
14776: msdos_int_26h();
14777: break;
14778: case 0x27:
1.1.1.28 root 14779: try {
14780: msdos_int_27h();
14781: } catch(...) {
14782: fatalerror("failed to terminate the process (PSP=%04X) by int 27h\n", SREG(CS));
14783: }
1.1 root 14784: break;
14785: case 0x28:
14786: Sleep(10);
1.1.1.35 root 14787: REQUEST_HARDWRE_UPDATE();
1.1 root 14788: break;
14789: case 0x29:
14790: msdos_int_29h();
14791: break;
14792: case 0x2e:
14793: msdos_int_2eh();
14794: break;
14795: case 0x2f:
14796: // multiplex interrupt
14797: switch(REG8(AH)) {
1.1.1.22 root 14798: case 0x05: msdos_int_2fh_05h(); break;
14799: case 0x11: msdos_int_2fh_11h(); break;
1.1.1.21 root 14800: case 0x12: msdos_int_2fh_12h(); break;
1.1.1.30 root 14801: case 0x13: msdos_int_2fh_13h(); break;
1.1.1.22 root 14802: case 0x14: msdos_int_2fh_14h(); break;
14803: case 0x15: msdos_int_2fh_15h(); break;
1.1 root 14804: case 0x16: msdos_int_2fh_16h(); break;
1.1.1.22 root 14805: case 0x19: msdos_int_2fh_19h(); break;
1.1 root 14806: case 0x1a: msdos_int_2fh_1ah(); break;
1.1.1.30 root 14807: case 0x40: msdos_int_2fh_40h(); break;
1.1 root 14808: case 0x43: msdos_int_2fh_43h(); break;
1.1.1.22 root 14809: case 0x46: msdos_int_2fh_46h(); break;
14810: case 0x48: msdos_int_2fh_48h(); break;
1.1 root 14811: case 0x4a: msdos_int_2fh_4ah(); break;
1.1.1.22 root 14812: case 0x4b: msdos_int_2fh_4bh(); break;
1.1 root 14813: case 0x4f: msdos_int_2fh_4fh(); break;
1.1.1.22 root 14814: case 0x55: msdos_int_2fh_55h(); break;
1.1.1.24 root 14815: case 0xad: msdos_int_2fh_adh(); break;
1.1 root 14816: case 0xae: msdos_int_2fh_aeh(); break;
1.1.1.34 root 14817: case 0xb7: msdos_int_2fh_b7h(); break;
1.1.1.30 root 14818: // Installation Check
14819: case 0x01: // PRINT.COM
14820: case 0x02: // PC LAN Program Redirector
14821: case 0x06: // ASSIGN
14822: case 0x08: // DRIVER.SYS
14823: case 0x10: // SHARE
14824: case 0x17: // Clibboard functions
14825: case 0x1b: // XMA2EMS.SYS
14826: case 0x23: // DR DOS 5.0 GRAFTABL
14827: case 0x27: // DR-DOR 6.0 TaskMAX
14828: case 0x2e: // Novell DOS 7 GRAFTABL
1.1.1.33 root 14829: case 0x39: // Kingswood TSR INTERFACE
14830: case 0x41: // DOS Enhanced LAN Manager 2.0+ MINIPOP/NETPOPUP
1.1.1.30 root 14831: case 0x45: // PROF.COM
14832: case 0x51: // ODIHELP.EXE
1.1.1.33 root 14833: case 0x52: // JAM.SYS v1.10+
1.1.1.30 root 14834: case 0x54: // POWER.EXE
14835: case 0x56: // INTERLNK
1.1.1.33 root 14836: case 0x57: // IOMEGA DRIVERS
1.1.1.30 root 14837: case 0x70: // License Service API
1.1.1.33 root 14838: case 0x72: // SRDISK v1.30+
1.1.1.30 root 14839: case 0x7a: // Novell NetWare
1.1.1.33 root 14840: case 0x7f: // PRINDIR v9.0
14841: case 0x80: // FAX BIOS
14842: case 0x81: // Nanosoft, Inc. TurboNET redirector
14843: case 0x82: // Nanosoft, Inc. CAPDOS
14844: case 0x89: // WHOA!.COM
14845: case 0x90: // Resident AID
1.1.1.30 root 14846: case 0x94: // MICRO.EXE
1.1.1.33 root 14847: case 0x97: // Micro Focus COBOL v3.1.31
14848: case 0x98: // Micro Focus COBOL v3.1.31
14849: case 0x99: // DOS Navigator II
14850: case 0x9e: // INTMON v2.1
14851: case 0x9f: // INTCFG v2.1
14852: case 0xa9: // METZTSR.COM
14853: case 0xab: // SRSoft MODAL PC v2
1.1.1.30 root 14854: case 0xac: // GRAPHICS.COM
1.1.1.33 root 14855: case 0xaf: // WinDOS v2.11
1.1.1.30 root 14856: case 0xb0: // GRAFTABLE.COM
1.1.1.33 root 14857: case 0xb4: // IBM PC3270 EMULATION PROG v3
1.1.1.30 root 14858: case 0xb8: // NETWORK
14859: case 0xb9: // RECEIVER.COM
14860: case 0xbc: // EGA.SYS
1.1.1.33 root 14861: case 0xbe: // REDVIEW
1.1.1.30 root 14862: case 0xbf: // PC LAN Program - REDIRIFS.EXE
14863: case 0xc0: // Novell LSL.COM
1.1.1.33 root 14864: case 0xc1: // Personal NetWare - STPIPX v1.00
14865: case 0xc3: // SETWPR.COM
14866: case 0xc5: // PC-DOS Econet v1.05
14867: case 0xc7: // COLAP.COM
14868: case 0xc9: // ThunderByte???
14869: case 0xca: // TBSCANX
14870: case 0xcb: // Communicating Applications Specification
14871: case 0xcc: // Tsoft NFSDRVR
14872: case 0xcd: // SWELL.EXE
14873: case 0xcf: // TEMPLEXX 1.0
14874: case 0xd0: // Lotus CD/Networker
1.1.1.30 root 14875: case 0xd2: // PCL-838.EXE
1.1.1.33 root 14876: case 0xd3: // TeleReplica
14877: case 0xd6: // VEDIT VSWAP
14878: case 0xd7: // Banyan VINES v4+
1.1.1.30 root 14879: case 0xd8: // Novell NetWare Lite - CLIENT.EXE
1.1.1.33 root 14880: case 0xda: // ZyXEL ZFAX v1.x
14881: case 0xdb: // ZyXEL ZFAX v2+
14882: case 0xdc: // GOLD.COM
14883: case 0xdd: // MIXFIX.EXE
14884: case 0xde: // Novell Netware - RPRINTER, NPRINTER
14885: case 0xdf: // HyperWare programs
14886: case 0xe0: // SETDRVER.COM v2.10+
14887: case 0xe1: // Phantom2 v1.1+
14888: case 0xe3: // ANARKEY.COM
14889: case 0xed: // Phar Lap DOS EXTENDERS
14890: case 0xee: // XVIEW
14891: case 0xf0: // 4MAP
14892: case 0xf1: // DOS EXTENDER
14893: case 0xf2: // WINX
14894: case 0xf4: // FINDIRQ.COM
14895: case 0xf7: // AUTOPARK.COM
14896: case 0xf8: // SuperStor PRO 2XON.COM
14897: case 0xfb: // AutoBraille v1.1A
14898: case 0xfe: // PC-NFS ???
14899: case 0xff: // Topware Network Operating System
1.1.1.30 root 14900: switch(REG8(AL)) {
14901: case 0x00:
14902: // This is not installed
14903: // REG8(AL) = 0x00;
14904: break;
1.1.1.33 root 14905: case 0x01:
14906: // Banyan VINES v4+ is not installed
14907: if(REG8(AH) == 0xd7 && REG16(BX) == 0x0000) {
14908: break;
14909: }
1.1.1.30 root 14910: default:
14911: 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));
14912: REG16(AX) = 0x01;
14913: m_CF = 1;
14914: break;
14915: }
14916: break;
1.1.1.22 root 14917: default:
14918: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
14919: break;
1.1 root 14920: }
14921: break;
1.1.1.24 root 14922: case 0x33:
14923: switch(REG8(AH)) {
14924: case 0x00:
14925: // Mouse
14926: switch(REG8(AL)) {
14927: case 0x00: msdos_int_33h_0000h(); break;
14928: case 0x01: msdos_int_33h_0001h(); break;
14929: case 0x02: msdos_int_33h_0002h(); break;
14930: case 0x03: msdos_int_33h_0003h(); break;
1.1.1.34 root 14931: case 0x04: msdos_int_33h_0004h(); break;
1.1.1.24 root 14932: case 0x05: msdos_int_33h_0005h(); break;
14933: case 0x06: msdos_int_33h_0006h(); break;
14934: case 0x07: msdos_int_33h_0007h(); break;
14935: case 0x08: msdos_int_33h_0008h(); break;
14936: case 0x09: msdos_int_33h_0009h(); break;
1.1.1.34 root 14937: case 0x0a: break; // Define Text Cursor
1.1.1.24 root 14938: case 0x0b: msdos_int_33h_000bh(); break;
14939: case 0x0c: msdos_int_33h_000ch(); break;
1.1.1.34 root 14940: case 0x0d: break; // Light Pen Emulation On
14941: case 0x0e: break; // Light Pen Emulation Off
1.1.1.24 root 14942: case 0x0f: msdos_int_33h_000fh(); break;
1.1.1.34 root 14943: case 0x10: break; // Define Screen Region for Updating
1.1.1.24 root 14944: case 0x11: msdos_int_33h_0011h(); break;
1.1.1.34 root 14945: case 0x12: REG16(AX) = 0xffff; break; // Set Large Graphics Cursor Block
14946: case 0x13: break; // Define Double-Speed Threshold
1.1.1.24 root 14947: case 0x14: msdos_int_33h_0014h(); break;
14948: case 0x15: msdos_int_33h_0015h(); break;
14949: case 0x16: msdos_int_33h_0016h(); break;
14950: case 0x17: msdos_int_33h_0017h(); break;
14951: case 0x1a: msdos_int_33h_001ah(); break;
14952: case 0x1b: msdos_int_33h_001bh(); break;
14953: case 0x1d: msdos_int_33h_001dh(); break;
14954: case 0x1e: msdos_int_33h_001eh(); break;
1.1.1.34 root 14955: case 0x1f: msdos_int_33h_001fh(); break;
14956: case 0x20: msdos_int_33h_0020h(); break;
1.1.1.24 root 14957: case 0x21: msdos_int_33h_0021h(); break;
14958: case 0x22: msdos_int_33h_0022h(); break;
14959: case 0x23: msdos_int_33h_0023h(); break;
14960: case 0x24: msdos_int_33h_0024h(); break;
14961: case 0x26: msdos_int_33h_0026h(); break;
14962: case 0x2a: msdos_int_33h_002ah(); break;
1.1.1.34 root 14963: case 0x2f: break; // Mouse Hardware Reset
1.1.1.24 root 14964: case 0x31: msdos_int_33h_0031h(); break;
14965: case 0x32: msdos_int_33h_0032h(); break;
14966: default:
14967: 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));
14968: break;
14969: }
14970: break;
14971: default:
14972: 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));
14973: break;
14974: }
14975: break;
1.1.1.19 root 14976: case 0x68:
14977: // dummy interrupt for EMS (int 67h)
14978: switch(REG8(AH)) {
14979: case 0x40: msdos_int_67h_40h(); break;
14980: case 0x41: msdos_int_67h_41h(); break;
14981: case 0x42: msdos_int_67h_42h(); break;
14982: case 0x43: msdos_int_67h_43h(); break;
14983: case 0x44: msdos_int_67h_44h(); break;
14984: case 0x45: msdos_int_67h_45h(); break;
14985: case 0x46: msdos_int_67h_46h(); break;
14986: case 0x47: msdos_int_67h_47h(); break;
14987: case 0x48: msdos_int_67h_48h(); break;
1.1.1.20 root 14988: // 0x49: LIM EMS - Reserved - Get I/O Port Address (Undocumented in EMS 3.2)
14989: // 0x4a: LIM EMS - Reserved - Get Translation Array (Undocumented in EMS 3.2)
1.1.1.19 root 14990: case 0x4b: msdos_int_67h_4bh(); break;
14991: case 0x4c: msdos_int_67h_4ch(); break;
14992: case 0x4d: msdos_int_67h_4dh(); break;
1.1.1.20 root 14993: case 0x4e: msdos_int_67h_4eh(); break;
1.1.1.21 root 14994: case 0x4f: msdos_int_67h_4fh(); break;
1.1.1.20 root 14995: case 0x50: msdos_int_67h_50h(); break;
1.1.1.19 root 14996: case 0x51: msdos_int_67h_51h(); break;
1.1.1.20 root 14997: case 0x52: msdos_int_67h_52h(); break;
1.1.1.19 root 14998: case 0x53: msdos_int_67h_53h(); break;
14999: case 0x54: msdos_int_67h_54h(); break;
1.1.1.20 root 15000: // 0x55: LIM EMS 4.0 - Alter Page Map And JUMP
15001: // 0x56: LIM EMS 4.0 - Alter Page Map And CALL
15002: case 0x57: msdos_int_67h_57h(); break;
15003: case 0x58: msdos_int_67h_58h(); break;
15004: // 0x59: LIM EMS 4.0 - Get Expanded Memory Hardware Information (for DOS Kernel)
15005: case 0x5a: msdos_int_67h_5ah(); break;
15006: // 0x5b: LIM EMS 4.0 - Alternate Map Register Set (for DOS Kernel)
15007: // 0x5c: LIM EMS 4.0 - Prepate Expanded Memory Hardware For Warm Boot
15008: // 0x5d: LIM EMS 4.0 - Enable/Disable OS Function Set Functions (for DOS Kernel)
1.1.1.31 root 15009: // 0x60: EEMS - Get Physical Window Array
15010: // 0x61: EEMS - Generic Accelerator Card Support
15011: // 0x68: EEMS - Get Address of All Pge Frames om System
15012: // 0x69: EEMS - Map Page into Frame
15013: // 0x6a: EEMS - Page Mapping
15014: // 0xde: VCPI
1.1.1.30 root 15015: case 0xde: msdos_int_67h_deh(); break;
1.1.1.19 root 15016: default:
1.1.1.22 root 15017: 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 15018: REG8(AH) = 0x84;
15019: break;
15020: }
15021: break;
15022: #ifdef SUPPORT_XMS
15023: case 0x69:
15024: // dummy interrupt for XMS (call far)
1.1.1.28 root 15025: try {
15026: switch(REG8(AH)) {
15027: case 0x00: msdos_call_xms_00h(); break;
15028: case 0x01: msdos_call_xms_01h(); break;
15029: case 0x02: msdos_call_xms_02h(); break;
15030: case 0x03: msdos_call_xms_03h(); break;
15031: case 0x04: msdos_call_xms_04h(); break;
15032: case 0x05: msdos_call_xms_05h(); break;
15033: case 0x06: msdos_call_xms_06h(); break;
15034: case 0x07: msdos_call_xms_07h(); break;
15035: case 0x08: msdos_call_xms_08h(); break;
15036: case 0x09: msdos_call_xms_09h(); break;
15037: case 0x0a: msdos_call_xms_0ah(); break;
15038: case 0x0b: msdos_call_xms_0bh(); break;
15039: case 0x0c: msdos_call_xms_0ch(); break;
15040: case 0x0d: msdos_call_xms_0dh(); break;
15041: case 0x0e: msdos_call_xms_0eh(); break;
15042: case 0x0f: msdos_call_xms_0fh(); break;
15043: case 0x10: msdos_call_xms_10h(); break;
15044: case 0x11: msdos_call_xms_11h(); break;
15045: case 0x12: msdos_call_xms_12h(); break;
1.1.1.29 root 15046: #if defined(HAS_I386)
15047: case 0x88: msdos_call_xms_88h(); break;
15048: case 0x89: msdos_call_xms_89h(); break;
15049: case 0x8e: msdos_call_xms_8eh(); break;
15050: case 0x8f: msdos_call_xms_8fh(); break;
15051: #endif
1.1.1.28 root 15052: default:
15053: 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));
15054: REG16(AX) = 0x0000;
15055: REG8(BL) = 0x80; // function not implemented
15056: break;
15057: }
15058: } catch(...) {
1.1.1.19 root 15059: REG16(AX) = 0x0000;
1.1.1.28 root 15060: REG8(BL) = 0x8f; // unrecoverable driver error
1.1.1.19 root 15061: }
15062: break;
15063: #endif
15064: case 0x6a:
1.1.1.24 root 15065: // irq12 (mouse)
15066: mouse_push_ax = REG16(AX);
15067: mouse_push_bx = REG16(BX);
15068: mouse_push_cx = REG16(CX);
15069: mouse_push_dx = REG16(DX);
15070: mouse_push_si = REG16(SI);
15071: mouse_push_di = REG16(DI);
15072:
1.1.1.34 root 15073: if(/*mouse.hidden == 0 && */mouse.call_addr.dw != 0) {
1.1.1.24 root 15074: REG16(AX) = mouse.status_irq;
15075: REG16(BX) = mouse.get_buttons();
1.1.1.34 root 15076: REG16(CX) = max(mouse.min_position.x & ~7, min(mouse.max_position.x & ~7, mouse.position.x));
15077: REG16(DX) = max(mouse.min_position.y & ~7, min(mouse.max_position.y & ~7, mouse.position.y));
1.1.1.24 root 15078: REG16(SI) = REG16(CX) * mouse.mickey.x / 8;
15079: REG16(DI) = REG16(DX) * mouse.mickey.y / 8;
15080:
15081: mem[0xfffd0 + 0x02] = 0x9a; // call far
15082: mem[0xfffd0 + 0x03] = mouse.call_addr.w.l & 0xff;
15083: mem[0xfffd0 + 0x04] = mouse.call_addr.w.l >> 8;
15084: mem[0xfffd0 + 0x05] = mouse.call_addr.w.h & 0xff;
15085: mem[0xfffd0 + 0x06] = mouse.call_addr.w.h >> 8;
15086: } else {
15087: mem[0xfffd0 + 0x02] = 0x90; // nop
15088: mem[0xfffd0 + 0x03] = 0x90; // nop
15089: mem[0xfffd0 + 0x04] = 0x90; // nop
15090: mem[0xfffd0 + 0x05] = 0x90; // nop
15091: mem[0xfffd0 + 0x06] = 0x90; // nop
15092: }
15093: break;
15094: case 0x6b:
15095: // end of irq12 (mouse)
15096: REG16(AX) = mouse_push_ax;
15097: REG16(BX) = mouse_push_bx;
15098: REG16(CX) = mouse_push_cx;
15099: REG16(DX) = mouse_push_dx;
15100: REG16(SI) = mouse_push_si;
15101: REG16(DI) = mouse_push_di;
15102:
15103: // EOI
15104: if((pic[1].isr &= ~(1 << 4)) == 0) {
15105: pic[0].isr &= ~(1 << 2); // master
15106: }
15107: pic_update();
15108: break;
15109: case 0x6c:
1.1.1.19 root 15110: // dummy interrupt for case map routine pointed in the country info
15111: if(REG8(AL) >= 0x80) {
15112: char tmp[2] = {0};
15113: tmp[0] = REG8(AL);
15114: my_strupr(tmp);
15115: REG8(AL) = tmp[0];
15116: }
15117: break;
1.1.1.27 root 15118: case 0x6d:
15119: // dummy interrupt for font read routine pointed by int 15h, ax=5000h
15120: REG8(AL) = 0x86; // not supported
15121: m_CF = 1;
15122: break;
1.1.1.32 root 15123: case 0x6e:
15124: // dummy interrupt for parameter error message read routine pointed by int 2fh, ax=122eh, dl=08h
15125: {
15126: UINT16 code = REG16(AX);
15127: if(code & 0xf0) {
15128: code = (code & 7) | ((code & 0x10) >> 1);
15129: }
15130: for(int i = 0; i < array_length(param_error_table); i++) {
15131: if(param_error_table[i].code == code || param_error_table[i].code == (UINT16)-1) {
15132: const char *message = NULL;
15133: if(active_code_page == 932) {
15134: message = param_error_table[i].message_japanese;
15135: }
15136: if(message == NULL) {
15137: message = param_error_table[i].message_english;
15138: }
15139: *(UINT8 *)(mem + WORK_TOP) = strlen(message);
15140: strcpy((char *)(mem + WORK_TOP + 1), message);
15141:
15142: SREG(ES) = WORK_TOP >> 4;
15143: i386_load_segment_descriptor(ES);
15144: REG16(DI) = 0x0000;
15145: break;
15146: }
15147: }
15148: }
15149: break;
1.1.1.8 root 15150: case 0x70:
15151: case 0x71:
15152: case 0x72:
15153: case 0x73:
15154: case 0x74:
15155: case 0x75:
15156: case 0x76:
15157: case 0x77:
15158: // EOI
15159: if((pic[1].isr &= ~(1 << (num - 0x70))) == 0) {
15160: pic[0].isr &= ~(1 << 2); // master
15161: }
15162: pic_update();
15163: break;
1.1 root 15164: default:
1.1.1.22 root 15165: // 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 15166: break;
15167: }
15168:
15169: // update cursor position
15170: if(cursor_moved) {
1.1.1.36 root 15171: pcbios_update_cursor_position();
1.1 root 15172: cursor_moved = false;
15173: }
15174: }
15175:
15176: // init
15177:
15178: int msdos_init(int argc, char *argv[], char *envp[], int standard_env)
15179: {
15180: // init file handler
15181: memset(file_handler, 0, sizeof(file_handler));
15182: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
15183: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
15184: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
1.1.1.21 root 15185: #ifdef MAP_AUX_DEVICE_TO_FILE
1.1 root 15186: if(_open("stdaux.txt", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
1.1.1.21 root 15187: #else
15188: if(_open("NUL", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
15189: #endif
15190: msdos_file_handler_open(3, "STDAUX", 0, 2, 0x80c0, 0);
1.1 root 15191: }
1.1.1.21 root 15192: if(_open("NUL", _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 4) {
1.1.1.37 root 15193: msdos_file_handler_open(4, "STDPRN", 0, 1, 0xa8c0, 0, 0, 1); // LPT1
1.1.1.21 root 15194: }
1.1 root 15195: _dup2(0, DUP_STDIN);
15196: _dup2(1, DUP_STDOUT);
15197: _dup2(2, DUP_STDERR);
1.1.1.21 root 15198: _dup2(3, DUP_STDAUX);
15199: _dup2(4, DUP_STDPRN);
1.1 root 15200:
1.1.1.24 root 15201: // init mouse
15202: memset(&mouse, 0, sizeof(mouse));
1.1.1.34 root 15203: mouse.enabled = true; // from DOSBox
15204: mouse.hidden = 1; // hidden in default ???
15205: mouse.old_hidden = 1; // from DOSBox
15206: mouse.max_position.x = 8 * (scr_width - 1);
15207: mouse.max_position.y = 8 * (scr_height - 1);
1.1.1.24 root 15208: mouse.mickey.x = 8;
15209: mouse.mickey.y = 16;
15210:
1.1.1.26 root 15211: #ifdef SUPPORT_XMS
15212: // init xms
15213: msdos_xms_init();
15214: #endif
15215:
1.1 root 15216: // init process
15217: memset(process, 0, sizeof(process));
15218:
1.1.1.13 root 15219: // init dtainfo
15220: msdos_dta_info_init();
15221:
1.1 root 15222: // init memory
15223: memset(mem, 0, sizeof(mem));
15224:
15225: // bios data area
1.1.1.23 root 15226: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 15227: CONSOLE_SCREEN_BUFFER_INFO csbi;
15228: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 15229: CONSOLE_FONT_INFO cfi;
15230: GetCurrentConsoleFont(hStdout, FALSE, &cfi);
15231:
15232: int regen = min(scr_width * scr_height * 2, 0x8000);
15233: text_vram_top_address = TEXT_VRAM_TOP;
15234: text_vram_end_address = text_vram_top_address + regen;
15235: shadow_buffer_top_address = SHADOW_BUF_TOP;
15236: shadow_buffer_end_address = shadow_buffer_top_address + regen;
15237:
15238: if(regen > 0x4000) {
15239: regen = 0x8000;
15240: vram_pages = 1;
15241: } else if(regen > 0x2000) {
15242: regen = 0x4000;
15243: vram_pages = 2;
15244: } else if(regen > 0x1000) {
15245: regen = 0x2000;
15246: vram_pages = 4;
15247: } else {
15248: regen = 0x1000;
15249: vram_pages = 8;
15250: }
1.1 root 15251:
1.1.1.25 root 15252: *(UINT16 *)(mem + 0x400) = 0x3f8; // com1 port address
15253: *(UINT16 *)(mem + 0x402) = 0x2f8; // com2 port address
1.1.1.29 root 15254: *(UINT16 *)(mem + 0x404) = 0x3e8; // com3 port address
15255: *(UINT16 *)(mem + 0x406) = 0x2e8; // com4 port address
1.1.1.25 root 15256: *(UINT16 *)(mem + 0x408) = 0x378; // lpt1 port address
1.1.1.37 root 15257: *(UINT16 *)(mem + 0x40a) = 0x278; // lpt2 port address
15258: *(UINT16 *)(mem + 0x40c) = 0x3bc; // lpt3 port address
1.1.1.32 root 15259: #ifdef EXT_BIOS_TOP
1.1.1.25 root 15260: *(UINT16 *)(mem + 0x40e) = EXT_BIOS_TOP >> 4;
1.1.1.32 root 15261: #endif
1.1.1.26 root 15262: *(UINT16 *)(mem + 0x410) = msdos_get_equipment();
1.1.1.33 root 15263: *(UINT16 *)(mem + 0x413) = MEMORY_END >> 10;
1.1.1.41! root 15264: *(UINT16 *)(mem + 0x41a) = 0x1e;
! 15265: *(UINT16 *)(mem + 0x41c) = 0x1e;
1.1 root 15266: *(UINT8 *)(mem + 0x449) = 0x03;//0x73;
1.1.1.14 root 15267: *(UINT16 *)(mem + 0x44a) = csbi.dwSize.X;
15268: *(UINT16 *)(mem + 0x44c) = regen;
1.1 root 15269: *(UINT16 *)(mem + 0x44e) = 0;
15270: *(UINT8 *)(mem + 0x450) = csbi.dwCursorPosition.X;
1.1.1.14 root 15271: *(UINT8 *)(mem + 0x451) = csbi.dwCursorPosition.Y - scr_top;
1.1 root 15272: *(UINT8 *)(mem + 0x460) = 7;
15273: *(UINT8 *)(mem + 0x461) = 7;
15274: *(UINT8 *)(mem + 0x462) = 0;
15275: *(UINT16 *)(mem + 0x463) = 0x3d4;
1.1.1.19 root 15276: *(UINT8 *)(mem + 0x465) = 0x09;
15277: *(UINT32 *)(mem + 0x46c) = get_ticks_since_midnight(timeGetTime());
1.1.1.40 root 15278: *(UINT16 *)(mem + 0x472) = 0x4321; // preserve memory in cpu reset
1.1.1.41! root 15279: *(UINT16 *)(mem + 0x480) = 0x1e;
! 15280: *(UINT16 *)(mem + 0x482) = 0x3e;
1.1.1.14 root 15281: *(UINT8 *)(mem + 0x484) = csbi.srWindow.Bottom - csbi.srWindow.Top;
15282: *(UINT8 *)(mem + 0x485) = cfi.dwFontSize.Y;
15283: *(UINT8 *)(mem + 0x487) = 0x60;
15284: *(UINT8 *)(mem + 0x496) = 0x10; // enhanced keyboard installed
1.1.1.32 root 15285: #ifdef EXT_BIOS_TOP
1.1.1.25 root 15286: *(UINT16 *)(mem + EXT_BIOS_TOP) = 1;
1.1.1.32 root 15287: #endif
1.1.1.14 root 15288:
15289: // initial screen
15290: SMALL_RECT rect;
15291: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
15292: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
15293: for(int y = 0, ofs1 = TEXT_VRAM_TOP, ofs2 = SHADOW_BUF_TOP; y < scr_height; y++) {
15294: for(int x = 0; x < scr_width; x++) {
15295: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Char.AsciiChar;
15296: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Attributes;
15297: }
15298: }
1.1 root 15299:
1.1.1.19 root 15300: // init mcb
1.1 root 15301: int seg = MEMORY_TOP >> 4;
1.1.1.19 root 15302:
15303: // iret table
15304: // note: int 2eh vector should address the routine in command.com,
15305: // and some softwares invite (int 2eh vector segment) - 1 must address the mcb of command.com.
15306: // so move iret table into allocated memory block
15307: // http://www5c.biglobe.ne.jp/~ecb/assembler2/2_6.html
1.1.1.33 root 15308: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, IRET_SIZE >> 4);
1.1.1.19 root 15309: IRET_TOP = seg << 4;
15310: seg += IRET_SIZE >> 4;
1.1.1.25 root 15311: memset(mem + IRET_TOP, 0xcf, IRET_SIZE); // iret
1.1.1.19 root 15312:
15313: // dummy xms/ems device
1.1.1.33 root 15314: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, XMS_SIZE >> 4);
1.1.1.19 root 15315: XMS_TOP = seg << 4;
15316: seg += XMS_SIZE >> 4;
15317:
15318: // environment
1.1.1.33 root 15319: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, ENV_SIZE >> 4);
1.1 root 15320: int env_seg = seg;
15321: int ofs = 0;
1.1.1.32 root 15322: char env_append[ENV_SIZE] = {0}, append_added = 0;
15323: char comspec_added = 0;
1.1.1.33 root 15324: char lastdrive_added = 0;
1.1.1.32 root 15325: char env_msdos_path[ENV_SIZE] = {0};
15326: char env_path[ENV_SIZE] = {0}, path_added = 0;
1.1.1.33 root 15327: char prompt_added = 0;
1.1.1.32 root 15328: char env_temp[ENV_SIZE] = {0}, temp_added = 0, tmp_added = 0;
1.1.1.33 root 15329: char tz_added = 0;
1.1.1.32 root 15330: char *path, *short_path;
15331:
15332: if((path = getenv("MSDOS_APPEND")) != NULL) {
15333: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
15334: strcpy(env_append, short_path);
15335: }
15336: }
15337: if((path = getenv("APPEND")) != NULL) {
15338: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
15339: if(env_append[0] != '\0') {
15340: strcat(env_append, ";");
15341: }
15342: strcat(env_append, short_path);
15343: }
15344: }
15345:
15346: if((path = msdos_search_command_com(argv[0], env_path)) != NULL) {
15347: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
15348: strcpy(comspec_path, short_path);
15349: }
15350: }
15351: if((path = getenv("MSDOS_COMSPEC")) != NULL && _access(path, 0) == 0) {
15352: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
15353: strcpy(comspec_path, short_path);
15354: }
15355: }
1.1 root 15356:
1.1.1.28 root 15357: if((path = getenv("MSDOS_PATH")) != NULL) {
1.1.1.32 root 15358: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
15359: strcpy(env_msdos_path, short_path);
15360: strcpy(env_path, short_path);
1.1.1.14 root 15361: }
15362: }
1.1.1.28 root 15363: if((path = getenv("PATH")) != NULL) {
1.1.1.32 root 15364: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
15365: if(env_path[0] != '\0') {
15366: strcat(env_path, ";");
15367: }
15368: strcat(env_path, short_path);
1.1.1.9 root 15369: }
15370: }
1.1.1.32 root 15371:
15372: if(GetTempPath(ENV_SIZE, env_temp) != 0) {
15373: strcpy(env_temp, msdos_get_multiple_short_path(env_temp));
1.1.1.15 root 15374: }
1.1.1.32 root 15375: for(int i = 0; i < 4; i++) {
15376: static const char *name[4] = {"MSDOS_TEMP", "MSDOS_TMP", "TEMP", "TMP"};
15377: if((path = getenv(name[i])) != NULL && _access(path, 0) == 0) {
15378: if((short_path = msdos_get_multiple_short_path(path)) != NULL && short_path[0] != '\0') {
15379: strcpy(env_temp, short_path);
15380: break;
15381: }
15382: }
1.1.1.24 root 15383: }
1.1.1.32 root 15384:
1.1.1.9 root 15385: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1 root 15386: // lower to upper
1.1.1.28 root 15387: char tmp[ENV_SIZE], name[ENV_SIZE];
1.1 root 15388: strcpy(tmp, *p);
15389: for(int i = 0;; i++) {
15390: if(tmp[i] == '=') {
15391: tmp[i] = '\0';
15392: sprintf(name, ";%s;", tmp);
1.1.1.25 root 15393: my_strupr(name);
1.1 root 15394: tmp[i] = '=';
15395: break;
15396: } else if(tmp[i] >= 'a' && tmp[i] <= 'z') {
1.1.1.28 root 15397: tmp[i] = (tmp[i] - 'a') + 'A';
1.1 root 15398: }
15399: }
1.1.1.33 root 15400: if(strstr(";MSDOS_APPEND;MSDOS_COMSPEC;MSDOS_LASTDRIVE;MSDOS_TEMP;MSDOS_TMP;MSDOS_TZ;", name) != NULL) {
15401: // ignore MSDOS_(APPEND/COMSPEC/LASTDRIVE/TEMP/TMP/TZ)
15402: } else if(standard_env && strstr(";APPEND;COMSPEC;LASTDRIVE;MSDOS_PATH;PATH;PROMPT;TEMP;TMP;TZ;", name) == NULL) {
1.1.1.18 root 15403: // ignore non standard environments
15404: } else {
1.1.1.33 root 15405: if(strncmp(tmp, "APPEND=", 7) == 0) {
1.1.1.32 root 15406: if(env_append[0] != '\0') {
15407: sprintf(tmp, "APPEND=%s", env_append);
15408: } else {
15409: sprintf(tmp, "APPEND=%s", msdos_get_multiple_short_path(tmp + 7));
15410: }
15411: append_added = 1;
15412: } else if(strncmp(tmp, "COMSPEC=", 8) == 0) {
1.1.1.14 root 15413: strcpy(tmp, "COMSPEC=C:\\COMMAND.COM");
1.1.1.32 root 15414: comspec_added = 1;
1.1.1.33 root 15415: } else if(strncmp(tmp, "LASTDRIVE=", 10) == 0) {
15416: char *env = getenv("MSDOS_LASTDRIVE");
15417: if(env != NULL) {
15418: sprintf(tmp, "LASTDRIVE=%s", env);
15419: }
15420: lastdrive_added = 1;
15421: } else if(strncmp(tmp, "MSDOS_PATH=", 11) == 0) {
1.1.1.28 root 15422: if(env_msdos_path[0] != '\0') {
15423: sprintf(tmp, "MSDOS_PATH=%s", env_msdos_path);
15424: } else {
15425: sprintf(tmp, "MSDOS_PATH=%s", msdos_get_multiple_short_path(tmp + 11));
15426: }
1.1.1.33 root 15427: } else if(strncmp(tmp, "PATH=", 5) == 0) {
1.1.1.28 root 15428: if(env_path[0] != '\0') {
15429: sprintf(tmp, "PATH=%s", env_path);
15430: } else {
15431: sprintf(tmp, "PATH=%s", msdos_get_multiple_short_path(tmp + 5));
15432: }
1.1.1.32 root 15433: path_added = 1;
1.1.1.33 root 15434: } else if(strncmp(tmp, "PROMPT=", 7) == 0) {
15435: prompt_added = 1;
1.1.1.28 root 15436: } else if(strncmp(tmp, "TEMP=", 5) == 0) {
15437: if(env_temp[0] != '\0') {
15438: sprintf(tmp, "TEMP=%s", env_temp);
15439: } else {
15440: sprintf(tmp, "TEMP=%s", msdos_get_multiple_short_path(tmp + 5));
15441: }
1.1.1.32 root 15442: temp_added = 1;
1.1.1.33 root 15443: } else if(strncmp(tmp, "TMP=", 4) == 0) {
1.1.1.28 root 15444: if(env_temp[0] != '\0') {
15445: sprintf(tmp, "TMP=%s", env_temp);
15446: } else {
15447: sprintf(tmp, "TMP=%s", msdos_get_multiple_short_path(tmp + 4));
1.1 root 15448: }
1.1.1.32 root 15449: tmp_added = 1;
1.1.1.33 root 15450: } else if(strncmp(tmp, "TZ=", 3) == 0) {
15451: char *env = getenv("MSDOS_TZ");
15452: if(env != NULL) {
15453: sprintf(tmp, "TZ=%s", env);
15454: }
15455: tz_added = 1;
1.1 root 15456: }
15457: int len = strlen(tmp);
1.1.1.14 root 15458: if(ofs + len + 1 + (2 + (8 + 1 + 3)) + 2 > ENV_SIZE) {
1.1 root 15459: fatalerror("too many environments\n");
15460: }
15461: memcpy(mem + (seg << 4) + ofs, tmp, len);
15462: ofs += len + 1;
15463: }
15464: }
1.1.1.32 root 15465: if(!append_added && env_append[0] != '\0') {
15466: #define SET_ENV(name, value) { \
15467: char tmp[ENV_SIZE]; \
15468: sprintf(tmp, "%s=%s", name, value); \
15469: int len = strlen(tmp); \
15470: if(ofs + len + 1 + (2 + (8 + 1 + 3)) + 2 > ENV_SIZE) { \
15471: fatalerror("too many environments\n"); \
15472: } \
15473: memcpy(mem + (seg << 4) + ofs, tmp, len); \
15474: ofs += len + 1; \
15475: }
15476: SET_ENV("APPEND", env_append);
15477: }
15478: if(!comspec_added) {
15479: SET_ENV("COMSPEC", "C:\\COMMAND.COM");
15480: }
1.1.1.33 root 15481: if(!lastdrive_added) {
15482: SET_ENV("LASTDRIVE", "Z");
15483: }
1.1.1.32 root 15484: if(!path_added) {
15485: SET_ENV("PATH", env_path);
15486: }
1.1.1.33 root 15487: if(!prompt_added) {
15488: SET_ENV("PROMPT", "$P$G");
15489: }
1.1.1.32 root 15490: if(!temp_added) {
15491: SET_ENV("TEMP", env_temp);
15492: }
15493: if(!tmp_added) {
15494: SET_ENV("TMP", env_temp);
15495: }
1.1.1.33 root 15496: if(!tz_added) {
15497: TIME_ZONE_INFORMATION tzi;
15498: HKEY hKey, hSubKey;
15499: char tzi_std_name[64];
15500: char tz_std[8] = "GMT";
15501: char tz_dlt[8] = "GST";
15502: char tz_value[32];
15503:
15504: // timezone name from GetTimeZoneInformation may not be english
15505: bool daylight = (GetTimeZoneInformation(&tzi) != TIME_ZONE_ID_UNKNOWN);
15506: setlocale(LC_CTYPE, "");
15507: wcstombs(tzi_std_name, tzi.StandardName, sizeof(tzi_std_name));
15508:
15509: // get english timezone name from registry
15510: if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones", 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
15511: for(DWORD i = 0; !tz_added; i++) {
15512: char reg_name[256], sub_key[1024], std_name[256];
15513: DWORD size;
15514: FILETIME ftTime;
15515: LONG result = RegEnumKeyEx(hKey, i, reg_name, &(size = array_length(reg_name)), NULL, NULL, NULL, &ftTime);
15516:
15517: if(result == ERROR_SUCCESS) {
15518: sprintf(sub_key, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\%s", reg_name);
15519: if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, sub_key, 0, KEY_QUERY_VALUE, &hSubKey) == ERROR_SUCCESS) {
15520: if(RegQueryValueEx(hSubKey, "Std", NULL, NULL, (LPBYTE)std_name, &(size = array_length(std_name))) == ERROR_SUCCESS) {
15521: // search english timezone name from table
1.1.1.37 root 15522: if(strcmp(std_name, tzi_std_name) == 0) {
1.1.1.33 root 15523: for(int j = 0; j < array_length(tz_table); j++) {
15524: if(strcmp(reg_name, tz_table[j].name) == 0 && (tz_table[j].lcid == 0 || tz_table[j].lcid == GetUserDefaultLCID())) {
15525: if(tz_table[j].std != NULL) {
15526: strcpy(tz_std, tz_table[j].std);
15527: }
15528: if(tz_table[j].dlt != NULL) {
15529: strcpy(tz_dlt, tz_table[j].dlt);
15530: }
15531: tz_added = 1;
15532: break;
15533: }
15534: }
15535: }
15536: }
15537: RegCloseKey(hSubKey);
15538: }
15539: } else if(result == ERROR_NO_MORE_ITEMS) {
15540: break;
15541: }
15542: }
15543: RegCloseKey(hKey);
15544: }
15545: if((tzi.Bias % 60) != 0) {
15546: sprintf(tz_value, "%s%d:%2d", tz_std, tzi.Bias / 60, abs(tzi.Bias % 60));
15547: } else {
15548: sprintf(tz_value, "%s%d", tz_std, tzi.Bias / 60);
15549: }
15550: if(daylight) {
15551: strcat(tz_value, tz_dlt);
15552: }
15553: SET_ENV("TZ", tz_value);
15554: }
1.1 root 15555: seg += (ENV_SIZE >> 4);
15556:
15557: // psp
1.1.1.33 root 15558: msdos_mcb_create(seg++, 'M', PSP_SYSTEM, PSP_SIZE >> 4);
1.1 root 15559: current_psp = seg;
1.1.1.35 root 15560: psp_t *psp = msdos_psp_create(seg, seg + (PSP_SIZE >> 4), -1, env_seg);
15561: psp->parent_psp = current_psp;
1.1 root 15562: seg += (PSP_SIZE >> 4);
15563:
1.1.1.19 root 15564: // first free mcb in conventional memory
1.1.1.33 root 15565: msdos_mcb_create(seg, 'M', 0, (MEMORY_END >> 4) - seg - 2);
1.1.1.8 root 15566: first_mcb = seg;
15567:
1.1.1.19 root 15568: // dummy mcb to link to umb
1.1.1.33 root 15569: #if 0
1.1.1.39 root 15570: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', PSP_SYSTEM, (UMB_TOP >> 4) - (MEMORY_END >> 4), "SC"); // link umb
1.1.1.33 root 15571: #else
1.1.1.39 root 15572: msdos_mcb_create((MEMORY_END >> 4) - 1, 'Z', PSP_SYSTEM, 0, "SC"); // unlink umb
1.1.1.33 root 15573: #endif
1.1.1.19 root 15574:
15575: // first free mcb in upper memory block
1.1.1.8 root 15576: msdos_mcb_create(UMB_TOP >> 4, 'Z', 0, (UMB_END >> 4) - (UMB_TOP >> 4) - 1);
1.1 root 15577:
1.1.1.29 root 15578: #ifdef SUPPORT_HMA
15579: // first free mcb in high memory area
15580: msdos_hma_mcb_create(0x10, 0, 0xffe0, 0);
15581: #endif
15582:
1.1.1.26 root 15583: // interrupt vector
15584: for(int i = 0; i < 0x80; i++) {
15585: *(UINT16 *)(mem + 4 * i + 0) = i;
15586: *(UINT16 *)(mem + 4 * i + 2) = (IRET_TOP >> 4);
15587: }
1.1.1.35 root 15588: *(UINT16 *)(mem + 4 * 0x08 + 0) = 0x0018; // fffd:0018 irq0 (system timer)
1.1.1.26 root 15589: *(UINT16 *)(mem + 4 * 0x08 + 2) = 0xfffd;
15590: *(UINT16 *)(mem + 4 * 0x22 + 0) = 0x0000; // ffff:0000 boot
15591: *(UINT16 *)(mem + 4 * 0x22 + 2) = 0xffff;
15592: *(UINT16 *)(mem + 4 * 0x67 + 0) = 0x0012; // xxxx:0012 ems
15593: *(UINT16 *)(mem + 4 * 0x67 + 2) = XMS_TOP >> 4;
15594: *(UINT16 *)(mem + 4 * 0x74 + 0) = 0x0000; // fffd:0000 irq12 (mouse)
15595: *(UINT16 *)(mem + 4 * 0x74 + 2) = 0xfffd;
15596:
1.1.1.29 root 15597: // dummy devices (NUL -> CON -> ... -> CONFIG$ -> EMMXXXX0)
1.1.1.26 root 15598: static const struct {
15599: UINT16 attributes;
15600: char *dev_name;
15601: } dummy_devices[] = {
15602: {0x8013, "CON "},
15603: {0x8000, "AUX "},
15604: {0xa0c0, "PRN "},
15605: {0x8008, "CLOCK$ "},
15606: {0x8000, "COM1 "},
15607: {0xa0c0, "LPT1 "},
15608: {0xa0c0, "LPT2 "},
15609: {0xa0c0, "LPT3 "},
15610: {0x8000, "COM2 "},
15611: {0x8000, "COM3 "},
15612: {0x8000, "COM4 "},
1.1.1.30 root 15613: // {0xc000, "CONFIG$ "},
15614: {0xc000, "$IBMADSP"}, // for windows3.1 setup.exe
1.1.1.26 root 15615: };
15616: static const UINT8 dummy_device_routine[] = {
15617: // from NUL device of Windows 98 SE
15618: // or word ptr ES:[BX+03],0100
15619: 0x26, 0x81, 0x4f, 0x03, 0x00, 0x01,
15620: // retf
15621: 0xcb,
15622: };
1.1.1.29 root 15623: device_t *last = NULL;
1.1.1.32 root 15624: for(int i = 0; i < array_length(dummy_devices); i++) {
1.1.1.26 root 15625: device_t *device = (device_t *)(mem + DEVICE_TOP + 22 + 18 * i);
1.1.1.29 root 15626: device->next_driver.w.l = 22 + 18 * (i + 1);
15627: device->next_driver.w.h = DEVICE_TOP >> 4;
1.1.1.26 root 15628: device->attributes = dummy_devices[i].attributes;
1.1.1.29 root 15629: device->strategy = DEVICE_SIZE - sizeof(dummy_device_routine);
15630: device->interrupt = DEVICE_SIZE - sizeof(dummy_device_routine) + 6;
1.1.1.26 root 15631: memcpy(device->dev_name, dummy_devices[i].dev_name, 8);
1.1.1.29 root 15632: last = device;
15633: }
15634: if(last != NULL) {
15635: last->next_driver.w.l = 0;
15636: last->next_driver.w.h = XMS_TOP >> 4;
1.1.1.26 root 15637: }
1.1.1.29 root 15638: memcpy(mem + DEVICE_TOP + DEVICE_SIZE - sizeof(dummy_device_routine), dummy_device_routine, sizeof(dummy_device_routine));
1.1.1.26 root 15639:
1.1.1.25 root 15640: // dos info
15641: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
15642: dos_info->magic_word = 1;
15643: dos_info->first_mcb = MEMORY_TOP >> 4;
15644: dos_info->first_dpb.w.l = 0;
15645: dos_info->first_dpb.w.h = DPB_TOP >> 4;
15646: dos_info->first_sft.w.l = 0;
15647: dos_info->first_sft.w.h = SFT_TOP >> 4;
1.1.1.41! root 15648: dos_info->clock_device.w.l = 22 + 18 * 3; // CLOCK$ is the 4th device in IO.SYS
1.1.1.25 root 15649: dos_info->clock_device.w.h = DEVICE_TOP >> 4;
1.1.1.26 root 15650: dos_info->con_device.w.l = 22 + 18 * 0; // CON is the 1st device in IO.SYS
1.1.1.25 root 15651: dos_info->con_device.w.h = DEVICE_TOP >> 4;
15652: dos_info->max_sector_len = 512;
15653: dos_info->disk_buf_info.w.l = offsetof(dos_info_t, disk_buf_heads);
15654: dos_info->disk_buf_info.w.h = DOS_INFO_TOP >> 4;
15655: dos_info->cds.w.l = 0;
15656: dos_info->cds.w.h = CDS_TOP >> 4;
15657: dos_info->fcb_table.w.l = 0;
15658: dos_info->fcb_table.w.h = FCB_TABLE_TOP >> 4;
15659: dos_info->last_drive = 'Z' - 'A' + 1;
15660: dos_info->buffers_x = 20;
15661: dos_info->buffers_y = 0;
15662: dos_info->boot_drive = 'C' - 'A' + 1;
1.1.1.29 root 15663: dos_info->nul_device.next_driver.w.l = 22;
15664: dos_info->nul_device.next_driver.w.h = DEVICE_TOP >> 4;
1.1.1.25 root 15665: dos_info->nul_device.attributes = 0x8004;
1.1.1.29 root 15666: dos_info->nul_device.strategy = DOS_INFO_SIZE - sizeof(dummy_device_routine);
15667: dos_info->nul_device.interrupt = DOS_INFO_SIZE - sizeof(dummy_device_routine) + 6;
1.1.1.25 root 15668: memcpy(dos_info->nul_device.dev_name, "NUL ", 8);
15669: dos_info->disk_buf_heads.w.l = 0;
15670: dos_info->disk_buf_heads.w.h = DISK_BUF_TOP >> 4;
1.1.1.39 root 15671: dos_info->umb_linked = (((mcb_t *)(mem + MEMORY_END - 16))->mz == 'M' ? 0x01 : 0x00);
1.1.1.25 root 15672: dos_info->first_umb_fcb = UMB_TOP >> 4;
15673: dos_info->first_mcb_2 = MEMORY_TOP >> 4;
1.1.1.29 root 15674: memcpy(mem + DOS_INFO_TOP + DOS_INFO_SIZE - sizeof(dummy_device_routine), dummy_device_routine, sizeof(dummy_device_routine));
1.1.1.25 root 15675:
15676: char *env;
15677: if((env = getenv("LASTDRIVE")) != NULL) {
15678: if(env[0] >= 'A' && env[0] <= 'Z') {
15679: dos_info->last_drive = env[0] - 'A' + 1;
15680: } else if(env[0] >= 'a' && env[0] <= 'z') {
15681: dos_info->last_drive = env[0] - 'a' + 1;
15682: }
15683: }
15684: if((env = getenv("windir")) != NULL) {
15685: if(env[0] >= 'A' && env[0] <= 'Z') {
15686: dos_info->boot_drive = env[0] - 'A' + 1;
15687: } else if(env[0] >= 'a' && env[0] <= 'z') {
15688: dos_info->boot_drive = env[0] - 'a' + 1;
15689: }
15690: }
15691: #if defined(HAS_I386)
15692: dos_info->i386_or_later = 1;
15693: #else
15694: dos_info->i386_or_later = 0;
15695: #endif
15696: dos_info->ext_mem_size = (min(MAX_MEM, 0x4000000) - 0x100000) >> 10;
15697:
1.1.1.27 root 15698: // ems (int 67h) and xms
1.1.1.25 root 15699: device_t *xms_device = (device_t *)(mem + XMS_TOP);
15700: xms_device->next_driver.w.l = 0xffff;
15701: xms_device->next_driver.w.h = 0xffff;
15702: xms_device->attributes = 0xc000;
1.1.1.29 root 15703: xms_device->strategy = XMS_SIZE - sizeof(dummy_device_routine);
15704: xms_device->interrupt = XMS_SIZE - sizeof(dummy_device_routine) + 6;
1.1.1.25 root 15705: memcpy(xms_device->dev_name, "EMMXXXX0", 8);
15706:
1.1.1.26 root 15707: mem[XMS_TOP + 0x12] = 0xcd; // int 68h (dummy)
15708: mem[XMS_TOP + 0x13] = 0x68;
15709: mem[XMS_TOP + 0x14] = 0xcf; // iret
1.1.1.19 root 15710: #ifdef SUPPORT_XMS
15711: if(support_xms) {
1.1.1.26 root 15712: mem[XMS_TOP + 0x15] = 0xcd; // int 69h (dummy)
15713: mem[XMS_TOP + 0x16] = 0x69;
15714: mem[XMS_TOP + 0x17] = 0xcb; // retf
1.1.1.19 root 15715: } else
15716: #endif
1.1.1.26 root 15717: mem[XMS_TOP + 0x15] = 0xcb; // retf
1.1.1.29 root 15718: memcpy(mem + XMS_TOP + XMS_SIZE - sizeof(dummy_device_routine), dummy_device_routine, sizeof(dummy_device_routine));
1.1.1.19 root 15719:
1.1.1.26 root 15720: // irq12 routine (mouse)
1.1.1.24 root 15721: mem[0xfffd0 + 0x00] = 0xcd; // int 6ah (dummy)
15722: mem[0xfffd0 + 0x01] = 0x6a;
15723: mem[0xfffd0 + 0x02] = 0x9a; // call far mouse
15724: mem[0xfffd0 + 0x03] = 0xff;
15725: mem[0xfffd0 + 0x04] = 0xff;
15726: mem[0xfffd0 + 0x05] = 0xff;
15727: mem[0xfffd0 + 0x06] = 0xff;
15728: mem[0xfffd0 + 0x07] = 0xcd; // int 6bh (dummy)
15729: mem[0xfffd0 + 0x08] = 0x6b;
15730: mem[0xfffd0 + 0x09] = 0xcf; // iret
15731:
1.1.1.27 root 15732: // case map routine
15733: mem[0xfffd0 + 0x0a] = 0xcd; // int 6ch (dummy)
15734: mem[0xfffd0 + 0x0b] = 0x6c;
15735: mem[0xfffd0 + 0x0c] = 0xcb; // retf
15736:
15737: // font read routine
15738: mem[0xfffd0 + 0x0d] = 0xcd; // int 6dh (dummy)
15739: mem[0xfffd0 + 0x0e] = 0x6d;
15740: mem[0xfffd0 + 0x0f] = 0xcb; // retf
1.1.1.19 root 15741:
1.1.1.32 root 15742: // error message read routine
15743: mem[0xfffd0 + 0x10] = 0xcd; // int 6eh (dummy)
15744: mem[0xfffd0 + 0x11] = 0x6e;
15745: mem[0xfffd0 + 0x12] = 0xcb; // retf
15746:
1.1.1.35 root 15747: // dummy loop to wait BIOS/DOS service is done
15748: mem[0xfffd0 + 0x13] = 0xe6; // out f7h, al
15749: mem[0xfffd0 + 0x14] = 0xf7;
15750: mem[0xfffd0 + 0x15] = 0x78; // js/jns -4
15751: mem[0xfffd0 + 0x16] = 0xfc;
15752: mem[0xfffd0 + 0x17] = 0xcb; // retf
15753:
1.1.1.26 root 15754: // irq0 routine (system time)
1.1.1.35 root 15755: mem[0xfffd0 + 0x18] = 0xcd; // int 1ch
15756: mem[0xfffd0 + 0x19] = 0x1c;
15757: mem[0xfffd0 + 0x1a] = 0xea; // jmp far (IRET_TOP >> 4):0008
15758: mem[0xfffd0 + 0x1b] = 0x08;
15759: mem[0xfffd0 + 0x1c] = 0x00;
15760: mem[0xfffd0 + 0x1d] = ((IRET_TOP >> 4) ) & 0xff;
15761: mem[0xfffd0 + 0x1e] = ((IRET_TOP >> 4) >> 8) & 0xff;
1.1.1.14 root 15762:
1.1.1.26 root 15763: // boot routine
1.1 root 15764: mem[0xffff0] = 0xf4; // halt
15765: mem[0xffff1] = 0xcd; // int 21h
15766: mem[0xffff2] = 0x21;
15767: mem[0xffff3] = 0xcb; // retf
15768:
1.1.1.24 root 15769: mem[0xffff5] = '0'; // rom date
15770: mem[0xffff6] = '2';
15771: mem[0xffff7] = '/';
15772: mem[0xffff8] = '2';
15773: mem[0xffff9] = '2';
15774: mem[0xffffa] = '/';
15775: mem[0xffffb] = '0';
15776: mem[0xffffc] = '6';
15777: mem[0xffffe] = 0xfc; // machine id
15778: mem[0xfffff] = 0x00;
15779:
1.1 root 15780: // param block
15781: // + 0: param block (22bytes)
15782: // +24: fcb1/2 (20bytes)
15783: // +44: command tail (128bytes)
15784: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
15785: param->env_seg = 0;
15786: param->cmd_line.w.l = 44;
15787: param->cmd_line.w.h = (WORK_TOP >> 4);
15788: param->fcb1.w.l = 24;
15789: param->fcb1.w.h = (WORK_TOP >> 4);
15790: param->fcb2.w.l = 24;
15791: param->fcb2.w.h = (WORK_TOP >> 4);
15792:
15793: memset(mem + WORK_TOP + 24, 0x20, 20);
15794:
15795: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
15796: if(argc > 1) {
15797: sprintf(cmd_line->cmd, " %s", argv[1]);
15798: for(int i = 2; i < argc; i++) {
15799: char tmp[128];
15800: sprintf(tmp, "%s %s", cmd_line->cmd, argv[i]);
15801: strcpy(cmd_line->cmd, tmp);
15802: }
15803: cmd_line->len = (UINT8)strlen(cmd_line->cmd);
15804: } else {
15805: cmd_line->len = 0;
15806: }
15807: cmd_line->cmd[cmd_line->len] = 0x0d;
15808:
15809: // system file table
1.1.1.21 root 15810: *(UINT32 *)(mem + SFT_TOP + 0) = 0xffffffff;
15811: *(UINT16 *)(mem + SFT_TOP + 4) = 20;
1.1 root 15812:
1.1.1.19 root 15813: // disk buffer header (from DOSBox)
15814: *(UINT16 *)(mem + DISK_BUF_TOP + 0) = 0xffff; // forward ptr
15815: *(UINT16 *)(mem + DISK_BUF_TOP + 2) = 0xffff; // backward ptr
15816: *(UINT8 *)(mem + DISK_BUF_TOP + 4) = 0xff; // not in use
15817: *(UINT8 *)(mem + DISK_BUF_TOP + 10) = 0x01; // number of FATs
15818: *(UINT32 *)(mem + DISK_BUF_TOP + 13) = 0xffffffff; // pointer to DPB
15819:
1.1 root 15820: // current directory structure
15821: msdos_cds_update(_getdrive() - 1);
15822:
15823: // fcb table
15824: *(UINT32 *)(mem + FCB_TABLE_TOP + 0) = 0xffffffff;
1.1.1.14 root 15825: *(UINT16 *)(mem + FCB_TABLE_TOP + 4) = 0;
1.1 root 15826:
1.1.1.41! root 15827: // drive parameter block
! 15828: for(int i = 0; i < 26; i++) {
! 15829: #if 0
! 15830: UINT16 seg, ofs;
! 15831: msdos_drive_param_block_update(i, &seg, &ofs, 1);
! 15832: #else
! 15833: dpb_t *dpb = (dpb_t *)(mem + DPB_TOP + sizeof(dpb_t) * i);
! 15834: dpb->drive_num = i;
! 15835: dpb->unit_num = i;
! 15836: dpb->next_dpb_ofs = (i == 25) ? 0xffff : sizeof(dpb_t) * (i + 1);
! 15837: dpb->next_dpb_seg = (i == 25) ? 0xffff : DPB_TOP >> 4;
! 15838: #endif
! 15839: }
! 15840:
1.1.1.17 root 15841: // nls stuff
15842: msdos_nls_tables_init();
1.1 root 15843:
15844: // execute command
1.1.1.28 root 15845: try {
15846: if(msdos_process_exec(argv[0], param, 0)) {
15847: fatalerror("'%s' not found\n", argv[0]);
15848: }
15849: } catch(...) {
15850: // we should not reach here :-(
15851: fatalerror("failed to start '%s' because of unexpected exeption\n", argv[0]);
1.1 root 15852: }
15853: retval = 0;
15854: return(0);
15855: }
15856:
15857: #define remove_std_file(path) { \
15858: int fd = _open(path, _O_RDONLY | _O_BINARY); \
15859: if(fd != -1) { \
15860: _lseek(fd, 0, SEEK_END); \
15861: int size = _tell(fd); \
15862: _close(fd); \
15863: if(size == 0) { \
15864: remove(path); \
15865: } \
15866: } \
15867: }
15868:
15869: void msdos_finish()
15870: {
15871: for(int i = 0; i < MAX_FILES; i++) {
15872: if(file_handler[i].valid) {
15873: _close(i);
15874: }
15875: }
1.1.1.21 root 15876: #ifdef MAP_AUX_DEVICE_TO_FILE
1.1 root 15877: remove_std_file("stdaux.txt");
1.1.1.21 root 15878: #endif
1.1.1.30 root 15879: #ifdef SUPPORT_XMS
15880: msdos_xms_finish();
15881: #endif
1.1 root 15882: msdos_dbcs_table_finish();
15883: }
15884:
15885: /* ----------------------------------------------------------------------------
15886: PC/AT hardware emulation
15887: ---------------------------------------------------------------------------- */
15888:
15889: void hardware_init()
15890: {
1.1.1.3 root 15891: CPU_INIT_CALL(CPU_MODEL);
1.1 root 15892: CPU_RESET_CALL(CPU_MODEL);
1.1.1.14 root 15893: m_IF = 1;
1.1.1.3 root 15894: #if defined(HAS_I386)
1.1 root 15895: cpu_type = (REG32(EDX) >> 8) & 0x0f;
15896: cpu_step = (REG32(EDX) >> 0) & 0x0f;
1.1.1.3 root 15897: #endif
15898: i386_set_a20_line(0);
1.1.1.14 root 15899:
1.1.1.19 root 15900: ems_init();
1.1.1.25 root 15901: dma_init();
1.1 root 15902: pic_init();
1.1.1.25 root 15903: pio_init();
1.1.1.8 root 15904: #ifdef PIT_ALWAYS_RUNNING
15905: pit_init();
15906: #else
1.1 root 15907: pit_active = 0;
15908: #endif
1.1.1.25 root 15909: sio_init();
1.1.1.8 root 15910: cmos_init();
15911: kbd_init();
1.1 root 15912: }
15913:
1.1.1.10 root 15914: void hardware_finish()
15915: {
15916: #if defined(HAS_I386)
15917: vtlb_free(m_vtlb);
15918: #endif
1.1.1.19 root 15919: ems_finish();
1.1.1.37 root 15920: pio_finish();
1.1.1.25 root 15921: sio_finish();
1.1.1.10 root 15922: }
15923:
1.1.1.28 root 15924: void hardware_release()
15925: {
15926: // release hardware resources when this program will be terminated abnormally
15927: #ifdef EXPORT_DEBUG_TO_FILE
1.1.1.33 root 15928: if(fp_debug_log != NULL) {
15929: fclose(fp_debug_log);
15930: fp_debug_log = NULL;
1.1.1.28 root 15931: }
15932: #endif
15933: #if defined(HAS_I386)
15934: vtlb_free(m_vtlb);
15935: #endif
15936: ems_release();
1.1.1.37 root 15937: pio_release();
1.1.1.28 root 15938: sio_release();
15939: }
15940:
1.1 root 15941: void hardware_run()
15942: {
1.1.1.22 root 15943: #ifdef EXPORT_DEBUG_TO_FILE
1.1.1.28 root 15944: // open debug log file after msdos_init() is done not to use the standard file handlers
1.1.1.33 root 15945: fp_debug_log = fopen("debug.log", "w");
1.1.1.22 root 15946: #endif
1.1.1.3 root 15947: while(!m_halted) {
15948: #if defined(HAS_I386)
1.1 root 15949: CPU_EXECUTE_CALL(i386);
1.1.1.14 root 15950: if(m_eip != m_prev_eip) {
1.1.1.35 root 15951: idle_ops++;
15952: }
1.1.1.14 root 15953: #else
1.1.1.35 root 15954: CPU_EXECUTE_CALL(CPU_MODEL);
1.1.1.14 root 15955: if(m_pc != m_prevpc) {
1.1.1.35 root 15956: idle_ops++;
1.1.1.14 root 15957: }
1.1.1.35 root 15958: #endif
15959: if(++update_ops == UPDATE_OPS) {
1.1 root 15960: hardware_update();
1.1.1.35 root 15961: update_ops = 0;
1.1 root 15962: }
15963: }
1.1.1.22 root 15964: #ifdef EXPORT_DEBUG_TO_FILE
1.1.1.33 root 15965: if(fp_debug_log != NULL) {
15966: fclose(fp_debug_log);
15967: fp_debug_log = NULL;
1.1.1.28 root 15968: }
1.1.1.22 root 15969: #endif
1.1 root 15970: }
15971:
15972: void hardware_update()
15973: {
1.1.1.8 root 15974: static UINT32 prev_time = 0;
15975: UINT32 cur_time = timeGetTime();
15976:
15977: if(prev_time != cur_time) {
15978: // update pit and raise irq0
15979: #ifndef PIT_ALWAYS_RUNNING
15980: if(pit_active)
15981: #endif
15982: {
15983: if(pit_run(0, cur_time)) {
15984: pic_req(0, 0, 1);
15985: }
15986: pit_run(1, cur_time);
15987: pit_run(2, cur_time);
15988: }
1.1.1.24 root 15989:
1.1.1.25 root 15990: // update sio and raise irq4/3
1.1.1.29 root 15991: for(int c = 0; c < 4; c++) {
1.1.1.25 root 15992: sio_update(c);
15993: }
15994:
1.1.1.24 root 15995: // update keyboard and mouse
1.1.1.14 root 15996: static UINT32 prev_tick = 0;
15997: UINT32 cur_tick = cur_time / 32;
1.1.1.25 root 15998:
1.1.1.14 root 15999: if(prev_tick != cur_tick) {
16000: // update keyboard flags
16001: UINT8 state;
1.1.1.24 root 16002: state = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
16003: state |= (GetAsyncKeyState(VK_CAPITAL ) & 0x0001) ? 0x40 : 0;
16004: state |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x0001) ? 0x20 : 0;
16005: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
16006: state |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
16007: state |= (GetAsyncKeyState(VK_CONTROL ) & 0x8000) ? 0x04 : 0;
16008: state |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
16009: state |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
1.1.1.14 root 16010: mem[0x417] = state;
16011: state = (GetAsyncKeyState(VK_INSERT ) & 0x8000) ? 0x80 : 0;
16012: state |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
16013: state |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
16014: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
1.1.1.24 root 16015: // state |= (GetAsyncKeyState(VK_PAUSE ) & 0x0001) ? 0x08 : 0;
16016: // state |= (GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x04 : 0;
1.1.1.14 root 16017: state |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
16018: state |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
16019: mem[0x418] = state;
16020:
1.1.1.24 root 16021: // update console input if needed
1.1.1.34 root 16022: if(!key_changed || mouse.hidden == 0) {
1.1.1.24 root 16023: update_console_input();
16024: }
16025:
16026: // raise irq1 if key is pressed/released
16027: if(key_changed) {
1.1.1.8 root 16028: pic_req(0, 1, 1);
1.1.1.24 root 16029: key_changed = false;
16030: }
16031:
16032: // raise irq12 if mouse status is changed
16033: if(mouse.status & mouse.call_mask) {
1.1.1.34 root 16034: // if(mouse.hidden == 0) {
1.1.1.24 root 16035: pic_req(1, 4, 1);
16036: mouse.status_irq = mouse.status & mouse.call_mask;
1.1.1.34 root 16037: // }
1.1.1.24 root 16038: mouse.status &= ~mouse.call_mask;
1.1.1.8 root 16039: }
1.1.1.24 root 16040:
1.1.1.14 root 16041: prev_tick = cur_tick;
1.1.1.8 root 16042: }
1.1.1.24 root 16043:
1.1.1.19 root 16044: // update daily timer counter
16045: pcbios_update_daily_timer_counter(cur_time);
1.1.1.25 root 16046:
1.1.1.8 root 16047: prev_time = cur_time;
1.1 root 16048: }
16049: }
16050:
1.1.1.19 root 16051: // ems
16052:
16053: void ems_init()
16054: {
16055: memset(ems_handles, 0, sizeof(ems_handles));
16056: memset(ems_pages, 0, sizeof(ems_pages));
16057: free_ems_pages = MAX_EMS_PAGES;
16058: }
16059:
16060: void ems_finish()
16061: {
1.1.1.28 root 16062: ems_release();
16063: }
16064:
16065: void ems_release()
16066: {
1.1.1.31 root 16067: for(int i = 1; i <= MAX_EMS_HANDLES; i++) {
1.1.1.28 root 16068: if(ems_handles[i].buffer != NULL) {
1.1.1.19 root 16069: free(ems_handles[i].buffer);
16070: ems_handles[i].buffer = NULL;
16071: }
16072: }
16073: }
16074:
16075: void ems_allocate_pages(int handle, int pages)
16076: {
16077: if(pages > 0) {
16078: ems_handles[handle].buffer = (UINT8 *)calloc(1, 0x4000 * pages);
16079: } else {
16080: ems_handles[handle].buffer = NULL;
16081: }
16082: ems_handles[handle].pages = pages;
16083: ems_handles[handle].allocated = true;
16084: free_ems_pages -= pages;
16085: }
16086:
16087: void ems_reallocate_pages(int handle, int pages)
16088: {
16089: if(ems_handles[handle].allocated) {
16090: if(ems_handles[handle].pages != pages) {
16091: UINT8 *new_buffer = NULL;
16092:
16093: if(pages > 0) {
16094: new_buffer = (UINT8 *)calloc(1, 0x4000 * pages);
16095: }
1.1.1.32 root 16096: if(ems_handles[handle].buffer != NULL) {
16097: if(new_buffer != NULL) {
1.1.1.19 root 16098: if(pages > ems_handles[handle].pages) {
16099: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * ems_handles[handle].pages);
16100: } else {
16101: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * pages);
16102: }
16103: }
16104: free(ems_handles[handle].buffer);
16105: ems_handles[handle].buffer = NULL;
16106: }
16107: free_ems_pages += ems_handles[handle].pages;
16108:
16109: ems_handles[handle].buffer = new_buffer;
16110: ems_handles[handle].pages = pages;
16111: free_ems_pages -= pages;
16112: }
16113: } else {
16114: ems_allocate_pages(handle, pages);
16115: }
16116: }
16117:
16118: void ems_release_pages(int handle)
16119: {
16120: if(ems_handles[handle].allocated) {
1.1.1.32 root 16121: if(ems_handles[handle].buffer != NULL) {
1.1.1.19 root 16122: free(ems_handles[handle].buffer);
16123: ems_handles[handle].buffer = NULL;
16124: }
16125: free_ems_pages += ems_handles[handle].pages;
16126: ems_handles[handle].allocated = false;
16127: }
16128: }
16129:
16130: void ems_map_page(int physical, int handle, int logical)
16131: {
16132: if(ems_pages[physical].mapped) {
16133: if(ems_pages[physical].handle == handle && ems_pages[physical].page == logical) {
16134: return;
16135: }
16136: ems_unmap_page(physical);
16137: }
1.1.1.32 root 16138: if(ems_handles[handle].allocated && ems_handles[handle].buffer != NULL && logical < ems_handles[handle].pages) {
1.1.1.19 root 16139: memcpy(mem + EMS_TOP + 0x4000 * physical, ems_handles[handle].buffer + 0x4000 * logical, 0x4000);
16140: }
16141: ems_pages[physical].handle = handle;
16142: ems_pages[physical].page = logical;
16143: ems_pages[physical].mapped = true;
16144: }
16145:
16146: void ems_unmap_page(int physical)
16147: {
16148: if(ems_pages[physical].mapped) {
16149: int handle = ems_pages[physical].handle;
16150: int logical = ems_pages[physical].page;
16151:
1.1.1.32 root 16152: if(ems_handles[handle].allocated && ems_handles[handle].buffer != NULL && logical < ems_handles[handle].pages) {
1.1.1.19 root 16153: memcpy(ems_handles[handle].buffer + 0x4000 * logical, mem + EMS_TOP + 0x4000 * physical, 0x4000);
16154: }
16155: ems_pages[physical].mapped = false;
16156: }
16157: }
16158:
1.1.1.25 root 16159: // dma
1.1 root 16160:
1.1.1.25 root 16161: void dma_init()
1.1 root 16162: {
1.1.1.26 root 16163: memset(dma, 0, sizeof(dma));
1.1.1.25 root 16164: for(int c = 0; c < 2; c++) {
1.1.1.26 root 16165: // for(int ch = 0; ch < 4; ch++) {
16166: // dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w = 0xffff;
16167: // }
1.1.1.25 root 16168: dma_reset(c);
16169: }
1.1 root 16170: }
16171:
1.1.1.25 root 16172: void dma_reset(int c)
1.1 root 16173: {
1.1.1.25 root 16174: dma[c].low_high = false;
16175: dma[c].cmd = dma[c].req = dma[c].tc = 0;
16176: dma[c].mask = 0xff;
16177: }
16178:
16179: void dma_write(int c, UINT32 addr, UINT8 data)
16180: {
16181: int ch = (addr >> 1) & 3;
16182: UINT8 bit = 1 << (data & 3);
16183:
16184: switch(addr & 0x0f) {
16185: case 0x00: case 0x02: case 0x04: case 0x06:
16186: if(dma[c].low_high) {
16187: dma[c].ch[ch].bareg.b.h = data;
1.1 root 16188: } else {
1.1.1.25 root 16189: dma[c].ch[ch].bareg.b.l = data;
16190: }
16191: dma[c].ch[ch].areg.w = dma[c].ch[ch].bareg.w;
16192: dma[c].low_high = !dma[c].low_high;
16193: break;
16194: case 0x01: case 0x03: case 0x05: case 0x07:
16195: if(dma[c].low_high) {
16196: dma[c].ch[ch].bcreg.b.h = data;
16197: } else {
16198: dma[c].ch[ch].bcreg.b.l = data;
16199: }
16200: dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w;
16201: dma[c].low_high = !dma[c].low_high;
16202: break;
16203: case 0x08:
16204: // command register
16205: dma[c].cmd = data;
16206: break;
16207: case 0x09:
16208: // dma[c].request register
16209: if(data & 4) {
16210: if(!(dma[c].req & bit)) {
16211: dma[c].req |= bit;
16212: // dma_run(c, ch);
16213: }
16214: } else {
16215: dma[c].req &= ~bit;
16216: }
16217: break;
16218: case 0x0a:
16219: // single mask register
16220: if(data & 4) {
16221: dma[c].mask |= bit;
16222: } else {
16223: dma[c].mask &= ~bit;
16224: }
16225: break;
16226: case 0x0b:
16227: // mode register
16228: dma[c].ch[data & 3].mode = data;
16229: break;
16230: case 0x0c:
16231: dma[c].low_high = false;
16232: break;
16233: case 0x0d:
16234: // clear master
16235: dma_reset(c);
16236: break;
16237: case 0x0e:
16238: // clear mask register
16239: dma[c].mask = 0;
16240: break;
16241: case 0x0f:
16242: // all mask register
16243: dma[c].mask = data & 0x0f;
16244: break;
16245: }
16246: }
16247:
16248: UINT8 dma_read(int c, UINT32 addr)
16249: {
16250: int ch = (addr >> 1) & 3;
16251: UINT8 val = 0xff;
16252:
16253: switch(addr & 0x0f) {
16254: case 0x00: case 0x02: case 0x04: case 0x06:
16255: if(dma[c].low_high) {
16256: val = dma[c].ch[ch].areg.b.h;
16257: } else {
16258: val = dma[c].ch[ch].areg.b.l;
16259: }
16260: dma[c].low_high = !dma[c].low_high;
16261: return(val);
16262: case 0x01: case 0x03: case 0x05: case 0x07:
16263: if(dma[c].low_high) {
16264: val = dma[c].ch[ch].creg.b.h;
16265: } else {
16266: val = dma[c].ch[ch].creg.b.l;
16267: }
16268: dma[c].low_high = !dma[c].low_high;
16269: return(val);
16270: case 0x08:
16271: // status register
16272: val = (dma[c].req << 4) | dma[c].tc;
16273: dma[c].tc = 0;
16274: return(val);
16275: case 0x0d:
1.1.1.26 root 16276: // temporary register (intel 82374 does not support)
1.1.1.25 root 16277: return(dma[c].tmp & 0xff);
1.1.1.26 root 16278: case 0x0f:
16279: // mask register (intel 82374 does support)
16280: return(dma[c].mask);
1.1.1.25 root 16281: }
16282: return(0xff);
16283: }
16284:
16285: void dma_page_write(int c, int ch, UINT8 data)
16286: {
16287: dma[c].ch[ch].pagereg = data;
16288: }
16289:
16290: UINT8 dma_page_read(int c, int ch)
16291: {
16292: return(dma[c].ch[ch].pagereg);
16293: }
16294:
16295: void dma_run(int c, int ch)
16296: {
16297: UINT8 bit = 1 << ch;
16298:
16299: if((dma[c].req & bit) && !(dma[c].mask & bit)) {
16300: // execute dma
16301: while(dma[c].req & bit) {
16302: if(ch == 0 && (dma[c].cmd & 0x01)) {
16303: // memory -> memory
16304: UINT32 saddr = dma[c].ch[0].areg.w | (dma[c].ch[0].pagereg << 16);
16305: UINT32 daddr = dma[c].ch[1].areg.w | (dma[c].ch[1].pagereg << 16);
16306:
16307: if(c == 0) {
16308: dma[c].tmp = read_byte(saddr);
16309: write_byte(daddr, dma[c].tmp);
16310: } else {
16311: dma[c].tmp = read_word(saddr << 1);
16312: write_word(daddr << 1, dma[c].tmp);
16313: }
16314: if(!(dma[c].cmd & 0x02)) {
16315: if(dma[c].ch[0].mode & 0x20) {
16316: dma[c].ch[0].areg.w--;
16317: if(dma[c].ch[0].areg.w == 0xffff) {
16318: dma[c].ch[0].pagereg--;
16319: }
16320: } else {
16321: dma[c].ch[0].areg.w++;
16322: if(dma[c].ch[0].areg.w == 0) {
16323: dma[c].ch[0].pagereg++;
16324: }
16325: }
16326: }
16327: if(dma[c].ch[1].mode & 0x20) {
16328: dma[c].ch[1].areg.w--;
16329: if(dma[c].ch[1].areg.w == 0xffff) {
16330: dma[c].ch[1].pagereg--;
16331: }
16332: } else {
16333: dma[c].ch[1].areg.w++;
16334: if(dma[c].ch[1].areg.w == 0) {
16335: dma[c].ch[1].pagereg++;
16336: }
16337: }
16338:
16339: // check dma condition
16340: if(dma[c].ch[0].creg.w-- == 0) {
16341: if(dma[c].ch[0].mode & 0x10) {
16342: // self initialize
16343: dma[c].ch[0].areg.w = dma[c].ch[0].bareg.w;
16344: dma[c].ch[0].creg.w = dma[c].ch[0].bcreg.w;
16345: } else {
16346: // dma[c].mask |= bit;
16347: }
16348: }
16349: if(dma[c].ch[1].creg.w-- == 0) {
16350: // terminal count
16351: if(dma[c].ch[1].mode & 0x10) {
16352: // self initialize
16353: dma[c].ch[1].areg.w = dma[c].ch[1].bareg.w;
16354: dma[c].ch[1].creg.w = dma[c].ch[1].bcreg.w;
16355: } else {
16356: dma[c].mask |= bit;
16357: }
16358: dma[c].req &= ~bit;
16359: dma[c].tc |= bit;
16360: }
16361: } else {
16362: UINT32 addr = dma[c].ch[ch].areg.w | (dma[c].ch[ch].pagereg << 16);
16363:
16364: if((dma[c].ch[ch].mode & 0x0c) == 0x00) {
16365: // verify
16366: } else if((dma[c].ch[ch].mode & 0x0c) == 0x04) {
16367: // io -> memory
16368: if(c == 0) {
16369: dma[c].tmp = read_io_byte(dma[c].ch[ch].port);
16370: write_byte(addr, dma[c].tmp);
16371: } else {
16372: dma[c].tmp = read_io_word(dma[c].ch[ch].port);
16373: write_word(addr << 1, dma[c].tmp);
16374: }
16375: } else if((dma[c].ch[ch].mode & 0x0c) == 0x08) {
16376: // memory -> io
16377: if(c == 0) {
16378: dma[c].tmp = read_byte(addr);
16379: write_io_byte(dma[c].ch[ch].port, dma[c].tmp);
16380: } else {
16381: dma[c].tmp = read_word(addr << 1);
16382: write_io_word(dma[c].ch[ch].port, dma[c].tmp);
16383: }
16384: }
16385: if(dma[c].ch[ch].mode & 0x20) {
16386: dma[c].ch[ch].areg.w--;
16387: if(dma[c].ch[ch].areg.w == 0xffff) {
16388: dma[c].ch[ch].pagereg--;
16389: }
16390: } else {
16391: dma[c].ch[ch].areg.w++;
16392: if(dma[c].ch[ch].areg.w == 0) {
16393: dma[c].ch[ch].pagereg++;
16394: }
16395: }
16396:
16397: // check dma condition
16398: if(dma[c].ch[ch].creg.w-- == 0) {
16399: // terminal count
16400: if(dma[c].ch[ch].mode & 0x10) {
16401: // self initialize
16402: dma[c].ch[ch].areg.w = dma[c].ch[ch].bareg.w;
16403: dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w;
16404: } else {
16405: dma[c].mask |= bit;
16406: }
16407: dma[c].req &= ~bit;
16408: dma[c].tc |= bit;
16409: } else if((dma[c].ch[ch].mode & 0xc0) == 0x40) {
16410: // single mode
16411: break;
16412: }
16413: }
16414: }
16415: }
16416: }
16417:
16418: // pic
16419:
16420: void pic_init()
16421: {
16422: memset(pic, 0, sizeof(pic));
16423: pic[0].imr = pic[1].imr = 0xff;
16424:
16425: // from bochs bios
16426: pic_write(0, 0, 0x11); // icw1 = 11h
16427: pic_write(0, 1, 0x08); // icw2 = 08h
16428: pic_write(0, 1, 0x04); // icw3 = 04h
16429: pic_write(0, 1, 0x01); // icw4 = 01h
16430: pic_write(0, 1, 0xb8); // ocw1 = b8h
16431: pic_write(1, 0, 0x11); // icw1 = 11h
16432: pic_write(1, 1, 0x70); // icw2 = 70h
16433: pic_write(1, 1, 0x02); // icw3 = 02h
16434: pic_write(1, 1, 0x01); // icw4 = 01h
16435: }
16436:
16437: void pic_write(int c, UINT32 addr, UINT8 data)
16438: {
16439: if(addr & 1) {
16440: if(pic[c].icw2_r) {
16441: // icw2
16442: pic[c].icw2 = data;
16443: pic[c].icw2_r = 0;
16444: } else if(pic[c].icw3_r) {
16445: // icw3
16446: pic[c].icw3 = data;
16447: pic[c].icw3_r = 0;
16448: } else if(pic[c].icw4_r) {
16449: // icw4
16450: pic[c].icw4 = data;
16451: pic[c].icw4_r = 0;
16452: } else {
16453: // ocw1
1.1 root 16454: pic[c].imr = data;
16455: }
16456: } else {
16457: if(data & 0x10) {
16458: // icw1
16459: pic[c].icw1 = data;
16460: pic[c].icw2_r = 1;
16461: pic[c].icw3_r = (data & 2) ? 0 : 1;
16462: pic[c].icw4_r = data & 1;
16463: pic[c].irr = 0;
16464: pic[c].isr = 0;
16465: pic[c].imr = 0;
16466: pic[c].prio = 0;
16467: if(!(pic[c].icw1 & 1)) {
16468: pic[c].icw4 = 0;
16469: }
16470: pic[c].ocw3 = 0;
16471: } else if(data & 8) {
16472: // ocw3
16473: if(!(data & 2)) {
16474: data = (data & ~1) | (pic[c].ocw3 & 1);
16475: }
16476: if(!(data & 0x40)) {
16477: data = (data & ~0x20) | (pic[c].ocw3 & 0x20);
16478: }
16479: pic[c].ocw3 = data;
16480: } else {
16481: // ocw2
16482: int level = 0;
16483: if(data & 0x40) {
16484: level = data & 7;
16485: } else {
16486: if(!pic[c].isr) {
16487: return;
16488: }
16489: level = pic[c].prio;
16490: while(!(pic[c].isr & (1 << level))) {
16491: level = (level + 1) & 7;
16492: }
16493: }
16494: if(data & 0x80) {
16495: pic[c].prio = (level + 1) & 7;
16496: }
16497: if(data & 0x20) {
16498: pic[c].isr &= ~(1 << level);
16499: }
16500: }
16501: }
16502: pic_update();
16503: }
16504:
16505: UINT8 pic_read(int c, UINT32 addr)
16506: {
16507: if(addr & 1) {
16508: return(pic[c].imr);
16509: } else {
16510: // polling mode is not supported...
16511: //if(pic[c].ocw3 & 4) {
16512: // return ???;
16513: //}
16514: if(pic[c].ocw3 & 1) {
16515: return(pic[c].isr);
16516: } else {
16517: return(pic[c].irr);
16518: }
16519: }
16520: }
16521:
16522: void pic_req(int c, int level, int signal)
16523: {
16524: if(signal) {
16525: pic[c].irr |= (1 << level);
16526: } else {
16527: pic[c].irr &= ~(1 << level);
16528: }
16529: pic_update();
16530: }
16531:
16532: int pic_ack()
16533: {
16534: // ack (INTA=L)
16535: pic[pic_req_chip].isr |= pic_req_bit;
16536: pic[pic_req_chip].irr &= ~pic_req_bit;
16537: if(pic_req_chip > 0) {
16538: // update isr and irr of master
16539: UINT8 slave = 1 << (pic[pic_req_chip].icw3 & 7);
16540: pic[pic_req_chip - 1].isr |= slave;
16541: pic[pic_req_chip - 1].irr &= ~slave;
16542: }
16543: //if(pic[pic_req_chip].icw4 & 1) {
16544: // 8086 mode
16545: int vector = (pic[pic_req_chip].icw2 & 0xf8) | pic_req_level;
16546: //} else {
16547: // // 8080 mode
16548: // UINT16 addr = (UINT16)pic[pic_req_chip].icw2 << 8;
16549: // if(pic[pic_req_chip].icw1 & 4) {
16550: // addr |= (pic[pic_req_chip].icw1 & 0xe0) | (pic_req_level << 2);
16551: // } else {
16552: // addr |= (pic[pic_req_chip].icw1 & 0xc0) | (pic_req_level << 3);
16553: // }
16554: // vector = 0xcd | (addr << 8);
16555: //}
16556: if(pic[pic_req_chip].icw4 & 2) {
16557: // auto eoi
16558: pic[pic_req_chip].isr &= ~pic_req_bit;
16559: }
16560: return(vector);
16561: }
16562:
16563: void pic_update()
16564: {
16565: for(int c = 0; c < 2; c++) {
16566: UINT8 irr = pic[c].irr;
16567: if(c + 1 < 2) {
16568: // this is master
16569: if(pic[c + 1].irr & (~pic[c + 1].imr)) {
16570: // request from slave
16571: irr |= 1 << (pic[c + 1].icw3 & 7);
16572: }
16573: }
16574: irr &= (~pic[c].imr);
16575: if(!irr) {
16576: break;
16577: }
16578: if(!(pic[c].ocw3 & 0x20)) {
16579: irr |= pic[c].isr;
16580: }
16581: int level = pic[c].prio;
16582: UINT8 bit = 1 << level;
16583: while(!(irr & bit)) {
16584: level = (level + 1) & 7;
16585: bit = 1 << level;
16586: }
16587: if((c + 1 < 2) && (pic[c].icw3 & bit)) {
16588: // check slave
16589: continue;
16590: }
16591: if(pic[c].isr & bit) {
16592: break;
16593: }
16594: // interrupt request
16595: pic_req_chip = c;
16596: pic_req_level = level;
16597: pic_req_bit = bit;
1.1.1.3 root 16598: i386_set_irq_line(INPUT_LINE_IRQ, HOLD_LINE);
1.1 root 16599: return;
16600: }
1.1.1.3 root 16601: i386_set_irq_line(INPUT_LINE_IRQ, CLEAR_LINE);
1.1.1.2 root 16602: }
1.1 root 16603:
1.1.1.25 root 16604: // pio
16605:
16606: void pio_init()
16607: {
1.1.1.38 root 16608: // bool conv_mode = (GetConsoleCP() == 932);
16609:
1.1.1.26 root 16610: memset(pio, 0, sizeof(pio));
1.1.1.37 root 16611:
1.1.1.25 root 16612: for(int c = 0; c < 2; c++) {
1.1.1.37 root 16613: pio[c].stat = 0xdf;
1.1.1.25 root 16614: pio[c].ctrl = 0x0c;
1.1.1.38 root 16615: // pio[c].conv_mode = conv_mode;
1.1.1.25 root 16616: }
16617: }
16618:
1.1.1.37 root 16619: void pio_finish()
16620: {
16621: pio_release();
16622: }
16623:
16624: void pio_release()
16625: {
16626: for(int c = 0; c < 2; c++) {
16627: if(pio[c].fp != NULL) {
1.1.1.38 root 16628: if(pio[c].jis_mode) {
16629: fputc(0x1c, pio[c].fp);
16630: fputc(0x2e, pio[c].fp);
16631: }
1.1.1.37 root 16632: fclose(pio[c].fp);
16633: pio[c].fp = NULL;
16634: }
16635: }
16636: }
16637:
1.1.1.25 root 16638: void pio_write(int c, UINT32 addr, UINT8 data)
16639: {
16640: switch(addr & 3) {
16641: case 0:
16642: pio[c].data = data;
16643: break;
16644: case 2:
1.1.1.37 root 16645: if((pio[c].ctrl & 0x01) && !(data & 0x01)) {
16646: // strobe H -> L
16647: if(pio[c].data == 0x0d && (data & 0x02)) {
16648: // auto feed
16649: printer_out(c, 0x0d);
16650: printer_out(c, 0x0a);
16651: } else {
16652: printer_out(c, pio[c].data);
16653: }
16654: pio[c].stat &= ~0x40; // set ack
16655: }
1.1.1.25 root 16656: pio[c].ctrl = data;
16657: break;
16658: }
16659: }
16660:
16661: UINT8 pio_read(int c, UINT32 addr)
16662: {
16663: switch(addr & 3) {
16664: case 0:
1.1.1.37 root 16665: if(pio[c].ctrl & 0x20) {
16666: // input mode
16667: return(0xff);
16668: }
1.1.1.25 root 16669: return(pio[c].data);
16670: case 1:
1.1.1.37 root 16671: {
16672: UINT8 stat = pio[c].stat;
16673: pio[c].stat |= 0x40; // clear ack
16674: return(stat);
16675: }
1.1.1.25 root 16676: case 2:
16677: return(pio[c].ctrl);
16678: }
16679: return(0xff);
16680: }
16681:
1.1.1.37 root 16682: void printer_out(int c, UINT8 data)
16683: {
16684: SYSTEMTIME time;
1.1.1.38 root 16685: bool jis_mode = false;
1.1.1.37 root 16686:
16687: GetLocalTime(&time);
16688:
16689: if(pio[c].fp != NULL) {
16690: // if at least 1000ms passed from last written, close the current file
16691: FILETIME ftime1;
16692: FILETIME ftime2;
16693: SystemTimeToFileTime(&pio[c].time, &ftime1);
16694: SystemTimeToFileTime(&time, &ftime2);
16695: INT64 *time1 = (INT64 *)&ftime1;
16696: INT64 *time2 = (INT64 *)&ftime2;
16697: INT64 msec = (*time2 - *time1) / 10000;
16698:
16699: if(msec >= 1000) {
1.1.1.38 root 16700: if(pio[c].jis_mode) {
16701: fputc(0x1c, pio[c].fp);
16702: fputc(0x2e, pio[c].fp);
16703: jis_mode = true;
16704: }
1.1.1.37 root 16705: fclose(pio[c].fp);
16706: pio[c].fp = NULL;
16707: }
16708: }
16709: if(pio[c].fp == NULL) {
16710: // create a new file in the temp folder
16711: char file_name[MAX_PATH];
16712:
16713: 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);
16714: if(GetTempPath(MAX_PATH, pio[c].path)) {
16715: strcat(pio[c].path, file_name);
16716: } else {
16717: strcpy(pio[c].path, file_name);
16718: }
1.1.1.38 root 16719: pio[c].fp = fopen(pio[c].path, "w+b");
1.1.1.37 root 16720: }
16721: if(pio[c].fp != NULL) {
1.1.1.38 root 16722: if(jis_mode) {
16723: fputc(0x1c, pio[c].fp);
16724: fputc(0x26, pio[c].fp);
16725: }
1.1.1.37 root 16726: fputc(data, pio[c].fp);
1.1.1.38 root 16727:
16728: // reopen file if 1ch 26h 1ch 2eh (kanji-on kanji-off) are written at the top
16729: if(data == 0x2e && ftell(pio[c].fp) == 4) {
16730: UINT8 buffer[4];
16731: fseek(pio[c].fp, 0, SEEK_SET);
16732: fread(buffer, 4, 1, pio[c].fp);
16733: if(buffer[0] == 0x1c && buffer[1] == 0x26 && buffer[2] == 0x1c/* && buffer[3] == 0x2e*/) {
16734: fclose(pio[c].fp);
16735: pio[c].fp = fopen(pio[c].path, "w+b");
16736: }
16737: }
1.1.1.37 root 16738: pio[c].time = time;
16739: }
16740: }
16741:
1.1 root 16742: // pit
16743:
1.1.1.22 root 16744: #define PIT_FREQ 1193182ULL
1.1 root 16745: #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)
16746:
16747: void pit_init()
16748: {
1.1.1.8 root 16749: memset(pit, 0, sizeof(pit));
1.1 root 16750: for(int ch = 0; ch < 3; ch++) {
16751: pit[ch].count = 0x10000;
16752: pit[ch].ctrl_reg = 0x34;
16753: pit[ch].mode = 3;
16754: }
16755:
16756: // from bochs bios
16757: pit_write(3, 0x34);
16758: pit_write(0, 0x00);
16759: pit_write(0, 0x00);
16760: }
16761:
16762: void pit_write(int ch, UINT8 val)
16763: {
1.1.1.8 root 16764: #ifndef PIT_ALWAYS_RUNNING
1.1 root 16765: if(!pit_active) {
16766: pit_active = 1;
16767: pit_init();
16768: }
1.1.1.8 root 16769: #endif
1.1 root 16770: switch(ch) {
16771: case 0:
16772: case 1:
16773: case 2:
16774: // write count register
16775: if(!pit[ch].low_write && !pit[ch].high_write) {
16776: if(pit[ch].ctrl_reg & 0x10) {
16777: pit[ch].low_write = 1;
16778: }
16779: if(pit[ch].ctrl_reg & 0x20) {
16780: pit[ch].high_write = 1;
16781: }
16782: }
16783: if(pit[ch].low_write) {
16784: pit[ch].count_reg = val;
16785: pit[ch].low_write = 0;
16786: } else if(pit[ch].high_write) {
16787: if((pit[ch].ctrl_reg & 0x30) == 0x20) {
16788: pit[ch].count_reg = val << 8;
16789: } else {
16790: pit[ch].count_reg |= val << 8;
16791: }
16792: pit[ch].high_write = 0;
16793: }
16794: // start count
1.1.1.8 root 16795: if(!pit[ch].low_write && !pit[ch].high_write) {
16796: if(pit[ch].mode == 0 || pit[ch].mode == 4 || pit[ch].prev_time == 0) {
16797: pit[ch].count = PIT_COUNT_VALUE(ch);
16798: pit[ch].prev_time = timeGetTime();
16799: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 16800: }
16801: }
16802: break;
16803: case 3: // ctrl reg
16804: if((val & 0xc0) == 0xc0) {
16805: // i8254 read-back command
16806: for(ch = 0; ch < 3; ch++) {
16807: if(!(val & 0x10) && !pit[ch].status_latched) {
16808: pit[ch].status = pit[ch].ctrl_reg & 0x3f;
16809: pit[ch].status_latched = 1;
16810: }
16811: if(!(val & 0x20) && !pit[ch].count_latched) {
16812: pit_latch_count(ch);
16813: }
16814: }
16815: break;
16816: }
16817: ch = (val >> 6) & 3;
16818: if(val & 0x30) {
1.1.1.35 root 16819: static const int modes[8] = {0, 1, 2, 3, 4, 5, 2, 3};
1.1 root 16820: pit[ch].mode = modes[(val >> 1) & 7];
16821: pit[ch].count_latched = 0;
16822: pit[ch].low_read = pit[ch].high_read = 0;
16823: pit[ch].low_write = pit[ch].high_write = 0;
16824: pit[ch].ctrl_reg = val;
16825: // stop count
1.1.1.8 root 16826: pit[ch].prev_time = pit[ch].expired_time = 0;
1.1 root 16827: pit[ch].count_reg = 0;
16828: } else if(!pit[ch].count_latched) {
16829: pit_latch_count(ch);
16830: }
16831: break;
16832: }
16833: }
16834:
16835: UINT8 pit_read(int ch)
16836: {
1.1.1.8 root 16837: #ifndef PIT_ALWAYS_RUNNING
1.1 root 16838: if(!pit_active) {
16839: pit_active = 1;
16840: pit_init();
16841: }
1.1.1.8 root 16842: #endif
1.1 root 16843: switch(ch) {
16844: case 0:
16845: case 1:
16846: case 2:
16847: if(pit[ch].status_latched) {
16848: pit[ch].status_latched = 0;
16849: return(pit[ch].status);
16850: }
16851: // if not latched, through current count
16852: if(!pit[ch].count_latched) {
16853: if(!pit[ch].low_read && !pit[ch].high_read) {
16854: pit_latch_count(ch);
16855: }
16856: }
16857: // return latched count
16858: if(pit[ch].low_read) {
16859: pit[ch].low_read = 0;
16860: if(!pit[ch].high_read) {
16861: pit[ch].count_latched = 0;
16862: }
16863: return(pit[ch].latch & 0xff);
16864: } else if(pit[ch].high_read) {
16865: pit[ch].high_read = 0;
16866: pit[ch].count_latched = 0;
16867: return((pit[ch].latch >> 8) & 0xff);
16868: }
16869: }
16870: return(0xff);
16871: }
16872:
1.1.1.8 root 16873: int pit_run(int ch, UINT32 cur_time)
1.1 root 16874: {
1.1.1.8 root 16875: if(pit[ch].expired_time != 0 && cur_time >= pit[ch].expired_time) {
1.1 root 16876: pit[ch].count = PIT_COUNT_VALUE(ch);
1.1.1.8 root 16877: pit[ch].prev_time = pit[ch].expired_time;
16878: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
16879: if(cur_time >= pit[ch].expired_time) {
16880: pit[ch].prev_time = cur_time;
16881: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 16882: }
1.1.1.8 root 16883: return(1);
1.1 root 16884: }
1.1.1.8 root 16885: return(0);
1.1 root 16886: }
16887:
16888: void pit_latch_count(int ch)
16889: {
1.1.1.8 root 16890: if(pit[ch].expired_time != 0) {
1.1.1.26 root 16891: UINT32 cur_time = timeGetTime();
1.1.1.8 root 16892: pit_run(ch, cur_time);
16893: UINT32 tmp = (pit[ch].count * (pit[ch].expired_time - cur_time)) / (pit[ch].expired_time - pit[ch].prev_time);
1.1.1.26 root 16894: UINT16 latch = (tmp != 0) ? (UINT16)tmp : 1;
16895:
16896: if(pit[ch].prev_latch == latch && pit[ch].expired_time > cur_time) {
16897: // decrement counter in 1msec period
16898: if(pit[ch].next_latch == 0) {
16899: tmp = (pit[ch].count * (pit[ch].expired_time - cur_time - 1)) / (pit[ch].expired_time - pit[ch].prev_time);
16900: pit[ch].next_latch = (tmp != 0) ? (UINT16)tmp : 1;
16901: }
16902: if(pit[ch].latch > pit[ch].next_latch) {
16903: pit[ch].latch--;
16904: }
16905: } else {
16906: pit[ch].prev_latch = pit[ch].latch = latch;
16907: pit[ch].next_latch = 0;
16908: }
1.1.1.8 root 16909: } else {
16910: pit[ch].latch = (UINT16)pit[ch].count;
1.1.1.26 root 16911: pit[ch].prev_latch = pit[ch].next_latch = 0;
1.1 root 16912: }
16913: pit[ch].count_latched = 1;
16914: if((pit[ch].ctrl_reg & 0x30) == 0x10) {
16915: // lower byte
16916: pit[ch].low_read = 1;
16917: pit[ch].high_read = 0;
16918: } else if((pit[ch].ctrl_reg & 0x30) == 0x20) {
16919: // upper byte
16920: pit[ch].low_read = 0;
16921: pit[ch].high_read = 1;
16922: } else {
16923: // lower -> upper
1.1.1.14 root 16924: pit[ch].low_read = pit[ch].high_read = 1;
1.1 root 16925: }
16926: }
16927:
1.1.1.8 root 16928: int pit_get_expired_time(int ch)
1.1 root 16929: {
1.1.1.22 root 16930: pit[ch].accum += 1024ULL * 1000ULL * (UINT64)pit[ch].count / PIT_FREQ;
16931: UINT64 val = pit[ch].accum >> 10;
16932: pit[ch].accum -= val << 10;
16933: return((val != 0) ? val : 1);
1.1.1.8 root 16934: }
16935:
1.1.1.25 root 16936: // sio
16937:
16938: void sio_init()
16939: {
1.1.1.26 root 16940: memset(sio, 0, sizeof(sio));
16941: memset(sio_mt, 0, sizeof(sio_mt));
16942:
1.1.1.29 root 16943: for(int c = 0; c < 4; c++) {
1.1.1.25 root 16944: sio[c].send_buffer = new FIFO(SIO_BUFFER_SIZE);
16945: sio[c].recv_buffer = new FIFO(SIO_BUFFER_SIZE);
16946:
16947: sio[c].divisor.w = 12; // 115200Hz / 9600Baud
16948: sio[c].line_ctrl = 0x03; // 8bit, stop 1bit, non parity
1.1.1.26 root 16949: sio[c].modem_ctrl = 0x03; // rts=on, dtr=on
16950: sio[c].set_rts = sio[c].set_dtr = true;
1.1.1.25 root 16951: sio[c].line_stat_buf = 0x60; // send/recv buffers are empty
16952: sio[c].irq_identify = 0x01; // no pending irq
16953:
16954: InitializeCriticalSection(&sio_mt[c].csSendData);
16955: InitializeCriticalSection(&sio_mt[c].csRecvData);
16956: InitializeCriticalSection(&sio_mt[c].csLineCtrl);
16957: InitializeCriticalSection(&sio_mt[c].csLineStat);
16958: InitializeCriticalSection(&sio_mt[c].csModemCtrl);
16959: InitializeCriticalSection(&sio_mt[c].csModemStat);
16960:
1.1.1.26 root 16961: if(sio_port_number[c] != 0) {
1.1.1.25 root 16962: sio[c].channel = c;
16963: sio_mt[c].hThread = CreateThread(NULL, 0, sio_thread, &sio[c], 0, NULL);
16964: }
16965: }
16966: }
16967:
16968: void sio_finish()
16969: {
1.1.1.29 root 16970: for(int c = 0; c < 4; c++) {
1.1.1.25 root 16971: if(sio_mt[c].hThread != NULL) {
16972: WaitForSingleObject(sio_mt[c].hThread, INFINITE);
16973: CloseHandle(sio_mt[c].hThread);
1.1.1.28 root 16974: sio_mt[c].hThread = NULL;
1.1.1.25 root 16975: }
16976: DeleteCriticalSection(&sio_mt[c].csSendData);
16977: DeleteCriticalSection(&sio_mt[c].csRecvData);
16978: DeleteCriticalSection(&sio_mt[c].csLineCtrl);
16979: DeleteCriticalSection(&sio_mt[c].csLineStat);
16980: DeleteCriticalSection(&sio_mt[c].csModemCtrl);
16981: DeleteCriticalSection(&sio_mt[c].csModemStat);
1.1.1.28 root 16982: }
16983: sio_release();
16984: }
16985:
16986: void sio_release()
16987: {
1.1.1.29 root 16988: for(int c = 0; c < 4; c++) {
1.1.1.28 root 16989: // sio_thread() may access the resources :-(
1.1.1.32 root 16990: bool running = (sio_mt[c].hThread != NULL);
16991:
16992: if(running) {
16993: EnterCriticalSection(&sio_mt[c].csSendData);
16994: }
16995: if(sio[c].send_buffer != NULL) {
16996: sio[c].send_buffer->release();
16997: delete sio[c].send_buffer;
16998: sio[c].send_buffer = NULL;
16999: }
17000: if(running) {
17001: LeaveCriticalSection(&sio_mt[c].csSendData);
17002: EnterCriticalSection(&sio_mt[c].csRecvData);
17003: }
17004: if(sio[c].recv_buffer != NULL) {
17005: sio[c].recv_buffer->release();
17006: delete sio[c].recv_buffer;
17007: sio[c].recv_buffer = NULL;
17008: }
17009: if(running) {
17010: LeaveCriticalSection(&sio_mt[c].csRecvData);
1.1.1.28 root 17011: }
1.1.1.25 root 17012: }
17013: }
17014:
17015: void sio_write(int c, UINT32 addr, UINT8 data)
17016: {
17017: switch(addr & 7) {
17018: case 0:
17019: if(sio[c].selector & 0x80) {
17020: if(sio[c].divisor.b.l != data) {
17021: EnterCriticalSection(&sio_mt[c].csLineCtrl);
17022: sio[c].divisor.b.l = data;
17023: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
17024: }
17025: } else {
17026: EnterCriticalSection(&sio_mt[c].csSendData);
1.1.1.32 root 17027: if(sio[c].send_buffer != NULL) {
17028: sio[c].send_buffer->write(data);
17029: }
1.1.1.25 root 17030: // transmitter holding/shift registers are not empty
17031: sio[c].line_stat_buf &= ~0x60;
17032: LeaveCriticalSection(&sio_mt[c].csSendData);
17033:
17034: if(sio[c].irq_enable & 0x02) {
17035: sio_update_irq(c);
17036: }
17037: }
17038: break;
17039: case 1:
17040: if(sio[c].selector & 0x80) {
17041: if(sio[c].divisor.b.h != data) {
17042: EnterCriticalSection(&sio_mt[c].csLineCtrl);
17043: sio[c].divisor.b.h = data;
17044: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
17045: }
17046: } else {
17047: if(sio[c].irq_enable != data) {
17048: sio[c].irq_enable = data;
17049: sio_update_irq(c);
17050: }
17051: }
17052: break;
17053: case 3:
17054: {
17055: UINT8 line_ctrl = data & 0x3f;
17056: bool set_brk = ((data & 0x40) != 0);
17057:
17058: if(sio[c].line_ctrl != line_ctrl) {
17059: EnterCriticalSection(&sio_mt[c].csLineCtrl);
17060: sio[c].line_ctrl = line_ctrl;
17061: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
17062: }
17063: if(sio[c].set_brk != set_brk) {
17064: EnterCriticalSection(&sio_mt[c].csModemCtrl);
17065: sio[c].set_brk = set_brk;
17066: LeaveCriticalSection(&sio_mt[c].csModemCtrl);
17067: }
17068: }
17069: sio[c].selector = data;
17070: break;
17071: case 4:
17072: {
17073: bool set_dtr = ((data & 0x01) != 0);
17074: bool set_rts = ((data & 0x02) != 0);
17075:
17076: if(sio[c].set_dtr != set_dtr || sio[c].set_rts != set_rts) {
1.1.1.26 root 17077: // EnterCriticalSection(&sio_mt[c].csModemCtrl);
1.1.1.25 root 17078: sio[c].set_dtr = set_dtr;
17079: sio[c].set_rts = set_rts;
1.1.1.26 root 17080: // LeaveCriticalSection(&sio_mt[c].csModemCtrl);
17081:
17082: bool state_changed = false;
17083:
17084: EnterCriticalSection(&sio_mt[c].csModemStat);
17085: if(set_dtr) {
17086: sio[c].modem_stat |= 0x20; // dsr on
17087: } else {
17088: sio[c].modem_stat &= ~0x20; // dsr off
17089: }
17090: if(set_rts) {
17091: sio[c].modem_stat |= 0x10; // cts on
17092: } else {
17093: sio[c].modem_stat &= ~0x10; // cts off
17094: }
17095: if((sio[c].prev_modem_stat & 0x20) != (sio[c].modem_stat & 0x20)) {
17096: if(!(sio[c].modem_stat & 0x02)) {
17097: if(sio[c].irq_enable & 0x08) {
17098: state_changed = true;
17099: }
17100: sio[c].modem_stat |= 0x02;
17101: }
17102: }
17103: if((sio[c].prev_modem_stat & 0x10) != (sio[c].modem_stat & 0x10)) {
17104: if(!(sio[c].modem_stat & 0x01)) {
17105: if(sio[c].irq_enable & 0x08) {
17106: state_changed = true;
17107: }
17108: sio[c].modem_stat |= 0x01;
17109: }
17110: }
17111: LeaveCriticalSection(&sio_mt[c].csModemStat);
17112:
17113: if(state_changed) {
17114: sio_update_irq(c);
17115: }
1.1.1.25 root 17116: }
17117: }
17118: sio[c].modem_ctrl = data;
17119: break;
17120: case 7:
17121: sio[c].scratch = data;
17122: break;
17123: }
17124: }
17125:
17126: UINT8 sio_read(int c, UINT32 addr)
17127: {
17128: switch(addr & 7) {
17129: case 0:
17130: if(sio[c].selector & 0x80) {
17131: return(sio[c].divisor.b.l);
17132: } else {
17133: EnterCriticalSection(&sio_mt[c].csRecvData);
1.1.1.32 root 17134: UINT8 data = 0;
17135: if(sio[c].recv_buffer != NULL) {
17136: data = sio[c].recv_buffer->read();
17137: }
1.1.1.25 root 17138: // data is not ready
17139: sio[c].line_stat_buf &= ~0x01;
17140: LeaveCriticalSection(&sio_mt[c].csRecvData);
17141:
17142: if(sio[c].irq_enable & 0x01) {
17143: sio_update_irq(c);
17144: }
17145: return(data);
17146: }
17147: case 1:
17148: if(sio[c].selector & 0x80) {
17149: return(sio[c].divisor.b.h);
17150: } else {
17151: return(sio[c].irq_enable);
17152: }
17153: case 2:
17154: return(sio[c].irq_identify);
17155: case 3:
17156: return(sio[c].selector);
17157: case 4:
17158: return(sio[c].modem_ctrl);
17159: case 5:
17160: {
17161: EnterCriticalSection(&sio_mt[c].csLineStat);
17162: UINT8 val = sio[c].line_stat_err | sio[c].line_stat_buf;
17163: sio[c].line_stat_err = 0x00;
17164: LeaveCriticalSection(&sio_mt[c].csLineStat);
17165:
17166: bool state_changed = false;
17167:
17168: if((sio[c].line_stat_buf & 0x60) == 0x00) {
17169: EnterCriticalSection(&sio_mt[c].csSendData);
1.1.1.32 root 17170: if(sio[c].send_buffer != NULL && !sio[c].send_buffer->full()) {
1.1.1.25 root 17171: // transmitter holding register will be empty first
17172: if(sio[c].irq_enable & 0x02) {
17173: state_changed = true;
17174: }
17175: sio[c].line_stat_buf |= 0x20;
17176: }
17177: LeaveCriticalSection(&sio_mt[c].csSendData);
17178: } else if((sio[c].line_stat_buf & 0x60) == 0x20) {
17179: // transmitter shift register will be empty later
17180: sio[c].line_stat_buf |= 0x40;
17181: }
17182: if(!(sio[c].line_stat_buf & 0x01)) {
17183: EnterCriticalSection(&sio_mt[c].csRecvData);
1.1.1.32 root 17184: if(sio[c].recv_buffer != NULL && !sio[c].recv_buffer->empty()) {
1.1.1.25 root 17185: // data is ready
17186: if(sio[c].irq_enable & 0x01) {
17187: state_changed = true;
17188: }
17189: sio[c].line_stat_buf |= 0x01;
17190: }
17191: LeaveCriticalSection(&sio_mt[c].csRecvData);
17192: }
17193: if(state_changed) {
17194: sio_update_irq(c);
17195: }
17196: return(val);
17197: }
17198: case 6:
17199: {
17200: EnterCriticalSection(&sio_mt[c].csModemStat);
17201: UINT8 val = sio[c].modem_stat;
17202: sio[c].modem_stat &= 0xf0;
17203: sio[c].prev_modem_stat = sio[c].modem_stat;
17204: LeaveCriticalSection(&sio_mt[c].csModemStat);
17205:
17206: if(sio[c].modem_ctrl & 0x10) {
17207: // loop-back
17208: val &= 0x0f;
17209: val |= (sio[c].modem_ctrl & 0x0c) << 4;
17210: val |= (sio[c].modem_ctrl & 0x01) << 5;
17211: val |= (sio[c].modem_ctrl & 0x02) << 3;
17212: }
17213: return(val);
17214: }
17215: case 7:
17216: return(sio[c].scratch);
17217: }
17218: return(0xff);
17219: }
17220:
17221: void sio_update(int c)
17222: {
17223: if((sio[c].line_stat_buf & 0x60) == 0x00) {
17224: EnterCriticalSection(&sio_mt[c].csSendData);
1.1.1.32 root 17225: if(sio[c].send_buffer != NULL && !sio[c].send_buffer->full()) {
1.1.1.25 root 17226: // transmitter holding/shift registers will be empty
17227: sio[c].line_stat_buf |= 0x60;
17228: }
17229: LeaveCriticalSection(&sio_mt[c].csSendData);
17230: } else if((sio[c].line_stat_buf & 0x60) == 0x20) {
17231: // transmitter shift register will be empty
17232: sio[c].line_stat_buf |= 0x40;
17233: }
17234: if(!(sio[c].line_stat_buf & 0x01)) {
17235: EnterCriticalSection(&sio_mt[c].csRecvData);
1.1.1.32 root 17236: if(sio[c].recv_buffer != NULL && !sio[c].recv_buffer->empty()) {
1.1.1.25 root 17237: // data is ready
17238: sio[c].line_stat_buf |= 0x01;
17239: }
17240: LeaveCriticalSection(&sio_mt[c].csRecvData);
17241: }
17242: sio_update_irq(c);
17243: }
17244:
17245: void sio_update_irq(int c)
17246: {
17247: int level = -1;
17248:
17249: if(sio[c].irq_enable & 0x08) {
17250: EnterCriticalSection(&sio_mt[c].csModemStat);
17251: if((sio[c].modem_stat & 0x0f) != 0) {
17252: level = 0;
17253: }
17254: EnterCriticalSection(&sio_mt[c].csModemStat);
17255: }
17256: if(sio[c].irq_enable & 0x02) {
17257: if(sio[c].line_stat_buf & 0x20) {
17258: level = 1;
17259: }
17260: }
17261: if(sio[c].irq_enable & 0x01) {
17262: if(sio[c].line_stat_buf & 0x01) {
17263: level = 2;
17264: }
17265: }
17266: if(sio[c].irq_enable & 0x04) {
17267: EnterCriticalSection(&sio_mt[c].csLineStat);
17268: if(sio[c].line_stat_err != 0) {
17269: level = 3;
17270: }
17271: LeaveCriticalSection(&sio_mt[c].csLineStat);
17272: }
1.1.1.29 root 17273:
17274: // COM1 and COM3 shares IRQ4, COM2 and COM4 shares IRQ3
1.1.1.25 root 17275: if(level != -1) {
17276: sio[c].irq_identify = level << 1;
1.1.1.29 root 17277: pic_req(0, (c == 0 || c == 2) ? 4 : 3, 1);
1.1.1.25 root 17278: } else {
17279: sio[c].irq_identify = 1;
1.1.1.29 root 17280: pic_req(0, (c == 0 || c == 2) ? 4 : 3, 0);
1.1.1.25 root 17281: }
17282: }
17283:
17284: DWORD WINAPI sio_thread(void *lpx)
17285: {
17286: volatile sio_t *p = (sio_t *)lpx;
17287: sio_mt_t *q = &sio_mt[p->channel];
17288:
17289: char name[] = "COM1";
1.1.1.26 root 17290: name[3] = '0' + sio_port_number[p->channel];
17291: HANDLE hComm = NULL;
17292: COMMPROP commProp;
17293: DCB dcb;
17294: DWORD dwSettableBaud = 0xffb; // 75, 110, 150, 300, 600, 1200, 1800, 2400, 4800, 7200, and 9600bps
17295: BYTE bytBuffer[SIO_BUFFER_SIZE];
17296:
17297: if((hComm = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE) {
17298: if(GetCommProperties(hComm, &commProp)) {
17299: dwSettableBaud = commProp.dwSettableBaud;
17300: }
1.1.1.25 root 17301: EscapeCommFunction(hComm, CLRBREAK);
1.1.1.26 root 17302: // EscapeCommFunction(hComm, SETRTS);
17303: // EscapeCommFunction(hComm, SETDTR);
1.1.1.25 root 17304:
17305: while(!m_halted) {
17306: // setup comm port
17307: bool comm_state_changed = false;
17308:
17309: EnterCriticalSection(&q->csLineCtrl);
17310: if((p->prev_divisor != p->divisor.w || p->prev_line_ctrl != p->line_ctrl) && p->divisor.w != 0) {
17311: p->prev_divisor = p->divisor.w;
17312: p->prev_line_ctrl = p->line_ctrl;
17313: comm_state_changed = true;
17314: }
17315: LeaveCriticalSection(&q->csLineCtrl);
17316:
17317: if(comm_state_changed) {
1.1.1.26 root 17318: if(GetCommState(hComm, &dcb)) {
17319: // dcb.BaudRate = min(9600, 115200 / p->prev_divisor);
17320: DWORD baud = 115200 / p->prev_divisor;
17321: dcb.BaudRate = 9600; // default
17322:
17323: if((dwSettableBaud & BAUD_075 ) && baud >= 75 ) dcb.BaudRate = 75;
17324: if((dwSettableBaud & BAUD_110 ) && baud >= 110 ) dcb.BaudRate = 110;
17325: // 134.5bps is not supported ???
17326: // if((dwSettableBaud & BAUD_134_5) && baud >= 134.5) dcb.BaudRate = 134.5;
17327: if((dwSettableBaud & BAUD_150 ) && baud >= 150 ) dcb.BaudRate = 150;
17328: if((dwSettableBaud & BAUD_300 ) && baud >= 300 ) dcb.BaudRate = 300;
17329: if((dwSettableBaud & BAUD_600 ) && baud >= 600 ) dcb.BaudRate = 600;
17330: if((dwSettableBaud & BAUD_1200 ) && baud >= 1200 ) dcb.BaudRate = 1200;
17331: if((dwSettableBaud & BAUD_1800 ) && baud >= 1800 ) dcb.BaudRate = 1800;
17332: if((dwSettableBaud & BAUD_2400 ) && baud >= 2400 ) dcb.BaudRate = 2400;
17333: if((dwSettableBaud & BAUD_4800 ) && baud >= 4800 ) dcb.BaudRate = 4800;
17334: if((dwSettableBaud & BAUD_7200 ) && baud >= 7200 ) dcb.BaudRate = 7200;
17335: if((dwSettableBaud & BAUD_9600 ) && baud >= 9600 ) dcb.BaudRate = 9600;
17336: // if((dwSettableBaud & BAUD_14400) && baud >= 14400) dcb.BaudRate = 14400;
17337: // if((dwSettableBaud & BAUD_19200) && baud >= 19200) dcb.BaudRate = 19200;
17338: // if((dwSettableBaud & BAUD_38400) && baud >= 38400) dcb.BaudRate = 38400;
17339:
17340: switch(p->prev_line_ctrl & 0x03) {
17341: case 0x00: dcb.ByteSize = 5; break;
17342: case 0x01: dcb.ByteSize = 6; break;
17343: case 0x02: dcb.ByteSize = 7; break;
17344: case 0x03: dcb.ByteSize = 8; break;
17345: }
17346: switch(p->prev_line_ctrl & 0x04) {
17347: case 0x00: dcb.StopBits = ONESTOPBIT; break;
17348: case 0x04: dcb.StopBits = (dcb.ByteSize == 5) ? ONE5STOPBITS : TWOSTOPBITS; break;
17349: }
17350: switch(p->prev_line_ctrl & 0x38) {
17351: case 0x08: dcb.Parity = ODDPARITY; break;
17352: case 0x18: dcb.Parity = EVENPARITY; break;
17353: case 0x28: dcb.Parity = MARKPARITY; break;
17354: case 0x38: dcb.Parity = SPACEPARITY; break;
17355: default: dcb.Parity = NOPARITY; break;
17356: }
17357: dcb.fBinary = TRUE;
17358: dcb.fParity = (dcb.Parity != NOPARITY);
17359: dcb.fOutxCtsFlow = dcb.fOutxDsrFlow = TRUE;
17360: dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
17361: dcb.fDsrSensitivity = FALSE;//TRUE;
17362: dcb.fTXContinueOnXoff = TRUE;
17363: dcb.fOutX = dcb.fInX = FALSE;
17364: dcb.fErrorChar = FALSE;
17365: dcb.fNull = FALSE;
17366: dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
17367: dcb.fAbortOnError = FALSE;
17368:
17369: SetCommState(hComm, &dcb);
1.1.1.25 root 17370: }
17371:
17372: // check again to apply all comm state changes
17373: Sleep(10);
17374: continue;
17375: }
17376:
17377: // set comm pins
17378: bool change_brk = false;
1.1.1.26 root 17379: // bool change_rts = false;
17380: // bool change_dtr = false;
1.1.1.25 root 17381:
17382: EnterCriticalSection(&q->csModemCtrl);
17383: if(p->prev_set_brk != p->set_brk) {
17384: p->prev_set_brk = p->set_brk;
17385: change_brk = true;
17386: }
1.1.1.26 root 17387: // if(p->prev_set_rts != p->set_rts) {
17388: // p->prev_set_rts = p->set_rts;
17389: // change_rts = true;
17390: // }
17391: // if(p->prev_set_dtr != p->set_dtr) {
17392: // p->prev_set_dtr = p->set_dtr;
17393: // change_dtr = true;
17394: // }
1.1.1.25 root 17395: LeaveCriticalSection(&q->csModemCtrl);
17396:
17397: if(change_brk) {
1.1.1.26 root 17398: static UINT32 clear_time = 0;
17399: if(p->prev_set_brk) {
17400: EscapeCommFunction(hComm, SETBREAK);
17401: clear_time = timeGetTime() + 200;
17402: } else {
17403: // keep break for at least 200msec
17404: UINT32 cur_time = timeGetTime();
17405: if(clear_time > cur_time) {
17406: Sleep(clear_time - cur_time);
17407: }
17408: EscapeCommFunction(hComm, CLRBREAK);
17409: }
1.1.1.25 root 17410: }
1.1.1.26 root 17411: // if(change_rts) {
17412: // if(p->prev_set_rts) {
17413: // EscapeCommFunction(hComm, SETRTS);
17414: // } else {
17415: // EscapeCommFunction(hComm, CLRRTS);
17416: // }
17417: // }
17418: // if(change_dtr) {
17419: // if(p->prev_set_dtr) {
17420: // EscapeCommFunction(hComm, SETDTR);
17421: // } else {
17422: // EscapeCommFunction(hComm, CLRDTR);
17423: // }
17424: // }
1.1.1.25 root 17425:
17426: // get comm pins
17427: DWORD dwModemStat = 0;
17428:
17429: if(GetCommModemStatus(hComm, &dwModemStat)) {
17430: EnterCriticalSection(&q->csModemStat);
17431: if(dwModemStat & MS_RLSD_ON) {
17432: p->modem_stat |= 0x80;
17433: } else {
17434: p->modem_stat &= ~0x80;
17435: }
17436: if(dwModemStat & MS_RING_ON) {
17437: p->modem_stat |= 0x40;
17438: } else {
17439: p->modem_stat &= ~0x40;
17440: }
1.1.1.26 root 17441: // if(dwModemStat & MS_DSR_ON) {
17442: // p->modem_stat |= 0x20;
17443: // } else {
17444: // p->modem_stat &= ~0x20;
17445: // }
17446: // if(dwModemStat & MS_CTS_ON) {
17447: // p->modem_stat |= 0x10;
17448: // } else {
17449: // p->modem_stat &= ~0x10;
17450: // }
1.1.1.25 root 17451: if((p->prev_modem_stat & 0x80) != (p->modem_stat & 0x80)) {
17452: p->modem_stat |= 0x08;
17453: }
17454: if((p->prev_modem_stat & 0x40) && !(p->modem_stat & 0x40)) {
17455: p->modem_stat |= 0x04;
17456: }
1.1.1.26 root 17457: // if((p->prev_modem_stat & 0x20) != (p->modem_stat & 0x20)) {
17458: // p->modem_stat |= 0x02;
17459: // }
17460: // if((p->prev_modem_stat & 0x10) != (p->modem_stat & 0x10)) {
17461: // p->modem_stat |= 0x01;
17462: // }
1.1.1.25 root 17463: LeaveCriticalSection(&q->csModemStat);
17464: }
17465:
17466: // send data
17467: DWORD dwSend = 0;
17468:
17469: EnterCriticalSection(&q->csSendData);
1.1.1.32 root 17470: while(p->send_buffer != NULL && !p->send_buffer->empty()) {
1.1.1.25 root 17471: bytBuffer[dwSend++] = p->send_buffer->read();
17472: }
17473: LeaveCriticalSection(&q->csSendData);
17474:
17475: if(dwSend != 0) {
17476: DWORD dwWritten = 0;
17477: WriteFile(hComm, bytBuffer, dwSend, &dwWritten, NULL);
17478: }
17479:
17480: // get line status and recv data
17481: DWORD dwLineStat = 0;
17482: COMSTAT comStat;
17483:
17484: if(ClearCommError(hComm, &dwLineStat, &comStat)) {
17485: EnterCriticalSection(&q->csLineStat);
17486: if(dwLineStat & CE_BREAK) {
17487: p->line_stat_err |= 0x10;
17488: }
17489: if(dwLineStat & CE_FRAME) {
17490: p->line_stat_err |= 0x08;
17491: }
17492: if(dwLineStat & CE_RXPARITY) {
17493: p->line_stat_err |= 0x04;
17494: }
17495: if(dwLineStat & CE_OVERRUN) {
17496: p->line_stat_err |= 0x02;
17497: }
17498: LeaveCriticalSection(&q->csLineStat);
17499:
17500: if(comStat.cbInQue != 0) {
17501: EnterCriticalSection(&q->csRecvData);
1.1.1.32 root 17502: DWORD dwRecv = 0;
17503: if(p->recv_buffer != NULL) {
17504: dwRecv = min(comStat.cbInQue, p->recv_buffer->remain());
17505: }
1.1.1.25 root 17506: LeaveCriticalSection(&q->csRecvData);
17507:
17508: if(dwRecv != 0) {
17509: DWORD dwRead = 0;
17510: if(ReadFile(hComm, bytBuffer, dwRecv, &dwRead, NULL) && dwRead != 0) {
17511: EnterCriticalSection(&q->csRecvData);
1.1.1.32 root 17512: if(p->recv_buffer != NULL) {
17513: for(int i = 0; i < dwRead; i++) {
17514: p->recv_buffer->write(bytBuffer[i]);
17515: }
1.1.1.25 root 17516: }
17517: LeaveCriticalSection(&q->csRecvData);
17518: }
17519: }
17520: }
17521: }
17522: Sleep(10);
17523: }
17524: CloseHandle(hComm);
17525: }
17526: return 0;
17527: }
17528:
1.1.1.8 root 17529: // cmos
17530:
17531: void cmos_init()
17532: {
17533: memset(cmos, 0, sizeof(cmos));
17534: cmos_addr = 0;
1.1 root 17535:
1.1.1.8 root 17536: // from DOSBox
17537: cmos_write(0x0a, 0x26);
17538: cmos_write(0x0b, 0x02);
17539: cmos_write(0x0d, 0x80);
1.1 root 17540: }
17541:
1.1.1.8 root 17542: void cmos_write(int addr, UINT8 val)
1.1 root 17543: {
1.1.1.8 root 17544: cmos[addr & 0x7f] = val;
17545: }
17546:
17547: #define CMOS_GET_TIME() { \
17548: UINT32 cur_sec = timeGetTime() / 1000 ; \
17549: if(prev_sec != cur_sec) { \
17550: GetLocalTime(&time); \
17551: prev_sec = cur_sec; \
17552: } \
1.1 root 17553: }
1.1.1.8 root 17554: #define CMOS_BCD(v) ((cmos[0x0b] & 4) ? (v) : to_bcd(v))
1.1 root 17555:
1.1.1.8 root 17556: UINT8 cmos_read(int addr)
1.1 root 17557: {
1.1.1.8 root 17558: static SYSTEMTIME time;
17559: static UINT32 prev_sec = 0;
1.1 root 17560:
1.1.1.8 root 17561: switch(addr & 0x7f) {
17562: case 0x00: CMOS_GET_TIME(); return(CMOS_BCD(time.wSecond));
17563: case 0x02: CMOS_GET_TIME(); return(CMOS_BCD(time.wMinute));
17564: case 0x04: CMOS_GET_TIME(); return(CMOS_BCD(time.wHour));
17565: case 0x06: CMOS_GET_TIME(); return(time.wDayOfWeek + 1);
17566: case 0x07: CMOS_GET_TIME(); return(CMOS_BCD(time.wDay));
17567: case 0x08: CMOS_GET_TIME(); return(CMOS_BCD(time.wMonth));
17568: case 0x09: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear));
17569: // case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 2 ? 0x80 : 0)); // 2msec
17570: case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 20 ? 0x80 : 0)); // precision of timeGetTime() may not be 1msec
17571: case 0x15: return((MEMORY_END >> 10) & 0xff);
17572: case 0x16: return((MEMORY_END >> 18) & 0xff);
17573: case 0x17: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
17574: case 0x18: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
17575: case 0x30: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
17576: case 0x31: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
17577: case 0x32: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear / 100));
1.1 root 17578: }
1.1.1.8 root 17579: return(cmos[addr & 0x7f]);
1.1 root 17580: }
17581:
1.1.1.7 root 17582: // kbd (a20)
17583:
17584: void kbd_init()
17585: {
1.1.1.8 root 17586: kbd_data = kbd_command = 0;
1.1.1.7 root 17587: kbd_status = 0x18;
17588: }
17589:
17590: UINT8 kbd_read_data()
17591: {
1.1.1.8 root 17592: kbd_status &= ~1;
1.1.1.7 root 17593: return(kbd_data);
17594: }
17595:
17596: void kbd_write_data(UINT8 val)
17597: {
17598: switch(kbd_command) {
17599: case 0xd1:
17600: i386_set_a20_line((val >> 1) & 1);
17601: break;
17602: }
17603: kbd_command = 0;
1.1.1.8 root 17604: kbd_status &= ~8;
1.1.1.7 root 17605: }
17606:
17607: UINT8 kbd_read_status()
17608: {
17609: return(kbd_status);
17610: }
17611:
17612: void kbd_write_command(UINT8 val)
17613: {
17614: switch(val) {
17615: case 0xd0:
17616: kbd_data = ((m_a20_mask >> 19) & 2) | 1;
1.1.1.8 root 17617: kbd_status |= 1;
1.1.1.7 root 17618: break;
17619: case 0xdd:
17620: i386_set_a20_line(0);
17621: break;
17622: case 0xdf:
17623: i386_set_a20_line(1);
17624: break;
1.1.1.26 root 17625: case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
17626: case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
1.1.1.7 root 17627: if(!(val & 1)) {
1.1.1.8 root 17628: if((cmos[0x0f] & 0x7f) == 5) {
1.1.1.7 root 17629: // reset pic
17630: pic_init();
17631: pic[0].irr = pic[1].irr = 0x00;
17632: pic[0].imr = pic[1].imr = 0xff;
17633: }
17634: CPU_RESET_CALL(CPU_MODEL);
1.1.1.40 root 17635: UINT16 address = *(UINT16 *)(mem + 0x467);
17636: UINT16 selector = *(UINT16 *)(mem + 0x469);
17637: i386_jmp_far(selector, address);
1.1.1.7 root 17638: }
17639: i386_set_a20_line((val >> 1) & 1);
17640: break;
17641: }
17642: kbd_command = val;
1.1.1.8 root 17643: kbd_status |= 8;
1.1.1.7 root 17644: }
17645:
1.1.1.9 root 17646: // vga
17647:
17648: UINT8 vga_read_status()
17649: {
17650: // 60hz
17651: static const int period[3] = {16, 17, 17};
17652: static int index = 0;
17653: UINT32 time = timeGetTime() % period[index];
17654:
17655: index = (index + 1) % 3;
1.1.1.14 root 17656: return((time < 4 ? 0x08 : 0) | (time == 0 ? 0 : 0x01));
1.1.1.9 root 17657: }
17658:
1.1 root 17659: // i/o bus
17660:
1.1.1.29 root 17661: // this is ugly patch for SW1US.EXE, it sometimes mistakely read/write 01h-10h for serial I/O
17662: //#define SW1US_PATCH
17663:
1.1.1.25 root 17664: UINT8 read_io_byte(offs_t addr)
1.1.1.33 root 17665: #ifdef USE_DEBUGGER
1.1.1.25 root 17666: {
1.1.1.33 root 17667: if(now_debugging) {
17668: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
17669: if(in_break_point.table[i].status == 1) {
17670: if(addr == in_break_point.table[i].addr) {
17671: in_break_point.hit = i + 1;
17672: now_suspended = true;
17673: break;
17674: }
17675: }
17676: }
1.1.1.25 root 17677: }
1.1.1.33 root 17678: return(debugger_read_io_byte(addr));
1.1.1.25 root 17679: }
1.1.1.33 root 17680: UINT8 debugger_read_io_byte(offs_t addr)
1.1.1.25 root 17681: #endif
1.1 root 17682: {
1.1.1.33 root 17683: UINT8 val = 0xff;
17684:
1.1 root 17685: switch(addr) {
1.1.1.29 root 17686: #ifdef SW1US_PATCH
17687: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08:
17688: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: case 0x10:
1.1.1.33 root 17689: val = sio_read(0, addr - 1);
17690: break;
1.1.1.29 root 17691: #else
1.1.1.25 root 17692: case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
17693: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
1.1.1.33 root 17694: val = dma_read(0, addr);
17695: break;
1.1.1.29 root 17696: #endif
1.1.1.25 root 17697: case 0x20: case 0x21:
1.1.1.33 root 17698: val = pic_read(0, addr);
17699: break;
1.1.1.25 root 17700: case 0x40: case 0x41: case 0x42: case 0x43:
1.1.1.33 root 17701: val = pit_read(addr & 0x03);
17702: break;
1.1.1.7 root 17703: case 0x60:
1.1.1.33 root 17704: val = kbd_read_data();
17705: break;
1.1.1.9 root 17706: case 0x61:
1.1.1.33 root 17707: val = system_port;
17708: break;
1.1.1.7 root 17709: case 0x64:
1.1.1.33 root 17710: val = kbd_read_status();
17711: break;
1.1 root 17712: case 0x71:
1.1.1.33 root 17713: val = cmos_read(cmos_addr);
17714: break;
1.1.1.25 root 17715: case 0x81:
1.1.1.33 root 17716: val = dma_page_read(0, 2);
17717: break;
1.1.1.25 root 17718: case 0x82:
1.1.1.33 root 17719: val = dma_page_read(0, 3);
17720: break;
1.1.1.25 root 17721: case 0x83:
1.1.1.33 root 17722: val = dma_page_read(0, 1);
17723: break;
1.1.1.25 root 17724: case 0x87:
1.1.1.33 root 17725: val = dma_page_read(0, 0);
17726: break;
1.1.1.25 root 17727: case 0x89:
1.1.1.33 root 17728: val = dma_page_read(1, 2);
17729: break;
1.1.1.25 root 17730: case 0x8a:
1.1.1.33 root 17731: val = dma_page_read(1, 3);
17732: break;
1.1.1.25 root 17733: case 0x8b:
1.1.1.33 root 17734: val = dma_page_read(1, 1);
17735: break;
1.1.1.25 root 17736: case 0x8f:
1.1.1.33 root 17737: val = dma_page_read(1, 0);
17738: break;
1.1 root 17739: case 0x92:
1.1.1.33 root 17740: val = (m_a20_mask >> 19) & 2;
17741: break;
1.1.1.25 root 17742: case 0xa0: case 0xa1:
1.1.1.33 root 17743: val = pic_read(1, addr);
17744: break;
1.1.1.25 root 17745: case 0xc0: case 0xc2: case 0xc4: case 0xc6: case 0xc8: case 0xca: case 0xcc: case 0xce:
17746: case 0xd0: case 0xd2: case 0xd4: case 0xd6: case 0xd8: case 0xda: case 0xdc: case 0xde:
1.1.1.33 root 17747: val = dma_read(1, (addr - 0xc0) >> 1);
17748: break;
1.1.1.37 root 17749: case 0x278: case 0x279: case 0x27a:
17750: val = pio_read(1, addr);
17751: break;
1.1.1.29 root 17752: case 0x2e8: case 0x2e9: case 0x2ea: case 0x2eb: case 0x2ec: case 0x2ed: case 0x2ee: case 0x2ef:
1.1.1.33 root 17753: val = sio_read(3, addr);
17754: break;
1.1.1.25 root 17755: case 0x2f8: case 0x2f9: case 0x2fa: case 0x2fb: case 0x2fc: case 0x2fd: case 0x2fe: case 0x2ff:
1.1.1.33 root 17756: val = sio_read(1, addr);
17757: break;
1.1.1.25 root 17758: case 0x378: case 0x379: case 0x37a:
1.1.1.33 root 17759: val = pio_read(0, addr);
17760: break;
1.1.1.25 root 17761: case 0x3ba: case 0x3da:
1.1.1.33 root 17762: val = vga_read_status();
17763: break;
1.1.1.37 root 17764: case 0x3bc: case 0x3bd: case 0x3be:
17765: val = pio_read(2, addr);
17766: break;
1.1.1.29 root 17767: case 0x3e8: case 0x3e9: case 0x3ea: case 0x3eb: case 0x3ec: case 0x3ed: case 0x3ee: case 0x3ef:
1.1.1.33 root 17768: val = sio_read(2, addr);
17769: break;
1.1.1.25 root 17770: case 0x3f8: case 0x3f9: case 0x3fa: case 0x3fb: case 0x3fc: case 0x3fd: case 0x3fe: case 0x3ff:
1.1.1.33 root 17771: val = sio_read(0, addr);
17772: break;
1.1 root 17773: default:
1.1.1.33 root 17774: // fatalerror("unknown inb %4x\n", addr);
1.1 root 17775: break;
17776: }
1.1.1.33 root 17777: #ifdef ENABLE_DEBUG_IOPORT
17778: if(fp_debug_log != NULL) {
17779: fprintf(fp_debug_log, "inb %04X, %02X\n", addr, val);
17780: }
17781: #endif
17782: return(val);
1.1 root 17783: }
17784:
17785: UINT16 read_io_word(offs_t addr)
17786: {
17787: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8));
17788: }
17789:
1.1.1.33 root 17790: #ifdef USE_DEBUGGER
17791: UINT16 debugger_read_io_word(offs_t addr)
17792: {
17793: return(debugger_read_io_byte(addr) | (debugger_read_io_byte(addr + 1) << 8));
17794: }
17795: #endif
17796:
1.1 root 17797: UINT32 read_io_dword(offs_t addr)
17798: {
17799: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8) | (read_io_byte(addr + 2) << 16) | (read_io_byte(addr + 3) << 24));
17800: }
17801:
1.1.1.33 root 17802: #ifdef USE_DEBUGGER
17803: UINT32 debugger_read_io_dword(offs_t addr)
17804: {
17805: 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));
17806: }
17807: #endif
17808:
1.1 root 17809: void write_io_byte(offs_t addr, UINT8 val)
1.1.1.33 root 17810: #ifdef USE_DEBUGGER
17811: {
17812: if(now_debugging) {
17813: for(int i = 0; i < MAX_BREAK_POINTS; i++) {
17814: if(out_break_point.table[i].status == 1) {
17815: if(addr == out_break_point.table[i].addr) {
17816: out_break_point.hit = i + 1;
17817: now_suspended = true;
17818: break;
17819: }
17820: }
17821: }
17822: }
17823: debugger_write_io_byte(addr, val);
17824: }
17825: void debugger_write_io_byte(offs_t addr, UINT8 val)
17826: #endif
1.1 root 17827: {
1.1.1.25 root 17828: #ifdef ENABLE_DEBUG_IOPORT
1.1.1.33 root 17829: if(fp_debug_log != NULL) {
17830: fprintf(fp_debug_log, "outb %04X, %02X\n", addr, val);
1.1.1.25 root 17831: }
17832: #endif
1.1 root 17833: switch(addr) {
1.1.1.29 root 17834: #ifdef SW1US_PATCH
17835: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08:
17836: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: case 0x10:
17837: sio_write(0, addr - 1, val);
17838: break;
17839: #else
1.1.1.25 root 17840: case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
17841: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
17842: dma_write(0, addr, val);
17843: break;
1.1.1.29 root 17844: #endif
1.1.1.25 root 17845: case 0x20: case 0x21:
1.1 root 17846: pic_write(0, addr, val);
17847: break;
1.1.1.25 root 17848: case 0x40: case 0x41: case 0x42: case 0x43:
1.1 root 17849: pit_write(addr & 0x03, val);
17850: break;
1.1.1.7 root 17851: case 0x60:
17852: kbd_write_data(val);
17853: break;
1.1.1.9 root 17854: case 0x61:
17855: if((system_port & 3) != 3 && (val & 3) == 3) {
17856: // beep on
17857: // MessageBeep(-1);
17858: } else if((system_port & 3) == 3 && (val & 3) != 3) {
17859: // beep off
17860: }
17861: system_port = val;
17862: break;
1.1 root 17863: case 0x64:
1.1.1.7 root 17864: kbd_write_command(val);
1.1 root 17865: break;
17866: case 0x70:
17867: cmos_addr = val;
17868: break;
17869: case 0x71:
1.1.1.8 root 17870: cmos_write(cmos_addr, val);
1.1 root 17871: break;
1.1.1.25 root 17872: case 0x81:
17873: dma_page_write(0, 2, val);
17874: case 0x82:
17875: dma_page_write(0, 3, val);
17876: case 0x83:
17877: dma_page_write(0, 1, val);
17878: case 0x87:
17879: dma_page_write(0, 0, val);
17880: case 0x89:
17881: dma_page_write(1, 2, val);
17882: case 0x8a:
17883: dma_page_write(1, 3, val);
17884: case 0x8b:
17885: dma_page_write(1, 1, val);
17886: case 0x8f:
17887: dma_page_write(1, 0, val);
1.1 root 17888: case 0x92:
1.1.1.7 root 17889: i386_set_a20_line((val >> 1) & 1);
1.1 root 17890: break;
1.1.1.25 root 17891: case 0xa0: case 0xa1:
1.1 root 17892: pic_write(1, addr, val);
17893: break;
1.1.1.25 root 17894: case 0xc0: case 0xc2: case 0xc4: case 0xc6: case 0xc8: case 0xca: case 0xcc: case 0xce:
17895: case 0xd0: case 0xd2: case 0xd4: case 0xd6: case 0xd8: case 0xda: case 0xdc: case 0xde:
1.1.1.26 root 17896: dma_write(1, (addr - 0xc0) >> 1, val);
1.1.1.25 root 17897: break;
1.1.1.35 root 17898: #ifdef USE_SERVICE_THREAD
17899: case 0xf7:
17900: // dummy i/o for BIOS/DOS service
1.1.1.36 root 17901: if(in_service && cursor_moved) {
17902: // update cursor position before service is done
17903: pcbios_update_cursor_position();
17904: cursor_moved = false;
17905: }
1.1.1.35 root 17906: finish_service_loop();
17907: break;
17908: #endif
1.1.1.37 root 17909: case 0x278: case 0x279: case 0x27a:
17910: pio_write(1, addr, val);
17911: break;
1.1.1.29 root 17912: case 0x2e8: case 0x2e9: case 0x2ea: case 0x2eb: case 0x2ec: case 0x2ed: case 0x2ee: case 0x2ef:
17913: sio_write(3, addr, val);
17914: break;
1.1.1.25 root 17915: case 0x2f8: case 0x2f9: case 0x2fa: case 0x2fb: case 0x2fc: case 0x2fd: case 0x2fe: case 0x2ff:
17916: sio_write(1, addr, val);
17917: break;
17918: case 0x378: case 0x379: case 0x37a:
17919: pio_write(0, addr, val);
17920: break;
1.1.1.37 root 17921: case 0x3bc: case 0x3bd: case 0x3be:
17922: pio_write(2, addr, val);
17923: break;
1.1.1.29 root 17924: case 0x3e8: case 0x3e9: case 0x3ea: case 0x3eb: case 0x3ec: case 0x3ed: case 0x3ee: case 0x3ef:
17925: sio_write(2, addr, val);
17926: break;
1.1.1.25 root 17927: case 0x3f8: case 0x3f9: case 0x3fa: case 0x3fb: case 0x3fc: case 0x3fd: case 0x3fe: case 0x3ff:
17928: sio_write(0, addr, val);
17929: break;
1.1 root 17930: default:
1.1.1.33 root 17931: // fatalerror("unknown outb %4x,%2x\n", addr, val);
1.1 root 17932: break;
17933: }
17934: }
17935:
17936: void write_io_word(offs_t addr, UINT16 val)
17937: {
17938: write_io_byte(addr + 0, (val >> 0) & 0xff);
17939: write_io_byte(addr + 1, (val >> 8) & 0xff);
17940: }
17941:
1.1.1.33 root 17942: #ifdef USE_DEBUGGER
17943: void debugger_write_io_word(offs_t addr, UINT16 val)
17944: {
17945: debugger_write_io_byte(addr + 0, (val >> 0) & 0xff);
17946: debugger_write_io_byte(addr + 1, (val >> 8) & 0xff);
17947: }
17948: #endif
17949:
1.1 root 17950: void write_io_dword(offs_t addr, UINT32 val)
17951: {
17952: write_io_byte(addr + 0, (val >> 0) & 0xff);
17953: write_io_byte(addr + 1, (val >> 8) & 0xff);
17954: write_io_byte(addr + 2, (val >> 16) & 0xff);
17955: write_io_byte(addr + 3, (val >> 24) & 0xff);
17956: }
1.1.1.33 root 17957:
17958: #ifdef USE_DEBUGGER
17959: void debugger_write_io_dword(offs_t addr, UINT32 val)
17960: {
17961: debugger_write_io_byte(addr + 0, (val >> 0) & 0xff);
17962: debugger_write_io_byte(addr + 1, (val >> 8) & 0xff);
17963: debugger_write_io_byte(addr + 2, (val >> 16) & 0xff);
17964: debugger_write_io_byte(addr + 3, (val >> 24) & 0xff);
17965: }
17966: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.