|
|
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:
10: #define fatalerror(...) { \
11: fprintf(stderr, __VA_ARGS__); \
12: exit(1); \
13: }
14: #define error(...) fprintf(stderr, "error: " __VA_ARGS__)
1.1.1.22! root 15: #define nolog(...)
! 16:
! 17: //#define ENABLE_DEBUG
! 18: #ifdef ENABLE_DEBUG
! 19: #define EXPORT_DEBUG_TO_FILE
! 20: #define ENABLE_DEBUG_DASM
! 21: #define ENABLE_DEBUG_SYSCALL
! 22: #define ENABLE_DEBUG_UNIMPLEMENTED
! 23:
! 24: #ifdef EXPORT_DEBUG_TO_FILE
! 25: FILE* fdebug = NULL;
! 26: #else
! 27: #define fdebug stderr
! 28: #endif
! 29: #ifdef ENABLE_DEBUG_UNIMPLEMENTED
! 30: #define unimplemented_10h fatalerror
! 31: #define unimplemented_15h fatalerror
! 32: #define unimplemented_16h fatalerror
! 33: #define unimplemented_1ah fatalerror
! 34: #define unimplemented_21h fatalerror
! 35: #define unimplemented_2fh fatalerror
! 36: #define unimplemented_67h fatalerror
! 37: #define unimplemented_xms fatalerror
! 38: #endif
! 39: #endif
! 40: #ifndef unimplemented_10h
! 41: #define unimplemented_10h nolog
! 42: #endif
! 43: #ifndef unimplemented_15h
! 44: #define unimplemented_15h nolog
! 45: #endif
! 46: #ifndef unimplemented_16h
! 47: #define unimplemented_16h nolog
! 48: #endif
! 49: #ifndef unimplemented_1ah
! 50: #define unimplemented_1ah nolog
! 51: #endif
! 52: #ifndef unimplemented_21h
! 53: #define unimplemented_21h nolog
! 54: #endif
! 55: #ifndef unimplemented_2fh
! 56: #define unimplemented_2fh nolog
! 57: #endif
! 58: #ifndef unimplemented_67h
! 59: #define unimplemented_67h nolog
! 60: #endif
! 61: #ifndef unimplemented_xms
! 62: #define unimplemented_xms nolog
! 63: #endif
! 64:
! 65: #define my_strchr(str, chr) (char *)_mbschr((unsigned char *)(str), (unsigned int)(chr))
! 66: #define my_strtok(tok, del) (char *)_mbstok((unsigned char *)(tok), (const unsigned char *)(del))
! 67: #define my_strupr(str) (char *)_mbsupr((unsigned char *)(str))
1.1 root 68:
1.1.1.12 root 69: #if defined(__MINGW32__)
70: extern "C" int _CRT_glob = 0;
71: #endif
72:
73: /*
74: kludge for "more-standardized" C++
75: */
76: #if !defined(_MSC_VER)
77: inline int kludge_min(int a, int b) { return (a<b ? a:b); }
78: inline int kludge_max(int a, int b) { return (a>b ? a:b); }
79: #define min(a,b) kludge_min(a,b)
80: #define max(a,b) kludge_max(a,b)
1.1.1.14 root 81: #elif _MSC_VER >= 1400
82: void ignore_invalid_parameters(const wchar_t *, const wchar_t *, const wchar_t *, unsigned int, uintptr_t)
83: {
84: }
85: #endif
86:
87: #define USE_THREAD
88:
89: #ifdef USE_THREAD
90: static CRITICAL_SECTION vram_crit_sect;
91: #else
92: #define EnterCriticalSection(x)
93: #define LeaveCriticalSection(x)
94: #define vram_flush()
1.1.1.12 root 95: #endif
96:
1.1.1.14 root 97: #define VIDEO_REGEN *(UINT16 *)(mem + 0x44c)
98: #define SCR_BUF(y,x) scr_buf[(y) * scr_buf_size.X + (x)]
99:
100: void change_console_size(int width, int height);
101: void clear_scr_buffer(WORD attr);
102:
103: static UINT32 vram_length_char = 0, vram_length_attr = 0;
104: static UINT32 vram_last_length_char = 0, vram_last_length_attr = 0;
105: static COORD vram_coord_char, vram_coord_attr;
106:
107: bool ignore_illegal_insn = false;
108: bool limit_max_memory = false;
109: bool no_windows = false;
110: //bool ctrl_break = false;
111: bool stay_busy = false;
112: UINT32 iops = 0;
1.1.1.19 root 113: bool support_ems = false;
114: #ifdef SUPPORT_XMS
115: bool support_xms = false;
116: #endif
1.1.1.14 root 117:
118: BOOL is_vista_or_later;
119:
120: inline void maybe_idle()
121: {
122: // if it appears to be in a tight loop, assume waiting for input
123: // allow for one updated video character, for a spinning cursor
124: if(!stay_busy && iops < 1000 && vram_length_char <= 1 && vram_length_attr <= 1) {
125: Sleep(10);
126: }
127: iops = 0;
128: }
1.1.1.12 root 129:
1.1 root 130: /* ----------------------------------------------------------------------------
1.1.1.3 root 131: MAME i86/i386
1.1 root 132: ---------------------------------------------------------------------------- */
133:
1.1.1.10 root 134: #ifndef __BIG_ENDIAN__
1.1 root 135: #define LSB_FIRST
1.1.1.10 root 136: #endif
1.1 root 137:
138: #ifndef INLINE
139: #define INLINE inline
140: #endif
141: #define U64(v) UINT64(v)
142:
143: //#define logerror(...) fprintf(stderr, __VA_ARGS__)
144: #define logerror(...)
145: //#define popmessage(...) fprintf(stderr, __VA_ARGS__)
146: #define popmessage(...)
147:
148: /*****************************************************************************/
1.1.1.10 root 149: /* src/emu/devcpu.h */
150:
151: // CPU interface functions
152: #define CPU_INIT_NAME(name) cpu_init_##name
153: #define CPU_INIT(name) void CPU_INIT_NAME(name)()
154: #define CPU_INIT_CALL(name) CPU_INIT_NAME(name)()
155:
156: #define CPU_RESET_NAME(name) cpu_reset_##name
157: #define CPU_RESET(name) void CPU_RESET_NAME(name)()
158: #define CPU_RESET_CALL(name) CPU_RESET_NAME(name)()
159:
160: #define CPU_EXECUTE_NAME(name) cpu_execute_##name
161: #define CPU_EXECUTE(name) void CPU_EXECUTE_NAME(name)()
162: #define CPU_EXECUTE_CALL(name) CPU_EXECUTE_NAME(name)()
163:
164: #define CPU_TRANSLATE_NAME(name) cpu_translate_##name
165: #define CPU_TRANSLATE(name) int CPU_TRANSLATE_NAME(name)(address_spacenum space, int intention, offs_t *address)
166: #define CPU_TRANSLATE_CALL(name) CPU_TRANSLATE_NAME(name)(space, intention, address)
167:
168: #define CPU_DISASSEMBLE_NAME(name) cpu_disassemble_##name
169: #define CPU_DISASSEMBLE(name) int CPU_DISASSEMBLE_NAME(name)(char *buffer, offs_t eip, const UINT8 *oprom)
170: #define CPU_DISASSEMBLE_CALL(name) CPU_DISASSEMBLE_NAME(name)(buffer, eip, oprom)
171:
1.1.1.14 root 172: #define CPU_MODEL_STR(name) #name
173: #define CPU_MODEL_NAME(name) CPU_MODEL_STR(name)
174:
1.1.1.10 root 175: /*****************************************************************************/
176: /* src/emu/didisasm.h */
177:
178: // Disassembler constants
179: const UINT32 DASMFLAG_SUPPORTED = 0x80000000; // are disassembly flags supported?
180: const UINT32 DASMFLAG_STEP_OUT = 0x40000000; // this instruction should be the end of a step out sequence
181: const UINT32 DASMFLAG_STEP_OVER = 0x20000000; // this instruction should be stepped over by setting a breakpoint afterwards
182: const UINT32 DASMFLAG_OVERINSTMASK = 0x18000000; // number of extra instructions to skip when stepping over
183: const UINT32 DASMFLAG_OVERINSTSHIFT = 27; // bits to shift after masking to get the value
184: const UINT32 DASMFLAG_LENGTHMASK = 0x0000ffff; // the low 16-bits contain the actual length
185:
186: /*****************************************************************************/
1.1 root 187: /* src/emu/diexec.h */
188:
189: // I/O line states
190: enum line_state
191: {
192: CLEAR_LINE = 0, // clear (a fired or held) line
193: ASSERT_LINE, // assert an interrupt immediately
194: HOLD_LINE, // hold interrupt line until acknowledged
195: PULSE_LINE // pulse interrupt line instantaneously (only for NMI, RESET)
196: };
197:
198: // I/O line definitions
199: enum
200: {
201: INPUT_LINE_IRQ = 0,
202: INPUT_LINE_NMI
203: };
204:
205: /*****************************************************************************/
1.1.1.10 root 206: /* src/emu/dimemory.h */
1.1 root 207:
1.1.1.10 root 208: // Translation intentions
209: const int TRANSLATE_TYPE_MASK = 0x03; // read write or fetch
210: const int TRANSLATE_USER_MASK = 0x04; // user mode or fully privileged
211: const int TRANSLATE_DEBUG_MASK = 0x08; // debug mode (no side effects)
212:
213: const int TRANSLATE_READ = 0; // translate for read
214: const int TRANSLATE_WRITE = 1; // translate for write
215: const int TRANSLATE_FETCH = 2; // translate for instruction fetch
216: const int TRANSLATE_READ_USER = (TRANSLATE_READ | TRANSLATE_USER_MASK);
217: const int TRANSLATE_WRITE_USER = (TRANSLATE_WRITE | TRANSLATE_USER_MASK);
218: const int TRANSLATE_FETCH_USER = (TRANSLATE_FETCH | TRANSLATE_USER_MASK);
219: const int TRANSLATE_READ_DEBUG = (TRANSLATE_READ | TRANSLATE_DEBUG_MASK);
220: const int TRANSLATE_WRITE_DEBUG = (TRANSLATE_WRITE | TRANSLATE_DEBUG_MASK);
221: const int TRANSLATE_FETCH_DEBUG = (TRANSLATE_FETCH | TRANSLATE_DEBUG_MASK);
1.1 root 222:
1.1.1.10 root 223: /*****************************************************************************/
224: /* src/emu/emucore.h */
1.1 root 225:
1.1.1.10 root 226: // constants for expression endianness
227: enum endianness_t
228: {
229: ENDIANNESS_LITTLE,
230: ENDIANNESS_BIG
231: };
1.1 root 232:
1.1.1.10 root 233: // declare native endianness to be one or the other
234: #ifdef LSB_FIRST
235: const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_LITTLE;
236: #else
237: const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_BIG;
238: #endif
239:
240: // endian-based value: first value is if 'endian' is little-endian, second is if 'endian' is big-endian
241: #define ENDIAN_VALUE_LE_BE(endian,leval,beval) (((endian) == ENDIANNESS_LITTLE) ? (leval) : (beval))
242:
243: // endian-based value: first value is if native endianness is little-endian, second is if native is big-endian
244: #define NATIVE_ENDIAN_VALUE_LE_BE(leval,beval) ENDIAN_VALUE_LE_BE(ENDIANNESS_NATIVE, leval, beval)
245:
246: // endian-based value: first value is if 'endian' matches native, second is if 'endian' doesn't match native
247: #define ENDIAN_VALUE_NE_NNE(endian,leval,beval) (((endian) == ENDIANNESS_NATIVE) ? (neval) : (nneval))
1.1 root 248:
249: /*****************************************************************************/
250: /* src/emu/memory.h */
251:
1.1.1.10 root 252: // address spaces
253: enum address_spacenum
254: {
255: AS_0, // first address space
256: AS_1, // second address space
257: AS_2, // third address space
258: AS_3, // fourth address space
259: ADDRESS_SPACES, // maximum number of address spaces
260:
261: // alternate address space names for common use
262: AS_PROGRAM = AS_0, // program address space
263: AS_DATA = AS_1, // data address space
264: AS_IO = AS_2 // I/O address space
265: };
266:
1.1 root 267: // offsets and addresses are 32-bit (for now...)
268: typedef UINT32 offs_t;
269:
270: // read accessors
271: UINT8 read_byte(offs_t byteaddress)
272: {
1.1.1.4 root 273: #if defined(HAS_I386)
1.1 root 274: if(byteaddress < MAX_MEM) {
275: return mem[byteaddress];
1.1.1.3 root 276: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
277: // return read_byte(byteaddress & 0xfffff);
1.1 root 278: }
279: return 0;
1.1.1.4 root 280: #else
281: return mem[byteaddress];
282: #endif
1.1 root 283: }
284:
285: UINT16 read_word(offs_t byteaddress)
286: {
1.1.1.14 root 287: if(byteaddress == 0x41c) {
288: // pointer to first free slot in keyboard buffer
289: // XXX: the buffer itself doesn't actually exist in DOS memory
290: if(key_buf_char->count() == 0) {
291: maybe_idle();
292: }
293: return (UINT16)key_buf_char->count();
294: }
1.1.1.4 root 295: #if defined(HAS_I386)
1.1 root 296: if(byteaddress < MAX_MEM - 1) {
297: return *(UINT16 *)(mem + byteaddress);
1.1.1.3 root 298: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
299: // return read_word(byteaddress & 0xfffff);
1.1 root 300: }
301: return 0;
1.1.1.4 root 302: #else
303: return *(UINT16 *)(mem + byteaddress);
304: #endif
1.1 root 305: }
306:
307: UINT32 read_dword(offs_t byteaddress)
308: {
1.1.1.4 root 309: #if defined(HAS_I386)
1.1 root 310: if(byteaddress < MAX_MEM - 3) {
311: return *(UINT32 *)(mem + byteaddress);
1.1.1.3 root 312: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
313: // return read_dword(byteaddress & 0xfffff);
1.1 root 314: }
315: return 0;
1.1.1.4 root 316: #else
317: return *(UINT32 *)(mem + byteaddress);
318: #endif
1.1 root 319: }
320:
321: // write accessors
1.1.1.14 root 322: #ifdef USE_THREAD
323: void vram_flush_char()
324: {
325: if(vram_length_char != 0) {
326: DWORD num;
327: WriteConsoleOutputCharacter(hStdout, scr_char, vram_length_char, vram_coord_char, &num);
328: vram_length_char = vram_last_length_char = 0;
329: }
330: }
331:
332: void vram_flush_attr()
333: {
334: if(vram_length_attr != 0) {
335: DWORD num;
336: WriteConsoleOutputAttribute(hStdout, scr_attr, vram_length_attr, vram_coord_attr, &num);
337: vram_length_attr = vram_last_length_attr = 0;
338: }
339: }
340:
341: void vram_flush()
342: {
343: if(vram_length_char != 0 || vram_length_attr != 0) {
344: EnterCriticalSection(&vram_crit_sect);
345: vram_flush_char();
346: vram_flush_attr();
347: LeaveCriticalSection(&vram_crit_sect);
348: }
349: }
350: #endif
351:
352: void write_text_vram_char(offs_t offset, UINT8 data)
1.1.1.8 root 353: {
1.1.1.14 root 354: #ifdef USE_THREAD
355: static offs_t first_offset_char, last_offset_char;
356:
357: if(vram_length_char != 0) {
358: if(offset <= last_offset_char && offset >= first_offset_char) {
359: scr_char[(offset - first_offset_char) >> 1] = data;
360: return;
361: }
362: if(offset != last_offset_char + 2) {
363: vram_flush_char();
364: }
365: }
366: if(vram_length_char == 0) {
367: first_offset_char = offset;
368: vram_coord_char.X = (offset >> 1) % scr_width;
369: vram_coord_char.Y = (offset >> 1) / scr_width + scr_top;
370: }
371: scr_char[vram_length_char++] = data;
372: last_offset_char = offset;
373: #else
1.1.1.8 root 374: COORD co;
375: DWORD num;
376:
1.1.1.14 root 377: co.X = (offset >> 1) % scr_width;
378: co.Y = (offset >> 1) / scr_width;
379: scr_char[0] = data;
380: WriteConsoleOutputCharacter(hStdout, scr_char, 1, co, &num);
381: #endif
382: }
383:
384: void write_text_vram_attr(offs_t offset, UINT8 data)
385: {
386: #ifdef USE_THREAD
387: static offs_t first_offset_attr, last_offset_attr;
388:
389: if(vram_length_attr != 0) {
390: if(offset <= last_offset_attr && offset >= first_offset_attr) {
391: scr_attr[(offset - first_offset_attr) >> 1] = data;
392: return;
393: }
394: if(offset != last_offset_attr + 2) {
395: vram_flush_attr();
396: }
397: }
398: if(vram_length_attr == 0) {
399: first_offset_attr = offset;
400: vram_coord_attr.X = (offset >> 1) % scr_width;
401: vram_coord_attr.Y = (offset >> 1) / scr_width + scr_top;
402: }
403: scr_attr[vram_length_attr++] = data;
404: last_offset_attr = offset;
405: #else
406: COORD co;
407: DWORD num;
1.1.1.8 root 408:
1.1.1.14 root 409: co.X = (offset >> 1) % scr_width;
410: co.Y = (offset >> 1) / scr_width;
411: scr_attr[0] = data;
412: WriteConsoleOutputAttribute(hStdout, scr_attr, 1, co, &num);
413: #endif
414: }
415:
416: void write_text_vram_byte(offs_t offset, UINT8 data)
417: {
418: EnterCriticalSection(&vram_crit_sect);
1.1.1.8 root 419: if(offset & 1) {
1.1.1.14 root 420: write_text_vram_attr(offset, data);
1.1.1.8 root 421: } else {
1.1.1.14 root 422: write_text_vram_char(offset, data);
1.1.1.8 root 423: }
1.1.1.14 root 424: LeaveCriticalSection(&vram_crit_sect);
1.1.1.8 root 425: }
426:
427: void write_text_vram_word(offs_t offset, UINT16 data)
428: {
1.1.1.14 root 429: EnterCriticalSection(&vram_crit_sect);
1.1.1.8 root 430: if(offset & 1) {
1.1.1.14 root 431: write_text_vram_attr(offset , (data ) & 0xff);
432: write_text_vram_char(offset + 1, (data >> 8) & 0xff);
1.1.1.8 root 433: } else {
1.1.1.14 root 434: write_text_vram_char(offset , (data ) & 0xff);
435: write_text_vram_attr(offset + 1, (data >> 8) & 0xff);
1.1.1.8 root 436: }
1.1.1.14 root 437: LeaveCriticalSection(&vram_crit_sect);
1.1.1.8 root 438: }
439:
440: void write_text_vram_dword(offs_t offset, UINT32 data)
441: {
1.1.1.14 root 442: EnterCriticalSection(&vram_crit_sect);
1.1.1.8 root 443: if(offset & 1) {
1.1.1.14 root 444: write_text_vram_attr(offset , (data ) & 0xff);
445: write_text_vram_char(offset + 1, (data >> 8) & 0xff);
446: write_text_vram_attr(offset + 2, (data >> 16) & 0xff);
447: write_text_vram_char(offset + 3, (data >> 24) & 0xff);
448: } else {
449: write_text_vram_char(offset , (data ) & 0xff);
450: write_text_vram_attr(offset + 1, (data >> 8) & 0xff);
451: write_text_vram_char(offset + 2, (data >> 16) & 0xff);
452: write_text_vram_attr(offset + 3, (data >> 24) & 0xff);
1.1.1.8 root 453: }
1.1.1.14 root 454: LeaveCriticalSection(&vram_crit_sect);
1.1.1.8 root 455: }
456:
1.1 root 457: void write_byte(offs_t byteaddress, UINT8 data)
458: {
1.1.1.8 root 459: if(byteaddress < MEMORY_END) {
1.1.1.3 root 460: mem[byteaddress] = data;
1.1.1.8 root 461: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 462: if(!restore_console_on_exit) {
463: change_console_size(scr_width, scr_height);
1.1.1.12 root 464: }
1.1.1.8 root 465: write_text_vram_byte(byteaddress - text_vram_top_address, data);
466: mem[byteaddress] = data;
467: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
468: if(int_10h_feh_called && !int_10h_ffh_called) {
469: write_text_vram_byte(byteaddress - shadow_buffer_top_address, data);
1.1 root 470: }
471: mem[byteaddress] = data;
1.1.1.4 root 472: #if defined(HAS_I386)
1.1.1.3 root 473: } else if(byteaddress < MAX_MEM) {
1.1.1.4 root 474: #else
475: } else {
476: #endif
1.1.1.3 root 477: mem[byteaddress] = data;
1.1 root 478: }
479: }
480:
481: void write_word(offs_t byteaddress, UINT16 data)
482: {
1.1.1.8 root 483: if(byteaddress < MEMORY_END) {
1.1.1.14 root 484: if(byteaddress == 0x450 + mem[0x462] * 2) {
485: COORD co;
486: co.X = data & 0xff;
487: co.Y = (data >> 8) + scr_top;
488: SetConsoleCursorPosition(hStdout, co);
489: }
1.1.1.3 root 490: *(UINT16 *)(mem + byteaddress) = data;
1.1.1.8 root 491: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 492: if(!restore_console_on_exit) {
493: change_console_size(scr_width, scr_height);
1.1.1.12 root 494: }
1.1.1.8 root 495: write_text_vram_word(byteaddress - text_vram_top_address, data);
496: *(UINT16 *)(mem + byteaddress) = data;
497: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
498: if(int_10h_feh_called && !int_10h_ffh_called) {
499: write_text_vram_word(byteaddress - shadow_buffer_top_address, data);
1.1 root 500: }
501: *(UINT16 *)(mem + byteaddress) = data;
1.1.1.4 root 502: #if defined(HAS_I386)
1.1.1.3 root 503: } else if(byteaddress < MAX_MEM - 1) {
1.1.1.4 root 504: #else
505: } else {
506: #endif
1.1.1.3 root 507: *(UINT16 *)(mem + byteaddress) = data;
1.1 root 508: }
509: }
510:
511: void write_dword(offs_t byteaddress, UINT32 data)
512: {
1.1.1.8 root 513: if(byteaddress < MEMORY_END) {
1.1.1.3 root 514: *(UINT32 *)(mem + byteaddress) = data;
1.1.1.8 root 515: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 516: if(!restore_console_on_exit) {
517: change_console_size(scr_width, scr_height);
1.1.1.12 root 518: }
1.1.1.8 root 519: write_text_vram_dword(byteaddress - text_vram_top_address, data);
520: *(UINT32 *)(mem + byteaddress) = data;
521: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
522: if(int_10h_feh_called && !int_10h_ffh_called) {
523: write_text_vram_dword(byteaddress - shadow_buffer_top_address, data);
1.1 root 524: }
525: *(UINT32 *)(mem + byteaddress) = data;
1.1.1.4 root 526: #if defined(HAS_I386)
1.1.1.3 root 527: } else if(byteaddress < MAX_MEM - 3) {
1.1.1.4 root 528: #else
529: } else {
530: #endif
1.1.1.3 root 531: *(UINT32 *)(mem + byteaddress) = data;
1.1 root 532: }
533: }
534:
535: #define read_decrypted_byte read_byte
536: #define read_decrypted_word read_word
537: #define read_decrypted_dword read_dword
538:
1.1.1.3 root 539: #define read_raw_byte read_byte
540: #define write_raw_byte write_byte
541:
542: #define read_word_unaligned read_word
543: #define write_word_unaligned write_word
544:
545: #define read_io_word_unaligned read_io_word
546: #define write_io_word_unaligned write_io_word
547:
1.1 root 548: UINT8 read_io_byte(offs_t byteaddress);
549: UINT16 read_io_word(offs_t byteaddress);
550: UINT32 read_io_dword(offs_t byteaddress);
551:
552: void write_io_byte(offs_t byteaddress, UINT8 data);
553: void write_io_word(offs_t byteaddress, UINT16 data);
554: void write_io_dword(offs_t byteaddress, UINT32 data);
555:
556: /*****************************************************************************/
557: /* src/osd/osdcomm.h */
558:
559: /* Highly useful macro for compile-time knowledge of an array size */
560: #define ARRAY_LENGTH(x) (sizeof(x) / sizeof(x[0]))
561:
1.1.1.3 root 562: #if defined(HAS_I386)
1.1.1.10 root 563: static CPU_TRANSLATE(i386);
564: #include "mame/lib/softfloat/softfloat.c"
565: #include "mame/emu/cpu/i386/i386.c"
1.1.1.12 root 566: #include "mame/emu/cpu/vtlb.c"
1.1.1.3 root 567: #elif defined(HAS_I286)
1.1.1.10 root 568: #include "mame/emu/cpu/i86/i286.c"
1.1.1.3 root 569: #else
1.1.1.10 root 570: #include "mame/emu/cpu/i86/i86.c"
1.1.1.3 root 571: #endif
1.1.1.22! root 572: #ifdef ENABLE_DEBUG_DASM
1.1.1.10 root 573: #include "mame/emu/cpu/i386/i386dasm.c"
1.1.1.22! root 574: int dasm = 0;
1.1 root 575: #endif
576:
1.1.1.3 root 577: #if defined(HAS_I386)
578: #define SREG(x) m_sreg[x].selector
579: #define SREG_BASE(x) m_sreg[x].base
580:
581: int cpu_type, cpu_step;
582: #else
583: #define REG8(x) m_regs.b[x]
584: #define REG16(x) m_regs.w[x]
585: #define SREG(x) m_sregs[x]
586: #define SREG_BASE(x) m_base[x]
587: #define m_CF m_CarryVal
588: #define m_a20_mask AMASK
589: #define i386_load_segment_descriptor(x) m_base[x] = SegBase(x)
590: #if defined(HAS_I286)
591: #define i386_set_a20_line(x) i80286_set_a20_line(x)
592: #else
593: #define i386_set_a20_line(x)
594: #endif
595: #define i386_set_irq_line(x, y) set_irq_line(x, y)
596: #endif
1.1 root 597:
598: void i386_jmp_far(UINT16 selector, UINT32 address)
599: {
1.1.1.3 root 600: #if defined(HAS_I386)
1.1 root 601: if(PROTECTED_MODE && !V8086_MODE) {
1.1.1.3 root 602: i386_protected_mode_jump(selector, address, 1, m_operand_size);
1.1 root 603: } else {
1.1.1.3 root 604: SREG(CS) = selector;
605: m_performed_intersegment_jump = 1;
606: i386_load_segment_descriptor(CS);
607: m_eip = address;
608: CHANGE_PC(m_eip);
1.1 root 609: }
1.1.1.3 root 610: #elif defined(HAS_I286)
611: i80286_code_descriptor(selector, address, 1);
612: #else
613: SREG(CS) = selector;
614: i386_load_segment_descriptor(CS);
615: m_pc = (SREG_BASE(CS) + address) & m_a20_mask;
616: #endif
1.1 root 617: }
618:
619: /* ----------------------------------------------------------------------------
620: main
621: ---------------------------------------------------------------------------- */
622:
1.1.1.10 root 623: bool is_started_from_command_prompt()
624: {
1.1.1.18 root 625: bool ret = false;
626:
627: HMODULE hLibrary = LoadLibrary(_T("Kernel32.dll"));
628: if(hLibrary) {
629: typedef DWORD (WINAPI *GetConsoleProcessListFunction)(__out LPDWORD lpdwProcessList, __in DWORD dwProcessCount);
630: GetConsoleProcessListFunction lpfnGetConsoleProcessList;
631: lpfnGetConsoleProcessList = reinterpret_cast<GetConsoleProcessListFunction>(::GetProcAddress(hLibrary, "GetConsoleProcessList"));
632: if(lpfnGetConsoleProcessList) {
633: DWORD pl;
634: ret = (lpfnGetConsoleProcessList(&pl, 1) > 1);
635: FreeLibrary(hLibrary);
636: return(ret);
637: }
638: FreeLibrary(hLibrary);
639: }
640:
641: HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
642: if(hSnapshot != INVALID_HANDLE_VALUE) {
643: DWORD dwParentProcessID = 0;
644: PROCESSENTRY32 pe32;
645: pe32.dwSize = sizeof(PROCESSENTRY32);
646: if(Process32First(hSnapshot, &pe32)) {
647: do {
648: if(pe32.th32ProcessID == GetCurrentProcessId()) {
649: dwParentProcessID = pe32.th32ParentProcessID;
650: break;
651: }
652: } while(Process32Next(hSnapshot, &pe32));
653: }
654: CloseHandle(hSnapshot);
655: if(dwParentProcessID != 0) {
656: HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwParentProcessID);
657: if(hProcess != NULL) {
658: HMODULE hMod;
659: DWORD cbNeeded;
660: if(EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) {
661: char module_name[MAX_PATH];
662: if(GetModuleBaseName(hProcess, hMod, module_name, sizeof(module_name))) {
663: ret = (_strnicmp(module_name, "cmd.exe", 7) == 0);
664: }
665: }
666: CloseHandle(hProcess);
667: }
668: }
669: }
670: return(ret);
1.1.1.14 root 671: }
672:
673: BOOL is_greater_windows_version(DWORD dwMajorVersion, DWORD dwMinorVersion, WORD wServicePackMajor, WORD wServicePackMinor)
674: {
675: //https://msdn.microsoft.com/en-us/library/windows/desktop/ms725491(v=vs.85).aspx
676: OSVERSIONINFOEX osvi;
677: DWORDLONG dwlConditionMask = 0;
678: int op = VER_GREATER_EQUAL;
679:
680: // Initialize the OSVERSIONINFOEX structure.
681: ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
682: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
683: osvi.dwMajorVersion = dwMajorVersion;
684: osvi.dwMinorVersion = dwMinorVersion;
685: osvi.wServicePackMajor = wServicePackMajor;
686: osvi.wServicePackMinor = wServicePackMinor;
687:
688: // Initialize the condition mask.
689: VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, op );
690: VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, op );
691: VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMAJOR, op );
692: VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMINOR, op );
693:
694: // Perform the test.
695: return VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, dwlConditionMask);
696: }
697:
698: BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
699: {
700: if(dwCtrlType == CTRL_BREAK_EVENT || dwCtrlType == CTRL_C_EVENT) {
701: m_halted = 1;
702: return TRUE;
703: }
704: return FALSE;
705: }
706:
707: #ifdef USE_THREAD
708: DWORD WINAPI vram_thread(LPVOID)
709: {
710: while(!m_halted) {
711: EnterCriticalSection(&vram_crit_sect);
712: if(vram_length_char != 0 && vram_length_char == vram_last_length_char) {
713: vram_flush_char();
714: }
715: if(vram_length_attr != 0 && vram_length_attr == vram_last_length_attr) {
716: vram_flush_attr();
717: }
718: vram_last_length_char = vram_length_char;
719: vram_last_length_attr = vram_length_attr;
720: LeaveCriticalSection(&vram_crit_sect);
721: // this is about half the maximum keyboard repeat rate - any
722: // lower tends to be jerky, any higher misses updates
723: Sleep(15);
1.1.1.10 root 724: }
1.1.1.14 root 725: return 0;
1.1.1.10 root 726: }
1.1.1.14 root 727: #endif
1.1.1.10 root 728:
1.1.1.9 root 729: #define IS_NUMERIC(c) ((c) >= '0' && (c) <= '9')
730:
1.1 root 731: int main(int argc, char *argv[], char *envp[])
732: {
1.1.1.9 root 733: int arg_offset = 0;
734: int standard_env = 0;
1.1.1.14 root 735: int buf_width = 0, buf_height = 0;
1.1.1.15 root 736: BOOL bSuccess, bChangeScreenSize = FALSE;
1.1 root 737:
1.1.1.9 root 738: for(int i = 1; i < argc; i++) {
739: if(_strnicmp(argv[i], "-e", 2) == 0) {
740: standard_env = 1;
741: arg_offset++;
1.1.1.14 root 742: } else if(_strnicmp(argv[i], "-i", 2) == 0) {
743: ignore_illegal_insn = true;
744: arg_offset++;
745: } else if(_strnicmp(argv[i], "-m", 2) == 0) {
746: limit_max_memory = true;
747: arg_offset++;
748: } else if(_strnicmp(argv[i], "-d", 2) == 0) {
749: no_windows = true;
750: arg_offset++;
751: } else if(_strnicmp(argv[i], "-b", 2) == 0) {
752: stay_busy = true;
753: arg_offset++;
1.1.1.19 root 754: } else if(_strnicmp(argv[i], "-x", 2) == 0) {
755: UMB_TOP = EMS_TOP + EMS_SIZE;
756: support_ems = true;
757: #ifdef SUPPORT_XMS
758: support_xms = true;
759: #endif
760: arg_offset++;
1.1.1.14 root 761: } else if(_strnicmp(argv[i], "-n", 2) == 0) {
1.1.1.17 root 762: if(sscanf(argv[1] + 2, "%d,%d", &buf_height, &buf_width) != 2) {
763: buf_width = buf_height = 0;
764: }
765: if(buf_width <= 0 || buf_width > 0x7fff) {
766: buf_width = 80;
767: }
768: if(buf_height <= 0 || buf_height > 0x7fff) {
769: buf_height = 25;
770: }
1.1.1.14 root 771: arg_offset++;
1.1.1.9 root 772: } else if(_strnicmp(argv[i], "-v", 2) == 0) {
1.1.1.17 root 773: 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.9 root 774: major_version = argv[i][2] - '0';
1.1.1.17 root 775: minor_version = (argv[i][4] - '0') * 10 + (argv[i][5] ? (argv[i][5] - '0') : 0);
1.1.1.9 root 776: }
777: arg_offset++;
778: } else {
779: break;
780: }
781: }
782:
783: if(argc < 2 + arg_offset) {
1.1 root 784: #ifdef _WIN64
1.1.1.14 root 785: fprintf(stderr, "MS-DOS Player (" CPU_MODEL_NAME(CPU_MODEL) ") for Win32-x64 console\n\n");
1.1 root 786: #else
1.1.1.14 root 787: fprintf(stderr, "MS-DOS Player (" CPU_MODEL_NAME(CPU_MODEL) ") for Win32 console\n\n");
1.1 root 788: #endif
1.1.1.19 root 789: fprintf(stderr, "Usage: MSDOS [-b] [-d] [-e] [-i] [-m] [-n[L[,C]]] [-vX.XX] [-x] (command file) [options]\n"
1.1.1.14 root 790: "\n"
791: "\t-b\tstay busy during keyboard polling\n"
792: "\t-d\tpretend running under straight DOS, not Windows\n"
793: "\t-e\tuse a reduced environment block\n"
794: "\t-i\tignore invalid instructions\n"
795: "\t-m\trestrict free memory to 0x7FFF paragraphs\n"
796: "\t-n\tcreate a new buffer (25 lines, 80 columns by default)\n"
1.1.1.19 root 797: "\t-v\tset the DOS version\n"
798: #ifdef SUPPORT_XMS
799: "\t-x\tenable XMS/EMS\n"
800: #else
801: "\t-x\tenable EMS\n"
802: #endif
803: );
1.1.1.10 root 804:
805: if(!is_started_from_command_prompt()) {
806: fprintf(stderr, "\nStart this program from a command prompt!\n\nHit any key to quit...");
807: while(!_kbhit()) {
808: Sleep(10);
809: }
810: }
1.1.1.20 root 811: #ifdef _DEBUG
812: _CrtDumpMemoryLeaks();
813: #endif
1.1 root 814: return(EXIT_FAILURE);
815: }
816:
1.1.1.14 root 817: is_vista_or_later = is_greater_windows_version(6, 0, 0, 0);
818:
1.1 root 819: CONSOLE_SCREEN_BUFFER_INFO csbi;
1.1.1.14 root 820: CONSOLE_CURSOR_INFO ci;
1.1 root 821: hStdin = GetStdHandle(STD_INPUT_HANDLE);
822: hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.12 root 823: bSuccess = GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 824: GetConsoleCursorInfo(hStdout, &ci);
1.1 root 825:
1.1.1.14 root 826: for(int y = 0; y < SCR_BUF_WIDTH; y++) {
827: for(int x = 0; x < SCR_BUF_HEIGHT; x++) {
828: SCR_BUF(y,x).Char.AsciiChar = ' ';
829: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
1.1 root 830: }
831: }
1.1.1.12 root 832: if(bSuccess) {
833: scr_width = csbi.dwSize.X;
1.1.1.14 root 834: scr_height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
835:
836: // v-text shadow buffer size is 0x7ff0
837: if((scr_width > SCR_BUF_WIDTH) || (scr_height > SCR_BUF_HEIGHT) || (scr_width * scr_height * 2 > 0x7ff0) ||
838: (buf_width != 0 && buf_width != scr_width) || (buf_height != 0 && buf_height != scr_height)) {
839: scr_width = min(buf_width != 0 ? buf_width : scr_width, SCR_BUF_WIDTH);
840: scr_height = min(buf_height != 0 ? buf_height : scr_height, SCR_BUF_HEIGHT);
841: if(scr_width * scr_height * 2 > 0x7ff0) {
842: scr_width = 80;
843: scr_height = 25;
844: }
1.1.1.15 root 845: bChangeScreenSize = TRUE;
1.1.1.14 root 846: }
1.1.1.12 root 847: } else {
848: // for a proof (not a console)
849: scr_width = 80;
850: scr_height = 25;
851: }
1.1.1.14 root 852: scr_buf_size.X = scr_width;
853: scr_buf_size.Y = scr_height;
854: scr_buf_pos.X = scr_buf_pos.Y = 0;
855: scr_top = csbi.srWindow.Top;
1.1 root 856: cursor_moved = false;
857:
858: key_buf_char = new FIFO();
859: key_buf_scan = new FIFO();
860:
861: hardware_init();
862:
1.1.1.9 root 863: if(msdos_init(argc - (arg_offset + 1), argv + (arg_offset + 1), envp, standard_env)) {
1.1 root 864: retval = EXIT_FAILURE;
865: } else {
1.1.1.15 root 866: if(bChangeScreenSize) {
867: change_console_size(scr_width, scr_height);
868: }
1.1.1.14 root 869: #if defined(_MSC_VER) && _MSC_VER >= 1400
870: _set_invalid_parameter_handler((_invalid_parameter_handler)ignore_invalid_parameters);
871: #endif
872: SetConsoleCtrlHandler(ctrl_handler, TRUE);
873:
1.1.1.8 root 874: TIMECAPS caps;
875: timeGetDevCaps(&caps, sizeof(TIMECAPS));
876: timeBeginPeriod(caps.wPeriodMin);
1.1.1.14 root 877:
878: #ifdef USE_THREAD
879: InitializeCriticalSection(&vram_crit_sect);
880: CloseHandle(CreateThread(NULL, 4096, vram_thread, NULL, 0, NULL));
881: #endif
1.1 root 882: hardware_run();
1.1.1.14 root 883: #ifdef USE_THREAD
884: vram_flush();
885: DeleteCriticalSection(&vram_crit_sect);
886: #endif
887:
1.1.1.12 root 888: if(bSuccess) {
889: if(restore_console_on_exit) {
1.1.1.14 root 890: // window can't be bigger than buffer,
891: // buffer can't be smaller than window,
892: // so make a tiny window,
893: // set the required buffer,
894: // then set the required window
895: SMALL_RECT rect;
896: SET_RECT(rect, 0, csbi.srWindow.Top, 0, csbi.srWindow.Top);
897: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1.1.1.12 root 898: SetConsoleScreenBufferSize(hStdout, csbi.dwSize);
1.1.1.14 root 899: SET_RECT(rect, 0, 0, csbi.srWindow.Right - csbi.srWindow.Left, csbi.srWindow.Bottom - csbi.srWindow.Top);
1.1.1.12 root 900: SetConsoleWindowInfo(hStdout, TRUE, &rect);
901: }
1.1.1.14 root 902: // hStdout (and all handles) will close in msdos_finish()...
903: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
904: SetConsoleCursorInfo(hStdout, &ci);
1.1.1.12 root 905: }
1.1 root 906: msdos_finish();
1.1.1.14 root 907:
1.1.1.8 root 908: timeEndPeriod(caps.wPeriodMin);
1.1.1.14 root 909: SetConsoleCtrlHandler(ctrl_handler, FALSE);
1.1 root 910: }
911:
1.1.1.10 root 912: hardware_finish();
913:
1.1 root 914: delete key_buf_char;
915: delete key_buf_scan;
916:
1.1.1.12 root 917: // SetConsoleTextAttribute(hStdout, csbi.wAttributes);
1.1 root 918:
1.1.1.20 root 919: #ifdef _DEBUG
920: _CrtDumpMemoryLeaks();
921: #endif
1.1 root 922: return(retval);
923: }
924:
1.1.1.20 root 925: /* ----------------------------------------------------------------------------
926: console
927: ---------------------------------------------------------------------------- */
928:
1.1.1.14 root 929: void change_console_size(int width, int height)
1.1.1.12 root 930: {
931: CONSOLE_SCREEN_BUFFER_INFO csbi;
932: SMALL_RECT rect;
933: COORD co;
934:
935: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 936: if(csbi.srWindow.Top != 0 || csbi.dwCursorPosition.Y > height - 1) {
937: if(csbi.srWindow.Right - csbi.srWindow.Left + 1 == width && csbi.srWindow.Bottom - csbi.srWindow.Top + 1 == height) {
938: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &csbi.srWindow);
939: SET_RECT(rect, 0, 0, width - 1, height - 1);
940: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
941: } else if(csbi.dwCursorPosition.Y > height - 1) {
942: SET_RECT(rect, 0, csbi.dwCursorPosition.Y - (height - 1), width - 1, csbi.dwCursorPosition.Y);
943: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
944: SET_RECT(rect, 0, 0, width - 1, height - 1);
945: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1.1.12 root 946: }
947: }
1.1.1.14 root 948: if(csbi.dwCursorPosition.Y > height - 1) {
1.1.1.12 root 949: co.X = csbi.dwCursorPosition.X;
1.1.1.14 root 950: co.Y = min(height - 1, csbi.dwCursorPosition.Y - csbi.srWindow.Top);
1.1.1.12 root 951: SetConsoleCursorPosition(hStdout, co);
952: cursor_moved = true;
953: }
1.1.1.14 root 954:
955: // window can't be bigger than buffer,
956: // buffer can't be smaller than window,
957: // so make a tiny window,
958: // set the required buffer,
959: // then set the required window
960: SET_RECT(rect, 0, csbi.srWindow.Top, 0, csbi.srWindow.Top);
1.1.1.12 root 961: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1.1.1.14 root 962: co.X = width;
963: co.Y = height;
1.1.1.12 root 964: SetConsoleScreenBufferSize(hStdout, co);
1.1.1.14 root 965: SET_RECT(rect, 0, 0, width - 1, height - 1);
966: SetConsoleWindowInfo(hStdout, TRUE, &rect);
967:
968: scr_width = scr_buf_size.X = width;
969: scr_height = scr_buf_size.Y = height;
970: scr_top = 0;
971:
972: clear_scr_buffer(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
973:
974: int regen = min(scr_width * scr_height * 2, 0x8000);
1.1.1.15 root 975: text_vram_end_address = text_vram_top_address + regen;
976: shadow_buffer_end_address = shadow_buffer_top_address + regen;
977:
1.1.1.14 root 978: if(regen > 0x4000) {
979: regen = 0x8000;
980: vram_pages = 1;
981: } else if(regen > 0x2000) {
982: regen = 0x4000;
983: vram_pages = 2;
984: } else if(regen > 0x1000) {
985: regen = 0x2000;
986: vram_pages = 4;
987: } else {
988: regen = 0x1000;
989: vram_pages = 8;
990: }
1.1.1.15 root 991: *(UINT16 *)(mem + 0x44a) = scr_width;
992: *(UINT16 *)(mem + 0x44c) = regen;
993: *(UINT8 *)(mem + 0x484) = scr_height - 1;
994:
995: restore_console_on_exit = true;
1.1.1.14 root 996: }
997:
998: void clear_scr_buffer(WORD attr)
999: {
1000: for(int y = 0; y < scr_height; y++) {
1001: for(int x = 0; x < scr_width; x++) {
1002: SCR_BUF(y,x).Char.AsciiChar = ' ';
1003: SCR_BUF(y,x).Attributes = attr;
1004: }
1005: }
1.1.1.12 root 1006: }
1007:
1.1.1.14 root 1008: bool update_key_buffer_tmp()
1.1 root 1009: {
1.1.1.8 root 1010: DWORD dwNumberOfEvents = 0;
1.1 root 1011: DWORD dwRead;
1012: INPUT_RECORD ir[16];
1013:
1.1.1.8 root 1014: if(GetNumberOfConsoleInputEvents(hStdin, &dwNumberOfEvents) && dwNumberOfEvents != 0) {
1015: if(ReadConsoleInputA(hStdin, ir, 16, &dwRead)) {
1016: for(int i = 0; i < dwRead; i++) {
1017: if((ir[i].EventType & KEY_EVENT) && ir[i].Event.KeyEvent.bKeyDown) {
1.1.1.14 root 1018: UINT8 chr = ir[i].Event.KeyEvent.uChar.AsciiChar;
1019: UINT8 scn = ir[i].Event.KeyEvent.wVirtualScanCode & 0xff;
1020: if(chr == 0) {
1021: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
1022: if(scn >= 0x3b && scn <= 0x44) {
1023: scn += 0x68 - 0x3b; // F1 to F10
1024: } else if(scn == 0x57 || scn == 0x58) {
1025: scn += 0x8b - 0x57; // F11 & F12
1026: } else if(scn >= 0x47 && scn <= 0x53) {
1027: scn += 0x97 - 0x47; // edit/arrow clusters
1028: } else if(scn == 0x35) {
1029: scn = 0xa4; // keypad /
1030: }
1031: } else if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
1032: if(scn == 0x07) {
1033: chr = 0x1e; // Ctrl+^
1034: } else if(scn == 0x0c) {
1035: chr = 0x1f; // Ctrl+_
1036: } else if(scn >= 0x35 && scn <= 0x58) {
1037: static const UINT8 ctrl_map[] = {
1038: 0x95, // keypad /
1039: 0,
1040: 0x96, // keypad *
1041: 0, 0, 0,
1042: 0x5e, // F1
1043: 0x5f, // F2
1044: 0x60, // F3
1045: 0x61, // F4
1046: 0x62, // F5
1047: 0x63, // F6
1048: 0x64, // F7
1049: 0x65, // F8
1050: 0x66, // F9
1051: 0x67, // F10
1052: 0,
1053: 0,
1054: 0x77, // Home
1055: 0x8d, // Up
1056: 0x84, // PgUp
1057: 0x8e, // keypad -
1058: 0x73, // Left
1059: 0x8f, // keypad center
1060: 0x74, // Right
1061: 0x90, // keyapd +
1062: 0x75, // End
1063: 0x91, // Down
1064: 0x76, // PgDn
1065: 0x92, // Insert
1066: 0x93, // Delete
1067: 0, 0, 0,
1068: 0x89, // F11
1069: 0x8a, // F12
1070: };
1071: scn = ctrl_map[scn - 0x35];
1072: }
1073: } else if(ir[i].Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
1074: if(scn >= 0x3b && scn <= 0x44) {
1075: scn += 0x54 - 0x3b; // F1 to F10
1076: } else if(scn == 0x57 || scn == 0x58) {
1077: scn += 0x87 - 0x57; // F11 & F12
1078: }
1079: } else if(scn == 0x57 || scn == 0x58) {
1080: scn += 0x85 - 0x57;
1081: }
1082: // ignore shift, ctrl, alt, win and menu keys
1083: if(scn != 0x1d && scn != 0x2a && scn != 0x36 && scn != 0x38 && (scn < 0x5b || scn > 0x5e)) {
1084: if(chr == 0) {
1085: key_buf_char->write(0x00);
1086: key_buf_scan->write(ir[i].Event.KeyEvent.dwControlKeyState & ENHANCED_KEY ? 0xe0 : 0x00);
1087: }
1088: key_buf_char->write(chr);
1089: key_buf_scan->write(scn);
1.1.1.8 root 1090: }
1091: } else {
1.1.1.14 root 1092: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
1093: chr = 0;
1094: if(scn >= 0x02 && scn <= 0x0e) {
1095: scn += 0x78 - 0x02; // 1 to 0 - =
1096: }
1097: }
1098: key_buf_char->write(chr);
1099: key_buf_scan->write(scn);
1100: }
1101: }
1102: }
1103: for(int i = dwRead; --i >= 0;) {
1104: if((ir[i].EventType & KEY_EVENT)) {
1105: kbd_data = ir[i].Event.KeyEvent.wVirtualScanCode & 0x7f;
1106: if(!ir[i].Event.KeyEvent.bKeyDown) {
1107: kbd_data |= 0x80;
1.1 root 1108: }
1.1.1.14 root 1109: return true;
1.1 root 1110: }
1111: }
1112: }
1113: }
1.1.1.14 root 1114: return false;
1.1.1.8 root 1115: }
1116:
1.1.1.14 root 1117: bool update_key_buffer()
1.1.1.8 root 1118: {
1119: int prev_count = key_buf_char->count();
1.1.1.14 root 1120: bool input = update_key_buffer_tmp();
1.1.1.8 root 1121: key_input += key_buf_char->count() - prev_count;
1.1.1.14 root 1122: return(input || key_buf_char->count() != 0);
1.1 root 1123: }
1124:
1.1.1.8 root 1125: int check_key_input()
1126: {
1127: if(key_input == 0) {
1128: int prev_count = key_buf_char->count();
1.1.1.14 root 1129: bool input = update_key_buffer_tmp();
1.1.1.8 root 1130: key_input = key_buf_char->count() - prev_count;
1.1.1.14 root 1131: if(key_input == 0 && input) {
1132: key_input = 1;
1133: }
1.1.1.8 root 1134: }
1135: int val = key_input;
1136: key_input = 0;
1137: return(val);
1138: }
1139:
1.1.1.20 root 1140: /* ----------------------------------------------------------------------------
1141: MS-DOS virtual machine
1142: ---------------------------------------------------------------------------- */
1143:
1144: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg);
1145: int msdos_psp_get_file_table(int fd, int psp_seg);
1146: void msdos_putch(UINT8 data);
1147:
1.1 root 1148: // process info
1149:
1150: process_t *msdos_process_info_create(UINT16 psp_seg)
1151: {
1152: for(int i = 0; i < MAX_PROCESS; i++) {
1153: if(process[i].psp == 0 || process[i].psp == psp_seg) {
1154: memset(&process[i], 0, sizeof(process_t));
1155: process[i].psp = psp_seg;
1156: return(&process[i]);
1157: }
1158: }
1159: fatalerror("too many processes\n");
1160: return(NULL);
1161: }
1162:
1163: process_t *msdos_process_info_get(UINT16 psp_seg)
1164: {
1165: for(int i = 0; i < MAX_PROCESS; i++) {
1166: if(process[i].psp == psp_seg) {
1167: return(&process[i]);
1168: }
1169: }
1170: fatalerror("invalid psp address\n");
1171: return(NULL);
1172: }
1173:
1.1.1.13 root 1174: // dta info
1175:
1176: void msdos_dta_info_init()
1177: {
1.1.1.14 root 1178: for(int i = 0; i < MAX_DTAINFO; i++) {
1.1.1.13 root 1179: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
1180: }
1181: }
1182:
1183: dtainfo_t *msdos_dta_info_get(UINT16 psp_seg, UINT32 dta_laddr)
1184: {
1185: dtainfo_t *free_dta = NULL;
1.1.1.14 root 1186: for(int i = 0; i < MAX_DTAINFO; i++) {
1187: if(dtalist[i].find_handle == INVALID_HANDLE_VALUE) {
1188: if(free_dta == NULL) {
1.1.1.13 root 1189: free_dta = &dtalist[i];
1190: }
1.1.1.14 root 1191: } else if(dta_laddr < LFN_DTA_LADDR && dtalist[i].dta == dta_laddr) {
1.1.1.13 root 1192: return(&dtalist[i]);
1193: }
1194: }
1.1.1.14 root 1195: if(free_dta) {
1.1.1.13 root 1196: free_dta->psp = psp_seg;
1197: free_dta->dta = dta_laddr;
1198: return(free_dta);
1199: }
1200: fatalerror("too many dta\n");
1201: return(NULL);
1202: }
1203:
1204: void msdos_dta_info_free(UINT16 psp_seg)
1205: {
1.1.1.14 root 1206: for(int i = 0; i < MAX_DTAINFO; i++) {
1207: if(dtalist[i].psp == psp_seg && dtalist[i].find_handle != INVALID_HANDLE_VALUE) {
1.1.1.13 root 1208: FindClose(dtalist[i].find_handle);
1209: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
1210: }
1211: }
1212: }
1213:
1.1 root 1214: void msdos_cds_update(int drv)
1215: {
1216: cds_t *cds = (cds_t *)(mem + CDS_TOP);
1217:
1218: memset(mem + CDS_TOP, 0, CDS_SIZE);
1219: sprintf(cds->path_name, "%c:\\", 'A' + drv);
1220: cds->drive_attrib = 0x4000; // physical drive
1221: cds->physical_drive_number = drv;
1222: }
1223:
1.1.1.17 root 1224: // nls information tables
1225:
1226: // uppercase table (func 6502h)
1227: void msdos_upper_table_update()
1228: {
1229: *(UINT16 *)(mem + UPPERTABLE_TOP) = 0x80;
1.1.1.22! root 1230: for(unsigned i = 0; i < 0x80; ++i) {
1.1.1.17 root 1231: UINT8 c[4];
1232: *(UINT32 *)c = 0; // reset internal conversion state
1233: CharUpperBuffA((LPSTR)c, 4); // (workaround for MBCS codepage)
1234: c[0] = 0x80 + i;
1235: DWORD rc = CharUpperBuffA((LPSTR)c, 1);
1236: mem[UPPERTABLE_TOP + 2 + i] = (rc == 1 && c[0]) ? c[0] : 0x80 + i;
1237: }
1238: }
1239:
1240: // filename uppercase table (func 6504h)
1241: void msdos_filename_upper_table_init()
1242: {
1243: // depended on (file)system, not on active codepage
1244: // temporary solution: just filling data
1245: *(UINT16 *)(mem + FILENAME_UPPERTABLE_TOP) = 0x80;
1.1.1.22! root 1246: for(unsigned i = 0; i < 0x80; ++i) {
1.1.1.17 root 1247: mem[FILENAME_UPPERTABLE_TOP + 2 + i] = 0x80 + i;
1248: }
1249: }
1250:
1251: // filaname terminator table (func 6505h)
1252: void msdos_filename_terminator_table_init()
1253: {
1254: const char illegal_chars[] = ".\"/\\[]:|<>+=;,"; // for standard MS-DOS fs.
1255: UINT8 *data = mem + FILENAME_TERMINATOR_TOP;
1256:
1257: data[2] = 1; // marker? (permissible character value)
1258: data[3] = 0x00; // 00h...FFh
1259: data[4] = 0xff;
1260: data[5] = 0; // marker? (excluded character)
1261: data[6] = 0x00; // 00h...20h
1262: data[7] = 0x20;
1263: data[8] = 2; // marker? (illegal characters for filename)
1264: data[9] = (UINT8)strlen(illegal_chars);
1265: memcpy(data + 10, illegal_chars, data[9]);
1266:
1267: // total length
1268: *(UINT16 *)data = (10 - 2) + data[9];
1269: }
1270:
1271: // collating table (func 6506h)
1272: void msdos_collating_table_update()
1273: {
1274: // temporary solution: just filling data
1275: *(UINT16 *)(mem + COLLATING_TABLE_TOP) = 0x100;
1.1.1.22! root 1276: for(unsigned i = 0; i < 256; ++i) {
1.1.1.17 root 1277: mem[COLLATING_TABLE_TOP + 2 + i] = i;
1278: }
1279: }
1280:
1.1 root 1281: // dbcs
1282:
1283: void msdos_dbcs_table_update()
1284: {
1285: UINT8 dbcs_data[DBCS_SIZE];
1286: memset(dbcs_data, 0, sizeof(dbcs_data));
1287:
1288: CPINFO info;
1289: GetCPInfo(active_code_page, &info);
1290:
1291: if(info.MaxCharSize != 1) {
1292: for(int i = 0;; i += 2) {
1293: UINT8 lo = info.LeadByte[i + 0];
1294: UINT8 hi = info.LeadByte[i + 1];
1295: dbcs_data[2 + i + 0] = lo;
1296: dbcs_data[2 + i + 1] = hi;
1297: if(lo == 0 && hi == 0) {
1298: dbcs_data[0] = i + 2;
1299: break;
1300: }
1301: }
1302: } else {
1303: dbcs_data[0] = 2; // ???
1304: }
1305: memcpy(mem + DBCS_TOP, dbcs_data, sizeof(dbcs_data));
1306: }
1307:
1.1.1.17 root 1308: void msdos_dbcs_table_finish()
1309: {
1310: if(active_code_page != system_code_page) {
1311: _setmbcp(system_code_page);
1312: }
1313: }
1314:
1315: void msdos_nls_tables_init()
1.1 root 1316: {
1317: system_code_page = active_code_page = _getmbcp();
1.1.1.17 root 1318: msdos_upper_table_update();
1319: msdos_filename_terminator_table_init();
1320: msdos_filename_upper_table_init();
1321: msdos_collating_table_update();
1.1 root 1322: msdos_dbcs_table_update();
1323: }
1324:
1.1.1.17 root 1325: void msdos_nls_tables_update()
1.1 root 1326: {
1.1.1.17 root 1327: msdos_dbcs_table_update();
1328: msdos_upper_table_update();
1329: // msdos_collating_table_update();
1.1 root 1330: }
1331:
1332: int msdos_lead_byte_check(UINT8 code)
1333: {
1334: UINT8 *dbcs_table = mem + DBCS_TABLE;
1335:
1336: for(int i = 0;; i += 2) {
1337: UINT8 lo = dbcs_table[i + 0];
1338: UINT8 hi = dbcs_table[i + 1];
1339: if(lo == 0 && hi == 0) {
1340: break;
1341: }
1342: if(lo <= code && code <= hi) {
1343: return(1);
1344: }
1345: }
1346: return(0);
1347: }
1348:
1.1.1.20 root 1349: int msdos_ctrl_code_check(UINT8 code)
1350: {
1.1.1.22! root 1351: return (code >= 0x01 && code <= 0x1a && code != 0x07 && code != 0x08 && code != 0x09 && code != 0x0a && code != 0x0d);
1.1.1.20 root 1352: }
1353:
1.1 root 1354: // file control
1355:
1.1.1.14 root 1356: char *msdos_remove_double_quote(char *path)
1357: {
1358: static char tmp[MAX_PATH];
1359:
1360: memset(tmp, 0, sizeof(tmp));
1361: if(strlen(path) >= 2 && path[0] == '"' && path[strlen(path) - 1] == '"') {
1362: memcpy(tmp, path + 1, strlen(path) - 2);
1363: } else {
1364: strcpy(tmp, path);
1365: }
1366: return(tmp);
1367: }
1368:
1369: char *msdos_combine_path(char *dir, const char *file)
1370: {
1371: static char tmp[MAX_PATH];
1372: char *tmp_dir = msdos_remove_double_quote(dir);
1373:
1374: if(strlen(tmp_dir) == 0) {
1375: strcpy(tmp, file);
1376: } else if(tmp_dir[strlen(tmp_dir) - 1] == '\\') {
1377: sprintf(tmp, "%s%s", tmp_dir, file);
1378: } else {
1379: sprintf(tmp, "%s\\%s", tmp_dir, file);
1380: }
1381: return(tmp);
1382: }
1383:
1.1 root 1384: char *msdos_trimmed_path(char *path, int lfn)
1385: {
1386: static char tmp[MAX_PATH];
1387:
1388: if(lfn) {
1389: strcpy(tmp, path);
1390: } else {
1391: // remove space in the path
1392: char *src = path, *dst = tmp;
1393:
1394: while(*src != '\0') {
1395: if(msdos_lead_byte_check(*src)) {
1396: *dst++ = *src++;
1397: *dst++ = *src++;
1398: } else if(*src != ' ') {
1399: *dst++ = *src++;
1400: } else {
1401: src++; // skip space
1402: }
1403: }
1404: *dst = '\0';
1405: }
1.1.1.14 root 1406: if(_stricmp(tmp, "C:\\COMMAND.COM") == 0) {
1407: // redirect C:\COMMAND.COM to comspec_path
1408: strcpy(tmp, comspec_path);
1409: } else if(is_vista_or_later && _access(tmp, 0) != 0) {
1410: // redirect new files (without wildcards) in C:\ to %TEMP%, since C:\ is not usually writable
1411: static int root_drive_protected = -1;
1412: char temp[MAX_PATH], name[MAX_PATH], *name_temp = NULL;
1413: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
1414:
1415: if(GetFullPathName(tmp, MAX_PATH, temp, &name_temp) != 0 &&
1416: name_temp != NULL && strstr(name_temp, "?") == NULL && strstr(name_temp, "*") == NULL) {
1417: strcpy(name, name_temp);
1418: name_temp[0] = '\0';
1419:
1420: if((temp[0] == 'A' + dos_info->boot_drive - 1 || temp[0] == 'a' + dos_info->boot_drive - 1) &&
1421: (temp[1] == ':') && (temp[2] == '\\' || temp[2] == '/') && (temp[3] == '\0')) {
1422: if(root_drive_protected == -1) {
1423: FILE *fp = NULL;
1424:
1425: sprintf(temp, "%c:\\MS-DOS_Player.$$$", 'A' + dos_info->boot_drive - 1);
1426: root_drive_protected = 1;
1427: try {
1428: if((fp = fopen(temp, "w")) != NULL) {
1429: if(fprintf(fp, "TEST") == 4) {
1430: root_drive_protected = 0;
1431: }
1432: }
1433: } catch(...) {
1434: }
1435: if(fp != NULL) {
1436: fclose(fp);
1437: }
1438: if(_access(temp, 0) == 0) {
1439: remove(temp);
1440: }
1441: }
1442: if(root_drive_protected == 1) {
1443: if(GetEnvironmentVariable("TEMP", temp, MAX_PATH) != 0 ||
1444: GetEnvironmentVariable("TMP", temp, MAX_PATH) != 0) {
1445: strcpy(tmp, msdos_combine_path(temp, name));
1446: }
1447: }
1448: }
1449: }
1450: }
1.1 root 1451: return(tmp);
1452: }
1453:
1454: bool match(char *text, char *pattern)
1455: {
1456: //http://www.prefield.com/algorithm/string/wildcard.html
1.1.1.14 root 1457: switch(*pattern) {
1.1 root 1458: case '\0':
1459: return !*text;
1460: case '*':
1.1.1.14 root 1461: return match(text, pattern + 1) || (*text && match(text + 1, pattern));
1.1 root 1462: case '?':
1463: return *text && match(text + 1, pattern + 1);
1464: default:
1465: return (*text == *pattern) && match(text + 1, pattern + 1);
1466: }
1467: }
1468:
1469: bool msdos_match_volume_label(char *path, char *volume)
1470: {
1471: char *p;
1472:
1.1.1.14 root 1473: if(!*volume) {
1474: return false;
1475: } else if((p = my_strchr(path, ':')) != NULL) {
1.1 root 1476: return msdos_match_volume_label(p + 1, volume);
1477: } else if((p = my_strchr(path, '\\')) != NULL) {
1478: return msdos_match_volume_label(p + 1, volume);
1479: } else if((p = my_strchr(path, '.')) != NULL) {
1.1.1.14 root 1480: char tmp[MAX_PATH];
1481: sprintf(tmp, "%.*s%s", (int)(p - path), path, p + 1);
1482: return match(volume, tmp);
1.1 root 1483: } else {
1484: return match(volume, path);
1485: }
1486: }
1487:
1488: char *msdos_fcb_path(fcb_t *fcb)
1489: {
1490: static char tmp[MAX_PATH];
1491: char name[9], ext[4];
1492:
1493: memset(name, 0, sizeof(name));
1494: memcpy(name, fcb->file_name, 8);
1495: strcpy(name, msdos_trimmed_path(name, 0));
1496:
1497: memset(ext, 0, sizeof(ext));
1498: memcpy(ext, fcb->file_name + 8, 3);
1499: strcpy(ext, msdos_trimmed_path(ext, 0));
1500:
1501: if(name[0] == '\0' || strcmp(name, "????????") == 0) {
1502: strcpy(name, "*");
1503: }
1504: if(ext[0] == '\0') {
1505: strcpy(tmp, name);
1506: } else {
1507: if(strcmp(ext, "???") == 0) {
1508: strcpy(ext, "*");
1509: }
1510: sprintf(tmp, "%s.%s", name, ext);
1511: }
1512: return(tmp);
1513: }
1514:
1515: void msdos_set_fcb_path(fcb_t *fcb, char *path)
1516: {
1517: char *ext = my_strchr(path, '.');
1518:
1519: memset(fcb->file_name, 0x20, 8 + 3);
1520: if(ext != NULL && path[0] != '.') {
1521: *ext = '\0';
1522: memcpy(fcb->file_name + 8, ext + 1, strlen(ext + 1));
1523: }
1524: memcpy(fcb->file_name, path, strlen(path));
1525: }
1526:
1527: char *msdos_short_path(char *path)
1528: {
1529: static char tmp[MAX_PATH];
1530:
1531: GetShortPathName(path, tmp, MAX_PATH);
1532: my_strupr(tmp);
1533: return(tmp);
1534: }
1535:
1.1.1.13 root 1536: char *msdos_short_name(WIN32_FIND_DATA *fd)
1537: {
1538: static char tmp[MAX_PATH];
1539:
1.1.1.14 root 1540: if(fd->cAlternateFileName[0]) {
1.1.1.13 root 1541: strcpy(tmp, fd->cAlternateFileName);
1542: } else {
1543: strcpy(tmp, fd->cFileName);
1544: }
1545: my_strupr(tmp);
1546: return(tmp);
1547: }
1548:
1.1 root 1549: char *msdos_short_full_path(char *path)
1550: {
1551: static char tmp[MAX_PATH];
1552: char full[MAX_PATH], *name;
1553:
1.1.1.14 root 1554: // Full works with non-existent files, but Short does not
1.1 root 1555: GetFullPathName(path, MAX_PATH, full, &name);
1.1.1.14 root 1556: *tmp = '\0';
1557: if(GetShortPathName(full, tmp, MAX_PATH) == 0 && name > path) {
1558: name[-1] = '\0';
1559: DWORD len = GetShortPathName(full, tmp, MAX_PATH);
1560: if(len == 0) {
1561: strcpy(tmp, full);
1562: } else {
1563: tmp[len++] = '\\';
1564: strcpy(tmp + len, name);
1565: }
1566: }
1.1 root 1567: my_strupr(tmp);
1568: return(tmp);
1569: }
1570:
1571: char *msdos_short_full_dir(char *path)
1572: {
1573: static char tmp[MAX_PATH];
1574: char full[MAX_PATH], *name;
1575:
1576: GetFullPathName(path, MAX_PATH, full, &name);
1577: name[-1] = '\0';
1578: GetShortPathName(full, tmp, MAX_PATH);
1579: my_strupr(tmp);
1580: return(tmp);
1581: }
1582:
1583: char *msdos_local_file_path(char *path, int lfn)
1584: {
1585: char *trimmed = msdos_trimmed_path(path, lfn);
1.1.1.14 root 1586: #if 0
1587: // I have forgotten the reason of this routine... :-(
1.1 root 1588: if(_access(trimmed, 0) != 0) {
1589: process_t *process = msdos_process_info_get(current_psp);
1590: static char tmp[MAX_PATH];
1591:
1592: sprintf(tmp, "%s\\%s", process->module_dir, trimmed);
1593: if(_access(tmp, 0) == 0) {
1594: return(tmp);
1595: }
1596: }
1.1.1.14 root 1597: #endif
1.1 root 1598: return(trimmed);
1599: }
1600:
1.1.1.11 root 1601: bool msdos_is_con_path(char *path)
1602: {
1603: char full[MAX_PATH], *name;
1604:
1605: GetFullPathName(path, MAX_PATH, full, &name);
1606: return(_stricmp(full, "\\\\.\\CON") == 0);
1607: }
1608:
1.1.1.14 root 1609: bool msdos_is_nul_path(char *path)
1.1.1.8 root 1610: {
1.1.1.14 root 1611: char full[MAX_PATH], *name;
1.1.1.8 root 1612:
1.1.1.14 root 1613: GetFullPathName(path, MAX_PATH, full, &name);
1614: return(_stricmp(full, "\\\\.\\NUL") == 0);
1.1.1.8 root 1615: }
1616:
1.1.1.9 root 1617: char *msdos_search_command_com(char *command_path, char *env_path)
1618: {
1619: static char tmp[MAX_PATH];
1620: char path[MAX_PATH], *file_name;
1621:
1622: if(GetFullPathName(command_path, MAX_PATH, tmp, &file_name) != 0) {
1623: sprintf(file_name, "COMMAND.COM");
1624: if(_access(tmp, 0) == 0) {
1625: return(tmp);
1626: }
1627: }
1628: if(GetModuleFileName(NULL, path, MAX_PATH) != 0 && GetFullPathName(path, MAX_PATH, tmp, &file_name) != 0) {
1629: sprintf(file_name, "COMMAND.COM");
1630: if(_access(tmp, 0) == 0) {
1631: return(tmp);
1632: }
1633: }
1634: if(GetFullPathName("COMMAND.COM", MAX_PATH, tmp, &file_name) != 0) {
1635: if(_access(tmp, 0) == 0) {
1636: return(tmp);
1637: }
1638: }
1639: char *token = my_strtok(env_path, ";");
1640: while(token != NULL) {
1.1.1.14 root 1641: if(strlen(token) != 0 && token[0] != '%') {
1.1.1.9 root 1642: strcpy(tmp, msdos_combine_path(token, "COMMAND.COM"));
1643: if(_access(tmp, 0) == 0) {
1644: return(tmp);
1645: }
1646: }
1647: token = my_strtok(NULL, ";");
1648: }
1649: return(NULL);
1650: }
1651:
1.1.1.14 root 1652: int msdos_drive_number(const char *path)
1.1 root 1653: {
1654: char tmp[MAX_PATH], *name;
1655:
1656: GetFullPathName(path, MAX_PATH, tmp, &name);
1657: if(tmp[0] >= 'a' && tmp[0] <= 'z') {
1658: return(tmp[0] - 'a');
1659: } else {
1660: return(tmp[0] - 'A');
1661: }
1662: }
1663:
1664: char *msdos_volume_label(char *path)
1665: {
1666: static char tmp[MAX_PATH];
1667: char volume[] = "A:\\";
1668:
1669: if(path[1] == ':') {
1670: volume[0] = path[0];
1671: } else {
1672: volume[0] = 'A' + _getdrive() - 1;
1673: }
1674: if(!GetVolumeInformation(volume, tmp, MAX_PATH, NULL, NULL, NULL, NULL, 0)) {
1675: memset(tmp, 0, sizeof(tmp));
1676: }
1677: return(tmp);
1678: }
1679:
1680: char *msdos_short_volume_label(char *label)
1681: {
1682: static char tmp[(8 + 1 + 3) + 1];
1683: char *src = label;
1684: int remain = strlen(label);
1685: char *dst_n = tmp;
1686: char *dst_e = tmp + 9;
1687:
1688: strcpy(tmp, " . ");
1689: for(int i = 0; i < 8 && remain > 0; i++) {
1690: if(msdos_lead_byte_check(*src)) {
1691: if(++i == 8) {
1692: break;
1693: }
1694: *dst_n++ = *src++;
1695: remain--;
1696: }
1697: *dst_n++ = *src++;
1698: remain--;
1699: }
1700: if(remain > 0) {
1701: for(int i = 0; i < 3 && remain > 0; i++) {
1702: if(msdos_lead_byte_check(*src)) {
1703: if(++i == 3) {
1704: break;
1705: }
1706: *dst_e++ = *src++;
1707: remain--;
1708: }
1709: *dst_e++ = *src++;
1710: remain--;
1711: }
1712: *dst_e = '\0';
1713: } else {
1714: *dst_n = '\0';
1715: }
1716: my_strupr(tmp);
1717: return(tmp);
1718: }
1719:
1.1.1.13 root 1720: errno_t msdos_maperr(unsigned long oserrno)
1721: {
1722: _doserrno = oserrno;
1.1.1.14 root 1723: switch(oserrno) {
1.1.1.13 root 1724: case ERROR_FILE_NOT_FOUND: // 2
1725: case ERROR_PATH_NOT_FOUND: // 3
1726: case ERROR_INVALID_DRIVE: // 15
1727: case ERROR_NO_MORE_FILES: // 18
1728: case ERROR_BAD_NETPATH: // 53
1729: case ERROR_BAD_NET_NAME: // 67
1730: case ERROR_BAD_PATHNAME: // 161
1731: case ERROR_FILENAME_EXCED_RANGE: // 206
1732: return ENOENT;
1733: case ERROR_TOO_MANY_OPEN_FILES: // 4
1734: return EMFILE;
1735: case ERROR_ACCESS_DENIED: // 5
1736: case ERROR_CURRENT_DIRECTORY: // 16
1737: case ERROR_NETWORK_ACCESS_DENIED: // 65
1738: case ERROR_CANNOT_MAKE: // 82
1739: case ERROR_FAIL_I24: // 83
1740: case ERROR_DRIVE_LOCKED: // 108
1741: case ERROR_SEEK_ON_DEVICE: // 132
1742: case ERROR_NOT_LOCKED: // 158
1743: case ERROR_LOCK_FAILED: // 167
1744: return EACCES;
1745: case ERROR_INVALID_HANDLE: // 6
1746: case ERROR_INVALID_TARGET_HANDLE: // 114
1747: case ERROR_DIRECT_ACCESS_HANDLE: // 130
1748: return EBADF;
1749: case ERROR_ARENA_TRASHED: // 7
1750: case ERROR_NOT_ENOUGH_MEMORY: // 8
1751: case ERROR_INVALID_BLOCK: // 9
1752: case ERROR_NOT_ENOUGH_QUOTA: // 1816
1753: return ENOMEM;
1754: case ERROR_BAD_ENVIRONMENT: // 10
1755: return E2BIG;
1756: case ERROR_BAD_FORMAT: // 11
1757: return ENOEXEC;
1758: case ERROR_NOT_SAME_DEVICE: // 17
1759: return EXDEV;
1760: case ERROR_FILE_EXISTS: // 80
1761: case ERROR_ALREADY_EXISTS: // 183
1762: return EEXIST;
1763: case ERROR_NO_PROC_SLOTS: // 89
1764: case ERROR_MAX_THRDS_REACHED: // 164
1765: case ERROR_NESTING_NOT_ALLOWED: // 215
1766: return EAGAIN;
1767: case ERROR_BROKEN_PIPE: // 109
1768: return EPIPE;
1769: case ERROR_DISK_FULL: // 112
1770: return ENOSPC;
1771: case ERROR_WAIT_NO_CHILDREN: // 128
1772: case ERROR_CHILD_NOT_COMPLETE: // 129
1773: return ECHILD;
1774: case ERROR_DIR_NOT_EMPTY: // 145
1775: return ENOTEMPTY;
1776: }
1.1.1.14 root 1777: if(oserrno >= ERROR_WRITE_PROTECT /* 19 */ &&
1.1.1.13 root 1778: oserrno <= ERROR_SHARING_BUFFER_EXCEEDED /* 36 */) {
1779: return EACCES;
1780: }
1.1.1.14 root 1781: if(oserrno >= ERROR_INVALID_STARTING_CODESEG /* 188 */ &&
1.1.1.13 root 1782: oserrno <= ERROR_INFLOOP_IN_RELOC_CHAIN /* 202 */) {
1783: return ENOEXEC;
1784: }
1785: return EINVAL;
1786: }
1787:
1788: int msdos_open(const char *filename, int oflag)
1789: {
1.1.1.14 root 1790: if((oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) != _O_RDONLY) {
1.1.1.13 root 1791: return _open(filename, oflag);
1792: }
1.1.1.14 root 1793:
1794: SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, !(oflag & _O_NOINHERIT) };
1.1.1.13 root 1795: DWORD disposition;
1.1.1.14 root 1796: switch(oflag & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
1797: default:
1.1.1.13 root 1798: case _O_EXCL:
1799: disposition = OPEN_EXISTING;
1800: break;
1801: case _O_CREAT:
1802: disposition = OPEN_ALWAYS;
1803: break;
1804: case _O_CREAT | _O_EXCL:
1805: case _O_CREAT | _O_TRUNC | _O_EXCL:
1806: disposition = CREATE_NEW;
1807: break;
1808: case _O_TRUNC:
1809: case _O_TRUNC | _O_EXCL:
1810: disposition = TRUNCATE_EXISTING;
1811: break;
1812: case _O_CREAT | _O_TRUNC:
1813: disposition = CREATE_ALWAYS;
1814: break;
1815: }
1.1.1.14 root 1816:
1.1.1.13 root 1817: HANDLE h = CreateFile(filename, GENERIC_READ | FILE_WRITE_ATTRIBUTES,
1818: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
1819: FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.14 root 1820: if(h == INVALID_HANDLE_VALUE) {
1.1.1.13 root 1821: // FILE_WRITE_ATTRIBUTES may not be granted for standard users.
1822: // Retry without FILE_WRITE_ATTRIBUTES.
1823: h = CreateFile(filename, GENERIC_READ,
1824: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
1825: FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.14 root 1826: if(h == INVALID_HANDLE_VALUE) {
1.1.1.13 root 1827: errno = msdos_maperr(GetLastError());
1828: return -1;
1829: }
1830: }
1.1.1.14 root 1831:
1.1.1.13 root 1832: int fd = _open_osfhandle((intptr_t) h, oflag);
1.1.1.14 root 1833: if(fd == -1) {
1.1.1.13 root 1834: CloseHandle(h);
1835: }
1836: return fd;
1837: }
1838:
1.1.1.14 root 1839: void msdos_file_handler_open(int fd, const char *path, int atty, int mode, UINT16 info, UINT16 psp_seg)
1.1 root 1840: {
1841: static int id = 0;
1842: char full[MAX_PATH], *name;
1843:
1844: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1845: strcpy(file_handler[fd].path, full);
1846: } else {
1847: strcpy(file_handler[fd].path, path);
1848: }
1.1.1.14 root 1849: // isatty makes no distinction between CON & NUL
1850: // GetFileSize fails on CON, succeeds on NUL
1851: if(atty && (info != 0x80d3 || GetFileSize((HANDLE)_get_osfhandle(fd), NULL) == 0)) {
1852: info = 0x8084;
1853: atty = 0;
1854: } else if(!atty && info == 0x80d3) {
1855: info = msdos_drive_number(".");
1856: }
1.1 root 1857: file_handler[fd].valid = 1;
1858: file_handler[fd].id = id++; // dummy id for int 21h ax=71a6h
1859: file_handler[fd].atty = atty;
1860: file_handler[fd].mode = mode;
1861: file_handler[fd].info = info;
1862: file_handler[fd].psp = psp_seg;
1.1.1.21 root 1863:
1864: // init system file table
1865: if(fd < 20) {
1866: UINT8 *sft = mem + SFT_TOP + 6 + 0x3b * fd;
1867:
1868: memset(sft, 0, 0x3b);
1869:
1870: *(UINT16 *)(sft + 0x00) = 1;
1871: *(UINT16 *)(sft + 0x02) = file_handler[fd].mode;
1872: *(UINT8 *)(sft + 0x04) = GetFileAttributes(file_handler[fd].path) & 0xff;
1873: *(UINT16 *)(sft + 0x05) = file_handler[fd].info & 0xff;
1874:
1875: if(!(file_handler[fd].info & 0x80)) {
1876: *(UINT16 *)(sft + 0x07) = sizeof(dpb_t) * (file_handler[fd].info & 0x1f);
1877: *(UINT16 *)(sft + 0x09) = DPB_TOP >> 4;
1878:
1879: FILETIME time, local;
1880: HANDLE hHandle;
1881: WORD dos_date = 0, dos_time = 0;
1882: DWORD file_size = 0;
1883: if((hHandle = (HANDLE)_get_osfhandle(fd)) != INVALID_HANDLE_VALUE) {
1884: if(GetFileTime(hHandle, NULL, NULL, &time)) {
1885: FileTimeToLocalFileTime(&time, &local);
1886: FileTimeToDosDateTime(&local, &dos_date, &dos_time);
1887: }
1888: file_size = GetFileSize(hHandle, NULL);
1889: }
1890: *(UINT16 *)(sft + 0x0d) = dos_time;
1891: *(UINT16 *)(sft + 0x0f) = dos_date;
1892: *(UINT32 *)(sft + 0x11) = file_size;
1893: }
1894:
1895: char fname[MAX_PATH] = {0}, ext[MAX_PATH] = {0};
1896: _splitpath(file_handler[fd].path, NULL, NULL, fname, ext);
1897: my_strupr(fname);
1898: my_strupr(ext);
1899: memset(sft + 0x20, 0x20, 11);
1900: memcpy(sft + 0x20, fname, min(strlen(fname), 8));
1901: memcpy(sft + 0x28, ext + 1, min(strlen(ext + 1), 3));
1902:
1903: *(UINT16 *)(sft + 0x31) = psp_seg;
1904: }
1.1 root 1905: }
1906:
1907: void msdos_file_handler_dup(int dst, int src, UINT16 psp_seg)
1908: {
1909: strcpy(file_handler[dst].path, file_handler[src].path);
1910: file_handler[dst].valid = 1;
1911: file_handler[dst].id = file_handler[src].id;
1912: file_handler[dst].atty = file_handler[src].atty;
1913: file_handler[dst].mode = file_handler[src].mode;
1914: file_handler[dst].info = file_handler[src].info;
1915: file_handler[dst].psp = psp_seg;
1916: }
1917:
1.1.1.20 root 1918: void msdos_file_handler_close(int fd)
1.1 root 1919: {
1920: file_handler[fd].valid = 0;
1.1.1.21 root 1921:
1922: if(fd < 20) {
1923: memset(mem + SFT_TOP + 6 + 0x3b * fd, 0, 0x3b);
1924: }
1.1 root 1925: }
1926:
1.1.1.14 root 1927: inline int msdos_file_attribute_create(UINT16 new_attr)
1.1 root 1928: {
1.1.1.14 root 1929: return(new_attr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
1930: FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE |
1931: FILE_ATTRIBUTE_DIRECTORY));
1.1 root 1932: }
1933:
1934: // find file
1935:
1936: int msdos_find_file_check_attribute(int attribute, int allowed_mask, int required_mask)
1937: {
1938: if((allowed_mask & 0x08) && !(attribute & FILE_ATTRIBUTE_DIRECTORY)) {
1939: return(0); // search directory only !!!
1940: } else if(!(allowed_mask & 0x02) && (attribute & FILE_ATTRIBUTE_HIDDEN)) {
1941: return(0);
1942: } else if(!(allowed_mask & 0x04) && (attribute & FILE_ATTRIBUTE_SYSTEM)) {
1943: return(0);
1944: } else if(!(allowed_mask & 0x10) && (attribute & FILE_ATTRIBUTE_DIRECTORY)) {
1945: return(0);
1946: } else if((attribute & required_mask) != required_mask) {
1947: return(0);
1948: } else {
1949: return(1);
1950: }
1951: }
1952:
1.1.1.13 root 1953: int msdos_find_file_has_8dot3name(WIN32_FIND_DATA *fd)
1954: {
1.1.1.14 root 1955: if(fd->cAlternateFileName[0]) {
1.1.1.13 root 1956: return 1;
1957: }
1958: size_t len = strlen(fd->cFileName);
1.1.1.14 root 1959: if(len > 12) {
1.1.1.13 root 1960: return 0;
1961: }
1962: const char *ext = strrchr(fd->cFileName, '.');
1.1.1.14 root 1963: if((ext ? ext - fd->cFileName : len) > 8) {
1.1.1.13 root 1964: return 0;
1965: }
1966: return 1;
1967: }
1968:
1.1 root 1969: void msdos_find_file_conv_local_time(WIN32_FIND_DATA *fd)
1970: {
1971: FILETIME local;
1972:
1973: FileTimeToLocalFileTime(&fd->ftCreationTime, &local);
1974: fd->ftCreationTime.dwLowDateTime = local.dwLowDateTime;
1975: fd->ftCreationTime.dwHighDateTime = local.dwHighDateTime;
1976:
1977: FileTimeToLocalFileTime(&fd->ftLastAccessTime, &local);
1978: fd->ftLastAccessTime.dwLowDateTime = local.dwLowDateTime;
1979: fd->ftLastAccessTime.dwHighDateTime = local.dwHighDateTime;
1980:
1981: FileTimeToLocalFileTime(&fd->ftLastWriteTime, &local);
1982: fd->ftLastWriteTime.dwLowDateTime = local.dwLowDateTime;
1983: fd->ftLastWriteTime.dwHighDateTime = local.dwHighDateTime;
1984: }
1985:
1986: // i/o
1987:
1988: void msdos_stdio_reopen()
1989: {
1990: if(!file_handler[0].valid) {
1991: _dup2(DUP_STDIN, 0);
1992: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
1993: }
1994: if(!file_handler[1].valid) {
1995: _dup2(DUP_STDOUT, 1);
1996: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
1997: }
1998: if(!file_handler[2].valid) {
1999: _dup2(DUP_STDERR, 2);
2000: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
2001: }
1.1.1.21 root 2002: if(!file_handler[3].valid) {
2003: _dup2(DUP_STDAUX, 3);
2004: msdos_file_handler_open(3, "STDAUX", 0, 2, 0x80c0, 0);
2005: }
2006: if(!file_handler[4].valid) {
2007: _dup2(DUP_STDPRN, 4);
2008: msdos_file_handler_open(4, "STDPRN", 0, 1, 0xa8c0, 0);
2009: }
2010: for(int i = 0; i < 5; i++) {
2011: if(msdos_psp_get_file_table(i, current_psp) == 0xff) {
2012: msdos_psp_set_file_table(i, i, current_psp);
2013: }
2014: }
1.1 root 2015: }
2016:
2017: int msdos_kbhit()
2018: {
2019: msdos_stdio_reopen();
2020:
1.1.1.20 root 2021: process_t *process = msdos_process_info_get(current_psp);
2022: int fd = msdos_psp_get_file_table(0, current_psp);
2023:
2024: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 2025: // stdin is redirected to file
1.1.1.20 root 2026: return(eof(fd) == 0);
1.1 root 2027: }
2028:
2029: // check keyboard status
1.1.1.5 root 2030: if(key_buf_char->count() != 0 || key_code != 0) {
1.1 root 2031: return(1);
2032: } else {
2033: return(_kbhit());
2034: }
2035: }
2036:
2037: int msdos_getch_ex(int echo)
2038: {
2039: static char prev = 0;
2040:
2041: msdos_stdio_reopen();
2042:
1.1.1.20 root 2043: process_t *process = msdos_process_info_get(current_psp);
2044: int fd = msdos_psp_get_file_table(0, current_psp);
2045:
2046: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 2047: // stdin is redirected to file
2048: retry:
2049: char data;
1.1.1.20 root 2050: if(_read(fd, &data, 1) == 1) {
1.1 root 2051: char tmp = data;
2052: if(data == 0x0a) {
2053: if(prev == 0x0d) {
2054: goto retry; // CRLF -> skip LF
2055: } else {
2056: data = 0x0d; // LF only -> CR
2057: }
2058: }
2059: prev = tmp;
2060: return(data);
2061: }
2062: return(EOF);
2063: }
2064:
2065: // input from console
1.1.1.5 root 2066: int key_char, key_scan;
2067: if(key_code != 0) {
2068: key_char = (key_code >> 0) & 0xff;
2069: key_scan = (key_code >> 8) & 0xff;
2070: key_code >>= 16;
2071: } else {
1.1.1.14 root 2072: while(key_buf_char->count() == 0 && !m_halted) {
2073: if(!update_key_buffer()) {
2074: Sleep(10);
2075: }
2076: }
2077: if(m_halted) {
2078: // ctrl-c pressed - insert CR to terminate input loops
2079: key_char = 0x0d;
2080: key_scan = 0;
2081: } else {
2082: key_char = key_buf_char->read();
2083: key_scan = key_buf_scan->read();
1.1.1.5 root 2084: }
1.1 root 2085: }
2086: if(echo && key_char) {
2087: msdos_putch(key_char);
2088: }
2089: return key_char ? key_char : (key_scan != 0xe0) ? key_scan : 0;
2090: }
2091:
2092: inline int msdos_getch()
2093: {
2094: return(msdos_getch_ex(0));
2095: }
2096:
2097: inline int msdos_getche()
2098: {
2099: return(msdos_getch_ex(1));
2100: }
2101:
2102: int msdos_write(int fd, const void *buffer, unsigned int count)
2103: {
2104: static int is_cr = 0;
2105:
2106: if(fd == 1 && !file_handler[1].atty) {
2107: // CR+LF -> LF
2108: UINT8 *buf = (UINT8 *)buffer;
2109: for(unsigned int i = 0; i < count; i++) {
2110: UINT8 data = buf[i];
2111: if(is_cr) {
2112: if(data != 0x0a) {
2113: UINT8 tmp = 0x0d;
2114: _write(1, &tmp, 1);
2115: }
2116: _write(1, &data, 1);
2117: is_cr = 0;
2118: } else if(data == 0x0d) {
2119: is_cr = 1;
2120: } else {
2121: _write(1, &data, 1);
2122: }
2123: }
2124: return(count);
2125: }
1.1.1.14 root 2126: vram_flush();
1.1 root 2127: return(_write(fd, buffer, count));
2128: }
2129:
2130: void msdos_putch(UINT8 data)
2131: {
2132: static int p = 0;
2133: static int is_kanji = 0;
2134: static int is_esc = 0;
2135: static int stored_x;
2136: static int stored_y;
2137: static WORD stored_a;
1.1.1.20 root 2138: static char tmp[64], out[64];
1.1 root 2139:
2140: msdos_stdio_reopen();
2141:
1.1.1.20 root 2142: process_t *process = msdos_process_info_get(current_psp);
2143: int fd = msdos_psp_get_file_table(1, current_psp);
2144:
2145: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 2146: // stdout is redirected to file
1.1.1.20 root 2147: msdos_write(fd, &data, 1);
1.1 root 2148: return;
2149: }
2150:
2151: // output to console
2152: tmp[p++] = data;
2153:
1.1.1.14 root 2154: vram_flush();
2155:
1.1 root 2156: if(is_kanji) {
2157: // kanji character
2158: is_kanji = 0;
2159: } else if(is_esc) {
2160: // escape sequense
2161: if((tmp[1] == ')' || tmp[1] == '(') && p == 3) {
2162: p = is_esc = 0;
2163: } else if(tmp[1] == '=' && p == 4) {
2164: COORD co;
2165: co.X = tmp[3] - 0x20;
1.1.1.14 root 2166: co.Y = tmp[2] - 0x20 + scr_top;
1.1 root 2167: SetConsoleCursorPosition(hStdout, co);
2168: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14 root 2169: mem[0x451 + mem[0x462] * 2] = co.Y - scr_top;
1.1 root 2170: cursor_moved = false;
2171: p = is_esc = 0;
2172: } else if((data >= 'a' && data <= 'z') || (data >= 'A' && data <= 'Z') || data == '*') {
2173: CONSOLE_SCREEN_BUFFER_INFO csbi;
2174: COORD co;
2175: GetConsoleScreenBufferInfo(hStdout, &csbi);
2176: co.X = csbi.dwCursorPosition.X;
2177: co.Y = csbi.dwCursorPosition.Y;
2178: WORD wAttributes = csbi.wAttributes;
2179:
2180: if(tmp[1] == 'D') {
2181: co.Y++;
2182: } else if(tmp[1] == 'E') {
2183: co.X = 0;
2184: co.Y++;
2185: } else if(tmp[1] == 'M') {
2186: co.Y--;
2187: } else if(tmp[1] == '*') {
2188: SMALL_RECT rect;
1.1.1.14 root 2189: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2190: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2191: co.X = 0;
2192: co.Y = csbi.srWindow.Top;
1.1 root 2193: } else if(tmp[1] == '[') {
2194: int param[256], params = 0;
2195: memset(param, 0, sizeof(param));
2196: for(int i = 2; i < p; i++) {
2197: if(tmp[i] >= '0' && tmp[i] <= '9') {
2198: param[params] *= 10;
2199: param[params] += tmp[i] - '0';
2200: } else {
2201: params++;
2202: }
2203: }
2204: if(data == 'A') {
1.1.1.14 root 2205: co.Y -= (params == 0) ? 1 : param[0];
1.1 root 2206: } else if(data == 'B') {
1.1.1.14 root 2207: co.Y += (params == 0) ? 1 : param[0];
1.1 root 2208: } else if(data == 'C') {
1.1.1.14 root 2209: co.X += (params == 0) ? 1 : param[0];
1.1 root 2210: } else if(data == 'D') {
1.1.1.14 root 2211: co.X -= (params == 0) ? 1 : param[0];
1.1 root 2212: } else if(data == 'H' || data == 'f') {
1.1.1.14 root 2213: co.X = (param[1] == 0 ? 1 : param[1]) - 1;
2214: co.Y = (param[0] == 0 ? 1 : param[0]) - 1 + csbi.srWindow.Top;
1.1 root 2215: } else if(data == 'J') {
2216: SMALL_RECT rect;
1.1.1.14 root 2217: clear_scr_buffer(csbi.wAttributes);
1.1 root 2218: if(param[0] == 0) {
2219: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 2220: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2221: if(co.Y < csbi.srWindow.Bottom) {
2222: SET_RECT(rect, 0, co.Y + 1, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2223: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2224: }
2225: } else if(param[0] == 1) {
1.1.1.14 root 2226: if(co.Y > csbi.srWindow.Top) {
2227: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, co.Y - 1);
2228: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2229: }
2230: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14 root 2231: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2232: } else if(param[0] == 2) {
1.1.1.14 root 2233: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2234: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2235: co.X = co.Y = 0;
2236: }
2237: } else if(data == 'K') {
2238: SMALL_RECT rect;
1.1.1.14 root 2239: clear_scr_buffer(csbi.wAttributes);
1.1 root 2240: if(param[0] == 0) {
2241: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 2242: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2243: } else if(param[0] == 1) {
2244: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14 root 2245: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2246: } else if(param[0] == 2) {
2247: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 2248: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2249: }
2250: } else if(data == 'L') {
2251: SMALL_RECT rect;
1.1.1.14 root 2252: if(params == 0) {
2253: param[0] = 1;
1.1 root 2254: }
1.1.1.14 root 2255: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2256: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2257: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2258: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2259: clear_scr_buffer(csbi.wAttributes);
1.1 root 2260: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y + param[0] - 1);
1.1.1.14 root 2261: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2262: co.X = 0;
2263: } else if(data == 'M') {
2264: SMALL_RECT rect;
1.1.1.14 root 2265: if(params == 0) {
2266: param[0] = 1;
2267: }
2268: if(co.Y + param[0] > csbi.srWindow.Bottom) {
2269: clear_scr_buffer(csbi.wAttributes);
2270: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2271: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2272: } else {
1.1.1.14 root 2273: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2274: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2275: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2276: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2277: clear_scr_buffer(csbi.wAttributes);
1.1 root 2278: }
2279: co.X = 0;
2280: } else if(data == 'h') {
2281: if(tmp[2] == '>' && tmp[3] == '5') {
2282: CONSOLE_CURSOR_INFO cur;
2283: GetConsoleCursorInfo(hStdout, &cur);
2284: if(cur.bVisible) {
2285: cur.bVisible = FALSE;
1.1.1.14 root 2286: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 2287: }
2288: }
2289: } else if(data == 'l') {
2290: if(tmp[2] == '>' && tmp[3] == '5') {
2291: CONSOLE_CURSOR_INFO cur;
2292: GetConsoleCursorInfo(hStdout, &cur);
2293: if(!cur.bVisible) {
2294: cur.bVisible = TRUE;
1.1.1.14 root 2295: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 2296: }
2297: }
2298: } else if(data == 'm') {
2299: wAttributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
2300: int reverse = 0, hidden = 0;
2301: for(int i = 0; i < params; i++) {
2302: if(param[i] == 1) {
2303: wAttributes |= FOREGROUND_INTENSITY;
2304: } else if(param[i] == 4) {
2305: wAttributes |= COMMON_LVB_UNDERSCORE;
2306: } else if(param[i] == 7) {
2307: reverse = 1;
2308: } else if(param[i] == 8 || param[i] == 16) {
2309: hidden = 1;
2310: } else if((param[i] >= 17 && param[i] <= 23) || (param[i] >= 30 && param[i] <= 37)) {
2311: wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
2312: if(param[i] >= 17 && param[i] <= 23) {
2313: param[i] -= 16;
2314: } else {
2315: param[i] -= 30;
2316: }
2317: if(param[i] & 1) {
2318: wAttributes |= FOREGROUND_RED;
2319: }
2320: if(param[i] & 2) {
2321: wAttributes |= FOREGROUND_GREEN;
2322: }
2323: if(param[i] & 4) {
2324: wAttributes |= FOREGROUND_BLUE;
2325: }
2326: } else if(param[i] >= 40 && param[i] <= 47) {
2327: wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
2328: if((param[i] - 40) & 1) {
2329: wAttributes |= BACKGROUND_RED;
2330: }
2331: if((param[i] - 40) & 2) {
2332: wAttributes |= BACKGROUND_GREEN;
2333: }
2334: if((param[i] - 40) & 4) {
2335: wAttributes |= BACKGROUND_BLUE;
2336: }
2337: }
2338: }
2339: if(reverse) {
2340: wAttributes &= ~0xff;
2341: wAttributes |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
2342: }
2343: if(hidden) {
2344: wAttributes &= ~0x0f;
2345: wAttributes |= (wAttributes >> 4) & 0x0f;
2346: }
2347: } else if(data == 'n') {
2348: if(param[0] == 6) {
2349: char tmp[16];
2350: sprintf(tmp, "\x1b[%d;%dR", co.Y + 1, co.X + 1);
2351: int len = strlen(tmp);
2352: for(int i = 0; i < len; i++) {
2353: key_buf_char->write(tmp[i]);
2354: key_buf_scan->write(0x00);
2355: }
2356: }
2357: } else if(data == 's') {
2358: stored_x = co.X;
2359: stored_y = co.Y;
2360: stored_a = wAttributes;
2361: } else if(data == 'u') {
2362: co.X = stored_x;
2363: co.Y = stored_y;
2364: wAttributes = stored_a;
2365: }
2366: }
2367: if(co.X < 0) {
2368: co.X = 0;
2369: } else if(co.X >= csbi.dwSize.X) {
2370: co.X = csbi.dwSize.X - 1;
2371: }
1.1.1.14 root 2372: if(co.Y < csbi.srWindow.Top) {
2373: co.Y = csbi.srWindow.Top;
2374: } else if(co.Y > csbi.srWindow.Bottom) {
2375: co.Y = csbi.srWindow.Bottom;
1.1 root 2376: }
2377: if(co.X != csbi.dwCursorPosition.X || co.Y != csbi.dwCursorPosition.Y) {
2378: SetConsoleCursorPosition(hStdout, co);
2379: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14 root 2380: mem[0x451 + mem[0x462] * 2] = co.Y - csbi.srWindow.Top;
1.1 root 2381: cursor_moved = false;
2382: }
2383: if(wAttributes != csbi.wAttributes) {
2384: SetConsoleTextAttribute(hStdout, wAttributes);
2385: }
2386: p = is_esc = 0;
2387: }
2388: return;
2389: } else {
2390: if(msdos_lead_byte_check(data)) {
2391: is_kanji = 1;
2392: return;
2393: } else if(data == 0x1b) {
2394: is_esc = 1;
2395: return;
2396: }
2397: }
1.1.1.20 root 2398:
2399: DWORD q = 0, num;
2400: is_kanji = 0;
2401: for(int i = 0; i < p; i++) {
2402: UINT8 c = tmp[i];
2403: if(is_kanji) {
2404: is_kanji = 0;
2405: } else if(msdos_lead_byte_check(data)) {
2406: is_kanji = 1;
2407: } else if(msdos_ctrl_code_check(data)) {
2408: out[q++] = '^';
2409: c += 'A' - 1;
2410: }
2411: out[q++] = c;
2412: }
2413: WriteConsole(hStdout, out, q, &num, NULL);
1.1 root 2414: p = 0;
1.1.1.14 root 2415:
1.1.1.15 root 2416: if(!restore_console_on_exit) {
2417: CONSOLE_SCREEN_BUFFER_INFO csbi;
2418: GetConsoleScreenBufferInfo(hStdout, &csbi);
2419: scr_top = csbi.srWindow.Top;
2420: }
1.1 root 2421: cursor_moved = true;
2422: }
2423:
2424: int msdos_aux_in()
2425: {
1.1.1.21 root 2426: msdos_stdio_reopen();
2427:
1.1.1.20 root 2428: process_t *process = msdos_process_info_get(current_psp);
2429: int fd = msdos_psp_get_file_table(3, current_psp);
2430:
2431: if(fd < process->max_files && file_handler[fd].valid && !eof(fd)) {
1.1 root 2432: char data = 0;
1.1.1.20 root 2433: _read(fd, &data, 1);
1.1 root 2434: return(data);
2435: } else {
2436: return(EOF);
2437: }
2438: }
2439:
2440: void msdos_aux_out(char data)
2441: {
1.1.1.21 root 2442: msdos_stdio_reopen();
2443:
1.1.1.20 root 2444: process_t *process = msdos_process_info_get(current_psp);
2445: int fd = msdos_psp_get_file_table(3, current_psp);
2446:
2447: if(fd < process->max_files && file_handler[fd].valid) {
2448: msdos_write(fd, &data, 1);
1.1 root 2449: }
2450: }
2451:
2452: void msdos_prn_out(char data)
2453: {
1.1.1.21 root 2454: msdos_stdio_reopen();
2455:
1.1.1.20 root 2456: process_t *process = msdos_process_info_get(current_psp);
2457: int fd = msdos_psp_get_file_table(4, current_psp);
2458:
2459: if(fd < process->max_files && file_handler[fd].valid) {
2460: msdos_write(fd, &data, 1);
1.1 root 2461: }
2462: }
2463:
2464: // memory control
2465:
1.1.1.19 root 2466: mcb_t *msdos_mcb_create(int mcb_seg, UINT8 mz, UINT16 psp, int paragraphs)
1.1 root 2467: {
2468: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2469:
2470: mcb->mz = mz;
2471: mcb->psp = psp;
1.1.1.19 root 2472: mcb->paragraphs32 = paragraphs;
1.1 root 2473: return(mcb);
2474: }
2475:
2476: void msdos_mcb_check(mcb_t *mcb)
2477: {
2478: if(!(mcb->mz == 'M' || mcb->mz == 'Z')) {
2479: fatalerror("broken mcb\n");
2480: }
2481: }
2482:
2483: int msdos_mem_split(int seg, int paragraphs)
2484: {
2485: int mcb_seg = seg - 1;
2486: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2487: msdos_mcb_check(mcb);
2488:
1.1.1.19 root 2489: if(mcb->paragraphs() > paragraphs) {
1.1 root 2490: int new_seg = mcb_seg + 1 + paragraphs;
1.1.1.19 root 2491: int new_paragraphs = mcb->paragraphs() - paragraphs - 1;
1.1 root 2492:
2493: msdos_mcb_create(new_seg, mcb->mz, 0, new_paragraphs);
2494: mcb->mz = 'M';
1.1.1.19 root 2495: mcb->paragraphs32 = paragraphs;
1.1 root 2496: return(0);
2497: }
2498: return(-1);
2499: }
2500:
2501: void msdos_mem_merge(int seg)
2502: {
2503: int mcb_seg = seg - 1;
2504: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2505: msdos_mcb_check(mcb);
2506:
2507: while(1) {
2508: if(mcb->mz == 'Z') {
2509: break;
2510: }
1.1.1.19 root 2511: int next_seg = mcb_seg + 1 + mcb->paragraphs();
1.1 root 2512: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
2513: msdos_mcb_check(next_mcb);
2514:
2515: if(next_mcb->psp != 0) {
2516: break;
2517: }
2518: mcb->mz = next_mcb->mz;
1.1.1.19 root 2519: mcb->paragraphs32 = mcb->paragraphs() + 1 + next_mcb->paragraphs();
1.1 root 2520: }
2521: }
2522:
1.1.1.8 root 2523: int msdos_mem_alloc(int mcb_seg, int paragraphs, int new_process)
1.1 root 2524: {
2525: while(1) {
2526: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2527:
1.1.1.14 root 2528: if(mcb->psp == 0) {
2529: msdos_mem_merge(mcb_seg + 1);
2530: } else {
2531: msdos_mcb_check(mcb);
2532: }
1.1.1.8 root 2533: if(!(new_process && mcb->mz != 'Z')) {
1.1.1.19 root 2534: if(mcb->psp == 0 && mcb->paragraphs() >= paragraphs) {
1.1 root 2535: msdos_mem_split(mcb_seg + 1, paragraphs);
2536: mcb->psp = current_psp;
2537: return(mcb_seg + 1);
2538: }
2539: }
2540: if(mcb->mz == 'Z') {
2541: break;
2542: }
1.1.1.19 root 2543: mcb_seg += 1 + mcb->paragraphs();
1.1 root 2544: }
2545: return(-1);
2546: }
2547:
2548: int msdos_mem_realloc(int seg, int paragraphs, int *max_paragraphs)
2549: {
2550: int mcb_seg = seg - 1;
2551: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2552: msdos_mcb_check(mcb);
1.1.1.19 root 2553: int current_paragraphs = mcb->paragraphs();
1.1 root 2554:
2555: msdos_mem_merge(seg);
1.1.1.19 root 2556: if(paragraphs > mcb->paragraphs()) {
1.1.1.14 root 2557: if(max_paragraphs) {
1.1.1.19 root 2558: *max_paragraphs = mcb->paragraphs();
1.1.1.14 root 2559: }
1.1 root 2560: msdos_mem_split(seg, current_paragraphs);
2561: return(-1);
2562: }
2563: msdos_mem_split(seg, paragraphs);
2564: return(0);
2565: }
2566:
2567: void msdos_mem_free(int seg)
2568: {
2569: int mcb_seg = seg - 1;
2570: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2571: msdos_mcb_check(mcb);
2572:
2573: mcb->psp = 0;
2574: msdos_mem_merge(seg);
2575: }
2576:
1.1.1.8 root 2577: int msdos_mem_get_free(int mcb_seg, int new_process)
1.1 root 2578: {
2579: int max_paragraphs = 0;
2580:
2581: while(1) {
2582: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2583: msdos_mcb_check(mcb);
2584:
1.1.1.8 root 2585: if(!(new_process && mcb->mz != 'Z')) {
1.1.1.19 root 2586: if(mcb->psp == 0 && mcb->paragraphs() > max_paragraphs) {
2587: max_paragraphs = mcb->paragraphs();
1.1 root 2588: }
2589: }
2590: if(mcb->mz == 'Z') {
2591: break;
2592: }
1.1.1.19 root 2593: mcb_seg += 1 + mcb->paragraphs();
1.1 root 2594: }
1.1.1.14 root 2595: return(max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs);
1.1 root 2596: }
2597:
1.1.1.8 root 2598: int msdos_mem_get_last_mcb(int mcb_seg, UINT16 psp)
2599: {
2600: int last_seg = -1;
2601:
2602: while(1) {
2603: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2604: msdos_mcb_check(mcb);
2605:
1.1.1.14 root 2606: if(mcb->psp == psp) {
1.1.1.8 root 2607: last_seg = mcb_seg;
2608: }
1.1.1.14 root 2609: if(mcb->mz == 'Z') {
2610: break;
2611: }
1.1.1.19 root 2612: mcb_seg += 1 + mcb->paragraphs();
1.1.1.8 root 2613: }
2614: return(last_seg);
2615: }
2616:
1.1.1.19 root 2617: int msdos_mem_get_umb_linked()
2618: {
2619: int mcb_seg = first_mcb;
2620:
2621: while(1) {
2622: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2623: msdos_mcb_check(mcb);
2624:
2625: if(mcb->mz == 'Z') {
2626: if(mcb_seg >= (UMB_TOP >> 4)) {
2627: return(-1);
2628: }
2629: break;
2630: }
2631: mcb_seg += 1 + mcb->paragraphs();
2632: }
2633: return(0);
2634: }
2635:
2636: int msdos_mem_link_umb()
2637: {
2638: int mcb_seg = first_mcb;
2639:
2640: while(1) {
2641: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2642: msdos_mcb_check(mcb);
2643: mcb_seg += 1 + mcb->paragraphs();
2644:
2645: if(mcb->mz == 'Z') {
2646: if(mcb_seg == (MEMORY_END >> 4) - 1) {
2647: mcb->mz = 'M';
1.1.1.20 root 2648: ((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked |= 0x01;
1.1.1.19 root 2649: return(-1);
2650: }
2651: break;
2652: }
2653: }
2654: return(0);
2655: }
2656:
2657: int msdos_mem_unlink_umb()
2658: {
2659: int mcb_seg = first_mcb;
2660:
2661: while(1) {
2662: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2663: msdos_mcb_check(mcb);
2664: mcb_seg += 1 + mcb->paragraphs();
2665:
2666: if(mcb->mz == 'Z') {
2667: break;
2668: } else {
2669: if(mcb_seg == (MEMORY_END >> 4) - 1) {
2670: mcb->mz = 'Z';
1.1.1.20 root 2671: ((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked &= ~0x01;
1.1.1.19 root 2672: return(-1);
2673: }
2674: }
2675: }
2676: return(0);
2677: }
2678:
1.1 root 2679: // environment
2680:
2681: void msdos_env_set_argv(int env_seg, char *argv)
2682: {
2683: char *dst = (char *)(mem + (env_seg << 4));
2684:
2685: while(1) {
2686: if(dst[0] == 0) {
2687: break;
2688: }
2689: dst += strlen(dst) + 1;
2690: }
2691: *dst++ = 0; // end of environment
2692: *dst++ = 1; // top of argv[0]
2693: *dst++ = 0;
2694: memcpy(dst, argv, strlen(argv));
2695: dst += strlen(argv);
2696: *dst++ = 0;
2697: *dst++ = 0;
2698: }
2699:
2700: char *msdos_env_get_argv(int env_seg)
2701: {
2702: static char env[ENV_SIZE];
2703: char *src = env;
2704:
2705: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
2706: while(1) {
2707: if(src[0] == 0) {
2708: if(src[1] == 1) {
2709: return(src + 3);
2710: }
2711: break;
2712: }
2713: src += strlen(src) + 1;
2714: }
2715: return(NULL);
2716: }
2717:
2718: char *msdos_env_get(int env_seg, const char *name)
2719: {
2720: static char env[ENV_SIZE];
2721: char *src = env;
2722:
2723: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
2724: while(1) {
2725: if(src[0] == 0) {
2726: break;
2727: }
2728: int len = strlen(src);
2729: char *n = my_strtok(src, "=");
2730: char *v = src + strlen(n) + 1;
2731:
2732: if(_stricmp(name, n) == 0) {
2733: return(v);
2734: }
2735: src += len + 1;
2736: }
2737: return(NULL);
2738: }
2739:
2740: void msdos_env_set(int env_seg, char *name, char *value)
2741: {
2742: char env[ENV_SIZE];
2743: char *src = env;
2744: char *dst = (char *)(mem + (env_seg << 4));
2745: char *argv = msdos_env_get_argv(env_seg);
2746: int done = 0;
2747:
2748: memcpy(src, dst, ENV_SIZE);
2749: memset(dst, 0, ENV_SIZE);
2750: while(1) {
2751: if(src[0] == 0) {
2752: break;
2753: }
2754: int len = strlen(src);
2755: char *n = my_strtok(src, "=");
2756: char *v = src + strlen(n) + 1;
2757: char tmp[1024];
2758:
2759: if(_stricmp(name, n) == 0) {
2760: sprintf(tmp, "%s=%s", n, value);
2761: done = 1;
2762: } else {
2763: sprintf(tmp, "%s=%s", n, v);
2764: }
2765: memcpy(dst, tmp, strlen(tmp));
2766: dst += strlen(tmp) + 1;
2767: src += len + 1;
2768: }
2769: if(!done) {
2770: char tmp[1024];
2771:
2772: sprintf(tmp, "%s=%s", name, value);
2773: memcpy(dst, tmp, strlen(tmp));
2774: dst += strlen(tmp) + 1;
2775: }
2776: if(argv) {
2777: *dst++ = 0; // end of environment
2778: *dst++ = 1; // top of argv[0]
2779: *dst++ = 0;
2780: memcpy(dst, argv, strlen(argv));
2781: dst += strlen(argv);
2782: *dst++ = 0;
2783: *dst++ = 0;
2784: }
2785: }
2786:
2787: // process
2788:
1.1.1.8 root 2789: psp_t *msdos_psp_create(int psp_seg, UINT16 mcb_seg, UINT16 parent_psp, UINT16 env_seg)
1.1 root 2790: {
2791: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
2792:
2793: memset(psp, 0, PSP_SIZE);
2794: psp->exit[0] = 0xcd;
2795: psp->exit[1] = 0x20;
1.1.1.8 root 2796: psp->first_mcb = mcb_seg;
1.1 root 2797: psp->far_call = 0xea;
2798: psp->cpm_entry.w.l = 0xfff1; // int 21h, retf
2799: psp->cpm_entry.w.h = 0xf000;
2800: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
2801: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
2802: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
2803: psp->parent_psp = parent_psp;
1.1.1.20 root 2804: if(parent_psp == (UINT16)-1) {
2805: for(int i = 0; i < 20; i++) {
2806: if(file_handler[i].valid) {
2807: psp->file_table[i] = i;
2808: } else {
2809: psp->file_table[i] = 0xff;
2810: }
1.1 root 2811: }
1.1.1.20 root 2812: } else {
2813: memcpy(psp->file_table, ((psp_t *)(mem + (parent_psp << 4)))->file_table, 20);
1.1 root 2814: }
2815: psp->env_seg = env_seg;
2816: psp->stack.w.l = REG16(SP);
1.1.1.3 root 2817: psp->stack.w.h = SREG(SS);
1.1.1.14 root 2818: psp->file_table_size = 20;
2819: psp->file_table_ptr.w.l = 0x18;
2820: psp->file_table_ptr.w.h = psp_seg;
1.1 root 2821: psp->service[0] = 0xcd;
2822: psp->service[1] = 0x21;
2823: psp->service[2] = 0xcb;
2824: return(psp);
2825: }
2826:
1.1.1.20 root 2827: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg)
2828: {
2829: if(psp_seg && fd < 20) {
2830: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
2831: psp->file_table[fd] = value;
2832: }
2833: }
2834:
2835: int msdos_psp_get_file_table(int fd, int psp_seg)
2836: {
2837: if(psp_seg && fd < 20) {
2838: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
2839: fd = psp->file_table[fd];
2840: }
2841: return fd;
2842: }
2843:
1.1 root 2844: int msdos_process_exec(char *cmd, param_block_t *param, UINT8 al)
2845: {
2846: // load command file
2847: int fd = -1;
2848: int dos_command = 0;
1.1.1.4 root 2849: char command[MAX_PATH], path[MAX_PATH], opt[MAX_PATH], *name, name_tmp[MAX_PATH];
1.1 root 2850:
2851: int opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
2852: int opt_len = mem[opt_ofs];
2853: memset(opt, 0, sizeof(opt));
2854: memcpy(opt, mem + opt_ofs + 1, opt_len);
2855:
1.1.1.14 root 2856: if(strlen(cmd) >= 5 && _stricmp(&cmd[strlen(cmd) - 4], ".BAT") == 0) {
2857: // this is a batch file, run command.com
2858: char tmp[MAX_PATH];
2859: if(opt_len != 0) {
2860: sprintf(tmp, "/C %s %s", cmd, opt);
2861: } else {
2862: sprintf(tmp, "/C %s", cmd);
2863: }
2864: strcpy(opt, tmp);
2865: opt_len = strlen(opt);
2866: mem[opt_ofs] = opt_len;
2867: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
2868: strcpy(command, comspec_path);
2869: strcpy(name_tmp, "COMMAND.COM");
2870: } else {
2871: if(_stricmp(cmd, "C:\\COMMAND.COM") == 0) {
2872: // redirect C:\COMMAND.COM to comspec_path
2873: strcpy(command, comspec_path);
2874: } else {
2875: strcpy(command, cmd);
2876: }
2877: GetFullPathName(command, MAX_PATH, path, &name);
2878: memset(name_tmp, 0, sizeof(name_tmp));
2879: strcpy(name_tmp, name);
2880:
2881: // check command.com
2882: if(_stricmp(name, "COMMAND.COM") == 0 || _stricmp(name, "COMMAND") == 0) {
2883: if(opt_len == 0) {
2884: // process_t *current_process = msdos_process_info_get(current_psp);
2885: process_t *current_process = NULL;
2886: for(int i = 0; i < MAX_PROCESS; i++) {
2887: if(process[i].psp == current_psp) {
2888: current_process = &process[i];
2889: break;
2890: }
2891: }
2892: if(current_process != NULL) {
2893: param->cmd_line.dw = current_process->dta.dw;
2894: opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
2895: opt_len = mem[opt_ofs];
2896: memset(opt, 0, sizeof(opt));
2897: memcpy(opt, mem + opt_ofs + 1, opt_len);
2898: }
2899: }
2900: for(int i = 0; i < opt_len; i++) {
2901: if(opt[i] == ' ') {
2902: continue;
2903: }
2904: if(opt[i] == '/' && (opt[i + 1] == 'c' || opt[i + 1] == 'C') && opt[i + 2] == ' ') {
2905: for(int j = i + 3; j < opt_len; j++) {
2906: if(opt[j] == ' ') {
2907: continue;
2908: }
2909: char *token = my_strtok(opt + j, " ");
2910:
2911: if(strlen(token) >= 5 && _stricmp(&token[strlen(token) - 4], ".BAT") == 0) {
2912: // this is a batch file, okay to run command.com
2913: } else {
2914: // run program directly without command.com
2915: strcpy(command, token);
2916: char tmp[MAX_PATH];
2917: strcpy(tmp, token + strlen(token) + 1);
2918: strcpy(opt, tmp);
2919: opt_len = strlen(opt);
2920: mem[opt_ofs] = opt_len;
2921: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
2922: dos_command = 1;
2923: }
2924: break;
1.1 root 2925: }
2926: }
1.1.1.14 root 2927: break;
1.1 root 2928: }
2929: }
2930: }
2931:
2932: // load command file
2933: strcpy(path, command);
2934: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
2935: sprintf(path, "%s.COM", command);
2936: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
2937: sprintf(path, "%s.EXE", command);
2938: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
1.1.1.14 root 2939: sprintf(path, "%s.BAT", command);
2940: if(_access(path, 0) == 0) {
2941: // this is a batch file, run command.com
2942: char tmp[MAX_PATH];
2943: if(opt_len != 0) {
2944: sprintf(tmp, "/C %s %s", path, opt);
2945: } else {
2946: sprintf(tmp, "/C %s", path);
2947: }
2948: strcpy(opt, tmp);
2949: opt_len = strlen(opt);
2950: mem[opt_ofs] = opt_len;
2951: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
2952: strcpy(path, comspec_path);
2953: strcpy(name_tmp, "COMMAND.COM");
2954: fd = _open(path, _O_RDONLY | _O_BINARY);
2955: } else {
2956: // search path in parent environments
2957: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
2958: char *env = msdos_env_get(parent_psp->env_seg, "PATH");
2959: if(env != NULL) {
2960: char env_path[4096];
2961: strcpy(env_path, env);
2962: char *token = my_strtok(env_path, ";");
2963:
2964: while(token != NULL) {
2965: if(strlen(token) != 0) {
2966: sprintf(path, "%s", msdos_combine_path(token, command));
2967: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
2968: break;
2969: }
2970: sprintf(path, "%s.COM", msdos_combine_path(token, command));
2971: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
2972: break;
2973: }
2974: sprintf(path, "%s.EXE", msdos_combine_path(token, command));
2975: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
2976: break;
2977: }
2978: sprintf(path, "%s.BAT", msdos_combine_path(token, command));
2979: if(_access(path, 0) == 0) {
2980: // this is a batch file, run command.com
2981: char tmp[MAX_PATH];
2982: if(opt_len != 0) {
2983: sprintf(tmp, "/C %s %s", path, opt);
2984: } else {
2985: sprintf(tmp, "/C %s", path);
2986: }
2987: strcpy(opt, tmp);
2988: opt_len = strlen(opt);
2989: mem[opt_ofs] = opt_len;
2990: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
2991: strcpy(path, comspec_path);
2992: strcpy(name_tmp, "COMMAND.COM");
2993: fd = _open(path, _O_RDONLY | _O_BINARY);
2994: break;
2995: }
1.1.1.8 root 2996: }
1.1.1.14 root 2997: token = my_strtok(NULL, ";");
1.1 root 2998: }
2999: }
3000: }
3001: }
3002: }
3003: }
3004: if(fd == -1) {
3005: if(dos_command) {
3006: // may be dos command
3007: char tmp[MAX_PATH];
3008: sprintf(tmp, "%s %s", command, opt);
3009: system(tmp);
3010: return(0);
3011: } else {
3012: return(-1);
3013: }
3014: }
3015: _read(fd, file_buffer, sizeof(file_buffer));
3016: _close(fd);
3017:
3018: // copy environment
3019: int env_seg, psp_seg;
3020:
1.1.1.8 root 3021: if((env_seg = msdos_mem_alloc(first_mcb, ENV_SIZE >> 4, 1)) == -1) {
1.1 root 3022: return(-1);
3023: }
3024: if(param->env_seg == 0) {
3025: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
3026: memcpy(mem + (env_seg << 4), mem + (parent_psp->env_seg << 4), ENV_SIZE);
3027: } else {
3028: memcpy(mem + (env_seg << 4), mem + (param->env_seg << 4), ENV_SIZE);
3029: }
3030: msdos_env_set_argv(env_seg, msdos_short_full_path(path));
3031:
3032: // check exe header
3033: exe_header_t *header = (exe_header_t *)file_buffer;
1.1.1.8 root 3034: int paragraphs, free_paragraphs = msdos_mem_get_free(first_mcb, 1);
1.1 root 3035: UINT16 cs, ss, ip, sp;
3036:
3037: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
3038: // memory allocation
3039: int header_size = header->header_size * 16;
3040: int load_size = header->pages * 512 - header_size;
3041: if(header_size + load_size < 512) {
3042: load_size = 512 - header_size;
3043: }
3044: paragraphs = (PSP_SIZE + load_size) >> 4;
3045: if(paragraphs + header->min_alloc > free_paragraphs) {
3046: msdos_mem_free(env_seg);
3047: return(-1);
3048: }
3049: paragraphs += header->max_alloc ? header->max_alloc : header->min_alloc;
3050: if(paragraphs > free_paragraphs) {
3051: paragraphs = free_paragraphs;
3052: }
1.1.1.8 root 3053: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1 root 3054: msdos_mem_free(env_seg);
3055: return(-1);
3056: }
3057: // relocation
3058: int start_seg = psp_seg + (PSP_SIZE >> 4);
3059: for(int i = 0; i < header->relocations; i++) {
3060: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
3061: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
3062: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
3063: }
3064: memcpy(mem + (start_seg << 4), file_buffer + header_size, load_size);
3065: // segments
3066: cs = header->init_cs + start_seg;
3067: ss = header->init_ss + start_seg;
3068: ip = header->init_ip;
3069: sp = header->init_sp - 2; // for symdeb
3070: } else {
3071: // memory allocation
3072: paragraphs = free_paragraphs;
1.1.1.8 root 3073: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1 root 3074: msdos_mem_free(env_seg);
3075: return(-1);
3076: }
3077: int start_seg = psp_seg + (PSP_SIZE >> 4);
3078: memcpy(mem + (start_seg << 4), file_buffer, 0x10000 - PSP_SIZE);
3079: // segments
3080: cs = ss = psp_seg;
3081: ip = 0x100;
3082: sp = 0xfffe;
3083: }
3084:
3085: // create psp
1.1.1.3 root 3086: #if defined(HAS_I386)
3087: *(UINT16 *)(mem + 4 * 0x22 + 0) = m_eip;
3088: #else
3089: *(UINT16 *)(mem + 4 * 0x22 + 0) = m_pc - SREG_BASE(CS);
3090: #endif
3091: *(UINT16 *)(mem + 4 * 0x22 + 2) = SREG(CS);
1.1 root 3092: psp_t *psp = msdos_psp_create(psp_seg, psp_seg + paragraphs, current_psp, env_seg);
3093: memcpy(psp->fcb1, mem + (param->fcb1.w.h << 4) + param->fcb1.w.l, sizeof(psp->fcb1));
3094: memcpy(psp->fcb2, mem + (param->fcb2.w.h << 4) + param->fcb2.w.l, sizeof(psp->fcb2));
3095: memcpy(psp->buffer, mem + (param->cmd_line.w.h << 4) + param->cmd_line.w.l, sizeof(psp->buffer));
3096:
3097: mcb_t *mcb_env = (mcb_t *)(mem + ((env_seg - 1) << 4));
3098: mcb_t *mcb_psp = (mcb_t *)(mem + ((psp_seg - 1) << 4));
3099: mcb_psp->psp = mcb_env->psp = psp_seg;
3100:
1.1.1.4 root 3101: for(int i = 0; i < 8; i++) {
3102: if(name_tmp[i] == '.') {
3103: mcb_psp->prog_name[i] = '\0';
3104: break;
3105: } else if(i < 7 && msdos_lead_byte_check(name_tmp[i])) {
3106: mcb_psp->prog_name[i] = name_tmp[i];
3107: i++;
3108: mcb_psp->prog_name[i] = name_tmp[i];
3109: } else if(name_tmp[i] >= 'a' && name_tmp[i] <= 'z') {
3110: mcb_psp->prog_name[i] = name_tmp[i] - 'a' + 'A';
3111: } else {
3112: mcb_psp->prog_name[i] = name_tmp[i];
3113: }
3114: }
3115:
1.1 root 3116: // process info
3117: process_t *process = msdos_process_info_create(psp_seg);
3118: strcpy(process->module_dir, msdos_short_full_dir(path));
3119: process->dta.w.l = 0x80;
3120: process->dta.w.h = psp_seg;
3121: process->switchar = '/';
3122: process->max_files = 20;
3123: process->parent_int_10h_feh_called = int_10h_feh_called;
3124: process->parent_int_10h_ffh_called = int_10h_ffh_called;
1.1.1.14 root 3125: process->parent_ds = SREG(DS);
1.1 root 3126:
3127: current_psp = psp_seg;
3128:
3129: if(al == 0x00) {
3130: int_10h_feh_called = int_10h_ffh_called = false;
3131:
3132: // registers and segments
3133: REG16(AX) = REG16(BX) = 0x00;
3134: REG16(CX) = 0xff;
3135: REG16(DX) = psp_seg;
3136: REG16(SI) = ip;
3137: REG16(DI) = sp;
3138: REG16(SP) = sp;
1.1.1.3 root 3139: SREG(DS) = SREG(ES) = psp_seg;
3140: SREG(SS) = ss;
3141: i386_load_segment_descriptor(DS);
3142: i386_load_segment_descriptor(ES);
3143: i386_load_segment_descriptor(SS);
1.1 root 3144:
3145: *(UINT16 *)(mem + (ss << 4) + sp) = 0;
3146: i386_jmp_far(cs, ip);
3147: } else if(al == 0x01) {
3148: // copy ss:sp and cs:ip to param block
3149: param->sp = sp;
3150: param->ss = ss;
3151: param->ip = ip;
3152: param->cs = cs;
3153: }
3154: return(0);
3155: }
3156:
3157: void msdos_process_terminate(int psp_seg, int ret, int mem_free)
3158: {
3159: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
3160:
3161: *(UINT32 *)(mem + 4 * 0x22) = psp->int_22h.dw;
3162: *(UINT32 *)(mem + 4 * 0x23) = psp->int_23h.dw;
3163: *(UINT32 *)(mem + 4 * 0x24) = psp->int_24h.dw;
3164:
1.1.1.3 root 3165: SREG(SS) = psp->stack.w.h;
3166: i386_load_segment_descriptor(SS);
1.1 root 3167: REG16(SP) = psp->stack.w.l;
3168: i386_jmp_far(psp->int_22h.w.h, psp->int_22h.w.l);
3169:
3170: process_t *process = msdos_process_info_get(psp_seg);
3171: int_10h_feh_called = process->parent_int_10h_feh_called;
3172: int_10h_ffh_called = process->parent_int_10h_ffh_called;
1.1.1.14 root 3173: SREG(DS) = process->parent_ds;
3174: i386_load_segment_descriptor(DS);
1.1 root 3175:
3176: if(mem_free) {
1.1.1.8 root 3177: int mcb_seg;
3178: while((mcb_seg = msdos_mem_get_last_mcb(first_mcb, psp_seg)) != -1) {
3179: msdos_mem_free(mcb_seg + 1);
3180: }
3181: while((mcb_seg = msdos_mem_get_last_mcb(UMB_TOP >> 4, psp_seg)) != -1) {
3182: msdos_mem_free(mcb_seg + 1);
3183: }
1.1 root 3184:
3185: for(int i = 0; i < MAX_FILES; i++) {
3186: if(file_handler[i].valid && file_handler[i].psp == psp_seg) {
3187: _close(i);
1.1.1.20 root 3188: msdos_file_handler_close(i);
3189: msdos_psp_set_file_table(i, 0x0ff, psp_seg); // FIXME: consider duplicated file handles
1.1 root 3190: }
3191: }
1.1.1.13 root 3192: msdos_dta_info_free(psp_seg);
1.1 root 3193: }
1.1.1.14 root 3194: msdos_stdio_reopen();
1.1 root 3195:
3196: memset(process, 0, sizeof(process_t));
3197:
3198: current_psp = psp->parent_psp;
3199: retval = ret;
3200: }
3201:
3202: // drive
3203:
3204: int msdos_drive_param_block_update(int drive_num, UINT16 *seg, UINT16 *ofs, int force_update)
3205: {
3206: *seg = DPB_TOP >> 4;
3207: *ofs = sizeof(dpb_t) * drive_num;
3208: dpb_t *dpb = (dpb_t *)(mem + (*seg << 4) + *ofs);
3209:
3210: if(!force_update && dpb->free_clusters != 0) {
3211: return(dpb->bytes_per_sector ? 1 : 0);
3212: }
3213: memset(dpb, 0, sizeof(dpb_t));
3214:
3215: int res = 0;
3216: char dev[64];
3217: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num);
3218:
1.1.1.17 root 3219: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1.1 root 3220: if(hFile != INVALID_HANDLE_VALUE) {
3221: DISK_GEOMETRY geo;
3222: DWORD dwSize;
3223: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
3224: dpb->bytes_per_sector = (UINT16)geo.BytesPerSector;
3225: dpb->highest_sector_num = (UINT8)(geo.SectorsPerTrack - 1);
3226: dpb->highest_cluster_num = (UINT16)(geo.TracksPerCylinder * geo.Cylinders.QuadPart + 1);
1.1.1.14 root 3227: dpb->maximum_cluster_num = (UINT32)(geo.TracksPerCylinder * geo.Cylinders.QuadPart + 1);
1.1 root 3228: switch(geo.MediaType) {
3229: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K)
3230: dpb->media_type = 0xff;
3231: break;
3232: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K)
3233: dpb->media_type = 0xfe;
3234: break;
3235: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K)
3236: dpb->media_type = 0xfd;
3237: break;
3238: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K)
3239: dpb->media_type = 0xfc;
3240: break;
3241: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M)
3242: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5")
3243: dpb->media_type = 0xf9;
3244: break;
3245: case FixedMedia: // hard disk
3246: case RemovableMedia:
1.1.1.19 root 3247: case Unknown:
1.1 root 3248: dpb->media_type = 0xf8;
3249: break;
3250: default:
3251: dpb->media_type = 0xf0;
3252: break;
3253: }
3254: res = 1;
3255: }
3256: dpb->drive_num = drive_num;
3257: dpb->unit_num = drive_num;
3258: dpb->next_dpb_ofs = *ofs + sizeof(dpb_t);
3259: dpb->next_dpb_seg = *seg;
1.1.1.14 root 3260: dpb->info_sector = 0xffff;
3261: dpb->backup_boot_sector = 0xffff;
1.1 root 3262: dpb->free_clusters = 0xffff;
1.1.1.14 root 3263: dpb->free_search_cluster = 0xffffffff;
1.1 root 3264: CloseHandle(hFile);
3265: }
3266: return(res);
3267: }
3268:
3269: // pc bios
3270:
1.1.1.19 root 3271: UINT32 get_ticks_since_midnight(UINT32 cur_msec)
3272: {
3273: static unsigned __int64 start_msec_since_midnight = 0;
3274: static unsigned __int64 start_msec_since_hostboot = 0;
3275:
3276: if(start_msec_since_midnight == 0) {
3277: SYSTEMTIME time;
3278: GetLocalTime(&time);
3279: start_msec_since_midnight = ((time.wHour * 60 + time.wMinute) * 60 + time.wSecond) * 1000 + time.wMilliseconds;
3280: start_msec_since_hostboot = cur_msec;
3281: }
3282: unsigned __int64 msec = (start_msec_since_midnight + cur_msec - start_msec_since_hostboot) % (24 * 60 * 60 * 1000);
3283: unsigned __int64 tick = msec * 0x1800b0 / (24 * 60 * 60 * 1000);
3284: return (UINT32)tick;
3285: }
3286:
3287: void pcbios_update_daily_timer_counter(UINT32 cur_msec)
3288: {
3289: UINT32 prev_tick = *(UINT32 *)(mem + 0x46c);
3290: UINT32 next_tick = get_ticks_since_midnight(cur_msec);
3291:
3292: if(prev_tick > next_tick) {
3293: mem[0x470] = 1;
3294: }
3295: *(UINT32 *)(mem + 0x46c) = next_tick;
3296: }
3297:
1.1.1.14 root 3298: inline void pcbios_irq0()
3299: {
3300: //++*(UINT32 *)(mem + 0x46c);
1.1.1.19 root 3301: pcbios_update_daily_timer_counter(timeGetTime());
1.1.1.14 root 3302: }
3303:
1.1.1.16 root 3304: int pcbios_get_text_vram_address(int page)
1.1 root 3305: {
3306: if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 3307: return TEXT_VRAM_TOP;
1.1 root 3308: } else {
1.1.1.14 root 3309: return TEXT_VRAM_TOP + VIDEO_REGEN * (page % vram_pages);
1.1 root 3310: }
3311: }
3312:
1.1.1.16 root 3313: int pcbios_get_shadow_buffer_address(int page)
1.1 root 3314: {
1.1.1.14 root 3315: if(!int_10h_feh_called) {
1.1.1.16 root 3316: return pcbios_get_text_vram_address(page);
1.1.1.14 root 3317: } else if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 3318: return SHADOW_BUF_TOP;
3319: } else {
1.1.1.14 root 3320: return SHADOW_BUF_TOP + VIDEO_REGEN * (page % vram_pages);
1.1.1.8 root 3321: }
3322: }
3323:
1.1.1.16 root 3324: int pcbios_get_shadow_buffer_address(int page, int x, int y)
1.1.1.8 root 3325: {
1.1.1.16 root 3326: return pcbios_get_shadow_buffer_address(page) + (x + y * scr_width) * 2;
1.1 root 3327: }
3328:
1.1.1.16 root 3329: void pcbios_set_console_size(int width, int height, bool clr_screen)
1.1 root 3330: {
1.1.1.14 root 3331: // clear the existing screen, not just the new one
3332: int clr_height = max(height, scr_height);
3333:
1.1.1.16 root 3334: if(scr_width != width || scr_height != height) {
3335: change_console_size(width, height);
1.1.1.14 root 3336: }
3337: mem[0x462] = 0;
3338: *(UINT16 *)(mem + 0x44e) = 0;
3339:
1.1.1.16 root 3340: text_vram_top_address = pcbios_get_text_vram_address(0);
3341: text_vram_end_address = text_vram_top_address + width * height * 2;
3342: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(0);
3343: shadow_buffer_end_address = shadow_buffer_top_address + width * height * 2;
1.1 root 3344:
1.1.1.16 root 3345: if(clr_screen) {
1.1.1.14 root 3346: for(int ofs = shadow_buffer_top_address; ofs < shadow_buffer_end_address;) {
3347: mem[ofs++] = 0x20;
3348: mem[ofs++] = 0x07;
3349: }
3350:
3351: EnterCriticalSection(&vram_crit_sect);
3352: for(int y = 0; y < clr_height; y++) {
3353: for(int x = 0; x < scr_width; x++) {
3354: SCR_BUF(y,x).Char.AsciiChar = ' ';
3355: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
1.1 root 3356: }
3357: }
3358: SMALL_RECT rect;
1.1.1.14 root 3359: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + clr_height - 1);
3360: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
3361: vram_length_char = vram_last_length_char = 0;
3362: vram_length_attr = vram_last_length_attr = 0;
3363: LeaveCriticalSection(&vram_crit_sect);
1.1 root 3364: }
1.1.1.14 root 3365: COORD co;
3366: co.X = 0;
3367: co.Y = scr_top;
3368: SetConsoleCursorPosition(hStdout, co);
3369: cursor_moved = true;
3370: SetConsoleTextAttribute(hStdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
1.1 root 3371: }
3372:
1.1.1.16 root 3373: inline void pcbios_int_10h_00h()
3374: {
3375: switch(REG8(AL) & 0x7f) {
3376: case 0x70: // v-text mode
3377: case 0x71: // extended cga v-text mode
3378: pcbios_set_console_size(scr_width, scr_height, !(REG8(AL) & 0x80));
3379: break;
3380: default:
3381: pcbios_set_console_size(80, 25, !(REG8(AL) & 0x80));
3382: break;
3383: }
3384: if(REG8(AL) & 0x80) {
3385: mem[0x487] |= 0x80;
3386: } else {
3387: mem[0x487] &= ~0x80;
3388: }
3389: mem[0x449] = REG8(AL) & 0x7f;
3390: }
3391:
1.1 root 3392: inline void pcbios_int_10h_01h()
3393: {
1.1.1.13 root 3394: mem[0x460] = REG8(CL);
3395: mem[0x461] = REG8(CH);
1.1.1.14 root 3396:
3397: CONSOLE_CURSOR_INFO ci;
3398: GetConsoleCursorInfo(hStdout, &ci);
3399: // ci.bVisible = !(REG8(CH) & 0x60) && REG8(CH) <= REG8(CL);
3400: // if(ci.bVisible) {
3401: int lines = max(8, REG8(CL) + 1);
3402: ci.dwSize = (REG8(CL) - REG8(CH) + 1) * 100 / lines;
3403: // }
3404: SetConsoleCursorInfo(hStdout, &ci);
1.1 root 3405: }
3406:
3407: inline void pcbios_int_10h_02h()
3408: {
1.1.1.14 root 3409: // continuously setting the cursor effectively stops it blinking
3410: if(mem[0x462] == REG8(BH) && (REG8(DL) != mem[0x450 + REG8(BH) * 2] || REG8(DH) != mem[0x451 + REG8(BH) * 2])) {
1.1 root 3411: COORD co;
3412: co.X = REG8(DL);
1.1.1.14 root 3413: co.Y = REG8(DH) + scr_top;
3414:
3415: // some programs hide the cursor by moving it off screen
3416: static bool hidden = false;
3417: CONSOLE_CURSOR_INFO ci;
3418: GetConsoleCursorInfo(hStdout, &ci);
3419:
3420: if(REG8(DH) >= scr_height || !SetConsoleCursorPosition(hStdout, co)) {
3421: if(ci.bVisible) {
3422: ci.bVisible = FALSE;
3423: // SetConsoleCursorInfo(hStdout, &ci);
3424: hidden = true;
3425: }
3426: } else if(hidden) {
3427: if(!ci.bVisible) {
3428: ci.bVisible = TRUE;
3429: // SetConsoleCursorInfo(hStdout, &ci);
3430: }
3431: hidden = false;
3432: }
1.1 root 3433: }
1.1.1.14 root 3434: mem[0x450 + (REG8(BH) % vram_pages) * 2] = REG8(DL);
3435: mem[0x451 + (REG8(BH) % vram_pages) * 2] = REG8(DH);
1.1 root 3436: }
3437:
3438: inline void pcbios_int_10h_03h()
3439: {
1.1.1.14 root 3440: REG8(DL) = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3441: REG8(DH) = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 3442: REG8(CL) = mem[0x460];
3443: REG8(CH) = mem[0x461];
3444: }
3445:
3446: inline void pcbios_int_10h_05h()
3447: {
1.1.1.14 root 3448: if(REG8(AL) >= vram_pages) {
3449: return;
3450: }
3451: if(mem[0x462] != REG8(AL)) {
3452: vram_flush();
3453:
1.1 root 3454: SMALL_RECT rect;
1.1.1.14 root 3455: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
3456: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3457:
1.1.1.16 root 3458: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(mem[0x462]); y < scr_height; y++) {
1.1.1.14 root 3459: for(int x = 0; x < scr_width; x++) {
3460: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
3461: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 3462: }
3463: }
1.1.1.16 root 3464: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(REG8(AL)); y < scr_height; y++) {
1.1.1.14 root 3465: for(int x = 0; x < scr_width; x++) {
3466: SCR_BUF(y,x).Char.AsciiChar = mem[ofs++];
3467: SCR_BUF(y,x).Attributes = mem[ofs++];
1.1 root 3468: }
3469: }
1.1.1.14 root 3470: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3471:
3472: COORD co;
1.1.1.14 root 3473: co.X = mem[0x450 + REG8(AL) * 2];
3474: co.Y = mem[0x451 + REG8(AL) * 2] + scr_top;
3475: if(co.Y < scr_top + scr_height) {
3476: SetConsoleCursorPosition(hStdout, co);
3477: }
1.1 root 3478: }
1.1.1.14 root 3479: mem[0x462] = REG8(AL);
3480: *(UINT16 *)(mem + 0x44e) = REG8(AL) * VIDEO_REGEN;
3481: int regen = min(scr_width * scr_height * 2, 0x8000);
1.1.1.16 root 3482: text_vram_top_address = pcbios_get_text_vram_address(mem[0x462]);
1.1.1.14 root 3483: text_vram_end_address = text_vram_top_address + regen;
1.1.1.16 root 3484: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(mem[0x462]);
1.1.1.14 root 3485: shadow_buffer_end_address = shadow_buffer_top_address + regen;
1.1 root 3486: }
3487:
3488: inline void pcbios_int_10h_06h()
3489: {
1.1.1.14 root 3490: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
3491: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
3492: return;
3493: }
3494: vram_flush();
3495:
1.1 root 3496: SMALL_RECT rect;
1.1.1.14 root 3497: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
3498: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
3499:
3500: int right = min(REG8(DL), scr_width - 1);
3501: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 3502:
3503: if(REG8(AL) == 0) {
1.1.1.14 root 3504: for(int y = REG8(CH); y <= bottom; y++) {
1.1.1.16 root 3505: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 3506: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
3507: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3508: }
3509: }
3510: } else {
1.1.1.14 root 3511: for(int y = REG8(CH), y2 = min(REG8(CH) + REG8(AL), bottom + 1); y <= bottom; y++, y2++) {
1.1.1.16 root 3512: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 3513: if(y2 <= bottom) {
3514: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 3515: } else {
1.1.1.14 root 3516: SCR_BUF(y,x).Char.AsciiChar = ' ';
3517: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3518: }
1.1.1.14 root 3519: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
3520: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 3521: }
3522: }
3523: }
1.1.1.14 root 3524: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3525: }
3526:
3527: inline void pcbios_int_10h_07h()
3528: {
1.1.1.14 root 3529: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
3530: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
3531: return;
3532: }
3533: vram_flush();
3534:
1.1 root 3535: SMALL_RECT rect;
1.1.1.14 root 3536: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
3537: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
3538:
3539: int right = min(REG8(DL), scr_width - 1);
3540: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 3541:
3542: if(REG8(AL) == 0) {
1.1.1.14 root 3543: for(int y = REG8(CH); y <= bottom; y++) {
1.1.1.16 root 3544: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 3545: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
3546: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3547: }
3548: }
3549: } else {
1.1.1.14 root 3550: for(int y = bottom, y2 = max(REG8(CH) - 1, bottom - REG8(AL)); y >= REG8(CH); y--, y2--) {
1.1.1.16 root 3551: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 3552: if(y2 >= REG8(CH)) {
3553: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 3554: } else {
1.1.1.14 root 3555: SCR_BUF(y,x).Char.AsciiChar = ' ';
3556: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3557: }
1.1.1.14 root 3558: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
3559: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 3560: }
3561: }
3562: }
1.1.1.14 root 3563: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3564: }
3565:
3566: inline void pcbios_int_10h_08h()
3567: {
3568: COORD co;
3569: DWORD num;
3570:
1.1.1.14 root 3571: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3572: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 3573:
3574: if(mem[0x462] == REG8(BH)) {
1.1.1.14 root 3575: co.Y += scr_top;
3576: vram_flush();
1.1 root 3577: ReadConsoleOutputCharacter(hStdout, scr_char, 1, co, &num);
3578: ReadConsoleOutputAttribute(hStdout, scr_attr, 1, co, &num);
3579: REG8(AL) = scr_char[0];
3580: REG8(AH) = scr_attr[0];
3581: } else {
1.1.1.16 root 3582: REG16(AX) = *(UINT16 *)(mem + pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y));
1.1 root 3583: }
3584: }
3585:
3586: inline void pcbios_int_10h_09h()
3587: {
3588: COORD co;
3589:
1.1.1.14 root 3590: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3591: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
3592:
1.1.1.16 root 3593: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
3594: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 3595:
3596: if(mem[0x462] == REG8(BH)) {
1.1.1.14 root 3597: EnterCriticalSection(&vram_crit_sect);
1.1.1.16 root 3598: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 3599: while(dest < end) {
3600: write_text_vram_char(dest - vram, REG8(AL));
3601: mem[dest++] = REG8(AL);
3602: write_text_vram_attr(dest - vram, REG8(BL));
3603: mem[dest++] = REG8(BL);
1.1 root 3604: }
1.1.1.14 root 3605: LeaveCriticalSection(&vram_crit_sect);
1.1 root 3606: } else {
1.1.1.14 root 3607: while(dest < end) {
1.1 root 3608: mem[dest++] = REG8(AL);
3609: mem[dest++] = REG8(BL);
3610: }
3611: }
3612: }
3613:
3614: inline void pcbios_int_10h_0ah()
3615: {
3616: COORD co;
3617:
1.1.1.14 root 3618: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3619: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
3620:
1.1.1.16 root 3621: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
3622: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 3623:
3624: if(mem[0x462] == REG8(BH)) {
1.1.1.14 root 3625: EnterCriticalSection(&vram_crit_sect);
1.1.1.16 root 3626: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 3627: while(dest < end) {
3628: write_text_vram_char(dest - vram, REG8(AL));
3629: mem[dest++] = REG8(AL);
3630: dest++;
1.1 root 3631: }
1.1.1.14 root 3632: LeaveCriticalSection(&vram_crit_sect);
1.1 root 3633: } else {
1.1.1.14 root 3634: while(dest < end) {
1.1 root 3635: mem[dest++] = REG8(AL);
3636: dest++;
3637: }
3638: }
3639: }
3640:
3641: inline void pcbios_int_10h_0eh()
3642: {
1.1.1.14 root 3643: DWORD num;
3644: COORD co;
3645:
3646: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3647: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
3648:
3649: if(REG8(AL) == 7) {
3650: //MessageBeep(-1);
3651: } else if(REG8(AL) == 8 || REG8(AL) == 10 || REG8(AL) == 13) {
3652: if(REG8(AL) == 10) {
3653: vram_flush();
3654: }
3655: WriteConsole(hStdout, ®8(AL), 1, &num, NULL);
3656: cursor_moved = true;
3657: } else {
1.1.1.16 root 3658: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
1.1.1.14 root 3659: if(mem[0x462] == REG8(BH)) {
3660: EnterCriticalSection(&vram_crit_sect);
1.1.1.16 root 3661: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 3662: write_text_vram_char(dest - vram, REG8(AL));
3663: LeaveCriticalSection(&vram_crit_sect);
3664:
3665: if(++co.X == scr_width) {
3666: co.X = 0;
3667: if(++co.Y == scr_height) {
3668: vram_flush();
3669: WriteConsole(hStdout, "\n", 1, &num, NULL);
3670: cursor_moved = true;
3671: }
3672: }
3673: if(!cursor_moved) {
3674: co.Y += scr_top;
3675: SetConsoleCursorPosition(hStdout, co);
3676: cursor_moved = true;
3677: }
3678: }
3679: mem[dest] = REG8(AL);
3680: }
1.1 root 3681: }
3682:
3683: inline void pcbios_int_10h_0fh()
3684: {
3685: REG8(AL) = mem[0x449];
3686: REG8(AH) = mem[0x44a];
3687: REG8(BH) = mem[0x462];
3688: }
3689:
1.1.1.14 root 3690: inline void pcbios_int_10h_11h()
3691: {
3692: switch(REG8(AL)) {
1.1.1.16 root 3693: case 0x01:
1.1.1.14 root 3694: case 0x11:
1.1.1.16 root 3695: pcbios_set_console_size(80, 28, true);
1.1.1.14 root 3696: break;
1.1.1.16 root 3697: case 0x02:
1.1.1.14 root 3698: case 0x12:
1.1.1.16 root 3699: pcbios_set_console_size(80, 50, true);
1.1.1.14 root 3700: break;
1.1.1.16 root 3701: case 0x04:
1.1.1.14 root 3702: case 0x14:
1.1.1.16 root 3703: pcbios_set_console_size(80, 25, true);
3704: break;
3705: case 0x18:
3706: pcbios_set_console_size(80, 50, true);
1.1.1.14 root 3707: break;
3708: case 0x30:
3709: SREG(ES) = 0;
3710: i386_load_segment_descriptor(ES);
3711: REG16(BP) = 0;
3712: REG16(CX) = mem[0x485];
3713: REG8(DL) = mem[0x484];
3714: break;
3715: }
3716: }
3717:
3718: inline void pcbios_int_10h_12h()
3719: {
1.1.1.16 root 3720: switch(REG8(BL)) {
3721: case 0x10:
1.1.1.14 root 3722: REG16(BX) = 0x0003;
3723: REG16(CX) = 0x0009;
1.1.1.16 root 3724: break;
1.1.1.14 root 3725: }
3726: }
3727:
1.1 root 3728: inline void pcbios_int_10h_13h()
3729: {
1.1.1.3 root 3730: int ofs = SREG_BASE(ES) + REG16(BP);
1.1 root 3731: COORD co;
3732: DWORD num;
3733:
3734: co.X = REG8(DL);
1.1.1.14 root 3735: co.Y = REG8(DH) + scr_top;
3736:
3737: vram_flush();
1.1 root 3738:
3739: switch(REG8(AL)) {
3740: case 0x00:
3741: case 0x01:
3742: if(mem[0x462] == REG8(BH)) {
3743: CONSOLE_SCREEN_BUFFER_INFO csbi;
3744: GetConsoleScreenBufferInfo(hStdout, &csbi);
3745: SetConsoleCursorPosition(hStdout, co);
3746:
3747: if(csbi.wAttributes != REG8(BL)) {
3748: SetConsoleTextAttribute(hStdout, REG8(BL));
3749: }
1.1.1.14 root 3750: WriteConsole(hStdout, &mem[ofs], REG16(CX), &num, NULL);
3751:
1.1 root 3752: if(csbi.wAttributes != REG8(BL)) {
3753: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
3754: }
3755: if(REG8(AL) == 0x00) {
1.1.1.15 root 3756: if(!restore_console_on_exit) {
3757: GetConsoleScreenBufferInfo(hStdout, &csbi);
3758: scr_top = csbi.srWindow.Top;
3759: }
1.1.1.14 root 3760: co.X = mem[0x450 + REG8(BH) * 2];
3761: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 3762: SetConsoleCursorPosition(hStdout, co);
3763: } else {
3764: cursor_moved = true;
3765: }
3766: } else {
1.1.1.3 root 3767: m_CF = 1;
1.1 root 3768: }
3769: break;
3770: case 0x02:
3771: case 0x03:
3772: if(mem[0x462] == REG8(BH)) {
3773: CONSOLE_SCREEN_BUFFER_INFO csbi;
3774: GetConsoleScreenBufferInfo(hStdout, &csbi);
3775: SetConsoleCursorPosition(hStdout, co);
3776:
3777: WORD wAttributes = csbi.wAttributes;
3778: for(int i = 0; i < REG16(CX); i++, ofs += 2) {
3779: if(wAttributes != mem[ofs + 1]) {
3780: SetConsoleTextAttribute(hStdout, mem[ofs + 1]);
3781: wAttributes = mem[ofs + 1];
3782: }
1.1.1.14 root 3783: WriteConsole(hStdout, &mem[ofs], 1, &num, NULL);
1.1 root 3784: }
3785: if(csbi.wAttributes != wAttributes) {
3786: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
3787: }
3788: if(REG8(AL) == 0x02) {
1.1.1.14 root 3789: co.X = mem[0x450 + REG8(BH) * 2];
3790: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 3791: SetConsoleCursorPosition(hStdout, co);
3792: } else {
3793: cursor_moved = true;
3794: }
3795: } else {
1.1.1.3 root 3796: m_CF = 1;
1.1 root 3797: }
3798: break;
3799: case 0x10:
3800: case 0x11:
3801: if(mem[0x462] == REG8(BH)) {
3802: ReadConsoleOutputCharacter(hStdout, scr_char, REG16(CX), co, &num);
3803: ReadConsoleOutputAttribute(hStdout, scr_attr, REG16(CX), co, &num);
3804: for(int i = 0; i < num; i++) {
3805: mem[ofs++] = scr_char[i];
3806: mem[ofs++] = scr_attr[i];
3807: if(REG8(AL) == 0x11) {
3808: mem[ofs++] = 0;
3809: mem[ofs++] = 0;
3810: }
3811: }
3812: } else {
1.1.1.16 root 3813: 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 3814: mem[ofs++] = mem[src++];
3815: mem[ofs++] = mem[src++];
3816: if(REG8(AL) == 0x11) {
3817: mem[ofs++] = 0;
3818: mem[ofs++] = 0;
3819: }
1.1.1.14 root 3820: if(++co.X == scr_width) {
3821: if(++co.Y == scr_height) {
1.1 root 3822: break;
3823: }
3824: co.X = 0;
3825: }
3826: }
3827: }
3828: break;
3829: case 0x20:
3830: case 0x21:
3831: if(mem[0x462] == REG8(BH)) {
1.1.1.14 root 3832: int len = min(REG16(CX), scr_width * scr_height);
3833: for(int i = 0; i < len; i++) {
1.1 root 3834: scr_char[i] = mem[ofs++];
3835: scr_attr[i] = mem[ofs++];
3836: if(REG8(AL) == 0x21) {
3837: ofs += 2;
3838: }
3839: }
1.1.1.14 root 3840: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
3841: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 3842: } else {
1.1.1.16 root 3843: 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 3844: mem[dest++] = mem[ofs++];
3845: mem[dest++] = mem[ofs++];
3846: if(REG8(AL) == 0x21) {
3847: ofs += 2;
3848: }
1.1.1.14 root 3849: if(++co.X == scr_width) {
3850: if(++co.Y == scr_height) {
1.1 root 3851: break;
3852: }
3853: co.X = 0;
3854: }
3855: }
3856: }
3857: break;
3858: default:
1.1.1.22! root 3859: 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 3860: m_CF = 1;
1.1 root 3861: break;
3862: }
3863: }
3864:
1.1.1.14 root 3865: inline void pcbios_int_10h_1ah()
3866: {
3867: switch(REG8(AL)) {
3868: case 0x00:
3869: REG8(AL) = 0x1a;
3870: REG8(BL) = 0x08;
3871: REG8(BH) = 0x00;
3872: break;
3873: default:
1.1.1.22! root 3874: 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 3875: m_CF = 1;
3876: break;
3877: }
3878: }
3879:
1.1 root 3880: inline void pcbios_int_10h_1dh()
3881: {
3882: switch(REG8(AL)) {
3883: case 0x01:
3884: break;
3885: case 0x02:
3886: REG16(BX) = 0;
3887: break;
3888: default:
1.1.1.22! root 3889: 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));
! 3890: m_CF = 1;
! 3891: break;
! 3892: }
! 3893: }
! 3894:
! 3895: inline void pcbios_int_10h_4fh()
! 3896: {
! 3897: switch(REG8(AL)) {
! 3898: case 0x00:
! 3899: REG8(AH) = 0x02; // not supported
! 3900: break;
! 3901: case 0x01:
! 3902: case 0x02:
! 3903: case 0x03:
! 3904: case 0x04:
! 3905: case 0x05:
! 3906: case 0x06:
! 3907: case 0x07:
! 3908: case 0x08:
! 3909: case 0x09:
! 3910: case 0x0a:
! 3911: case 0x0b:
! 3912: case 0x0c:
! 3913: REG8(AH) = 0x01; // failed
! 3914: break;
! 3915: default:
! 3916: 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 3917: m_CF = 1;
1.1 root 3918: break;
3919: }
3920: }
3921:
3922: inline void pcbios_int_10h_82h()
3923: {
3924: static UINT8 mode = 0;
3925:
3926: switch(REG8(AL)) {
1.1.1.22! root 3927: case 0x00:
1.1 root 3928: if(REG8(BL) != 0xff) {
3929: mode = REG8(BL);
3930: }
3931: REG8(AL) = mode;
3932: break;
3933: default:
1.1.1.22! root 3934: 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 3935: m_CF = 1;
1.1 root 3936: break;
3937: }
3938: }
3939:
1.1.1.22! root 3940: inline void pcbios_int_10h_83h()
! 3941: {
! 3942: static UINT8 mode = 0;
! 3943:
! 3944: switch(REG8(AL)) {
! 3945: case 0x00:
! 3946: REG16(AX) = 0; // offset???
! 3947: SREG(ES) = (SHADOW_BUF_TOP >> 4);
! 3948: i386_load_segment_descriptor(ES);
! 3949: REG16(BX) = (SHADOW_BUF_TOP & 0x0f);
! 3950: break;
! 3951: default:
! 3952: 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));
! 3953: m_CF = 1;
! 3954: break;
! 3955: }
! 3956: }
! 3957:
! 3958: inline void pcbios_int_10h_90h()
! 3959: {
! 3960: REG8(AL) = mem[0x449];
! 3961: }
! 3962:
! 3963: inline void pcbios_int_10h_91h()
! 3964: {
! 3965: REG8(AL) = 0x04; // VGA
! 3966: }
! 3967:
! 3968: inline void pcbios_int_10h_efh()
! 3969: {
! 3970: REG16(DX) = 0xffff;
! 3971: }
! 3972:
1.1 root 3973: inline void pcbios_int_10h_feh()
3974: {
3975: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 3976: SREG(ES) = (SHADOW_BUF_TOP >> 4);
1.1.1.3 root 3977: i386_load_segment_descriptor(ES);
1.1.1.8 root 3978: REG16(DI) = (SHADOW_BUF_TOP & 0x0f);
1.1 root 3979: }
3980: int_10h_feh_called = true;
3981: }
3982:
3983: inline void pcbios_int_10h_ffh()
3984: {
3985: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
3986: COORD co;
3987: DWORD num;
3988:
1.1.1.14 root 3989: vram_flush();
3990:
3991: co.X = (REG16(DI) >> 1) % scr_width;
3992: co.Y = (REG16(DI) >> 1) / scr_width;
1.1.1.16 root 3993: int ofs = pcbios_get_shadow_buffer_address(0, co.X, co.Y);
3994: int end = min(ofs + REG16(CX) * 2, pcbios_get_shadow_buffer_address(0, 0, scr_height));
1.1.1.14 root 3995: int len;
3996: for(len = 0; ofs < end; len++) {
3997: scr_char[len] = mem[ofs++];
3998: scr_attr[len] = mem[ofs++];
3999: }
4000: co.Y += scr_top;
4001: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
4002: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 4003: }
4004: int_10h_ffh_called = true;
4005: }
4006:
1.1.1.14 root 4007: inline void pcbios_int_15h_10h()
4008: {
1.1.1.22! root 4009: switch(REG8(AL)) {
! 4010: case 0x00:
1.1.1.14 root 4011: Sleep(10);
4012: hardware_update();
1.1.1.22! root 4013: break;
! 4014: default:
! 4015: 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 4016: REG8(AH) = 0x86;
4017: m_CF = 1;
4018: }
4019: }
4020:
1.1 root 4021: inline void pcbios_int_15h_23h()
4022: {
4023: switch(REG8(AL)) {
1.1.1.22! root 4024: case 0x00:
1.1.1.8 root 4025: REG8(CL) = cmos_read(0x2d);
4026: REG8(CH) = cmos_read(0x2e);
1.1 root 4027: break;
1.1.1.22! root 4028: case 0x01:
1.1.1.8 root 4029: cmos_write(0x2d, REG8(CL));
4030: cmos_write(0x2e, REG8(CH));
1.1 root 4031: break;
4032: default:
1.1.1.22! root 4033: 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 4034: REG8(AH) = 0x86;
1.1.1.3 root 4035: m_CF = 1;
1.1 root 4036: break;
4037: }
4038: }
4039:
4040: inline void pcbios_int_15h_24h()
4041: {
4042: switch(REG8(AL)) {
1.1.1.22! root 4043: case 0x00:
1.1.1.3 root 4044: i386_set_a20_line(0);
1.1 root 4045: REG8(AH) = 0;
4046: break;
1.1.1.22! root 4047: case 0x01:
1.1.1.3 root 4048: i386_set_a20_line(1);
1.1 root 4049: REG8(AH) = 0;
4050: break;
1.1.1.22! root 4051: case 0x02:
1.1 root 4052: REG8(AH) = 0;
1.1.1.3 root 4053: REG8(AL) = (m_a20_mask >> 20) & 1;
1.1 root 4054: REG16(CX) = 0;
4055: break;
1.1.1.22! root 4056: case 0x03:
1.1 root 4057: REG16(AX) = 0;
4058: REG16(BX) = 0;
4059: break;
1.1.1.22! root 4060: default:
! 4061: 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));
! 4062: REG8(AH) = 0x86;
! 4063: m_CF = 1;
! 4064: break;
1.1 root 4065: }
4066: }
4067:
4068: inline void pcbios_int_15h_49h()
4069: {
1.1.1.14 root 4070: REG8(AH) = 0;
4071: REG8(BL) = 0; // DOS/V
1.1 root 4072: }
4073:
1.1.1.22! root 4074: inline void pcbios_int_15h_50h()
! 4075: {
! 4076: switch(REG8(AL)) {
! 4077: case 0x00:
! 4078: case 0x01:
! 4079: if(REG8(BH) != 0x00 && REG8(BH) != 0x01) {
! 4080: REG8(AH) = 0x01; // invalid font type in bh
! 4081: m_CF = 1;
! 4082: } else if(REG8(BL) != 0) {
! 4083: REG8(AH) = 0x02; // bl not zero
! 4084: m_CF = 1;
! 4085: } else if(REG16(BP) != 0 && REG16(BP) != 437 && REG16(BP) != 932 && REG16(BP) != 934 && REG16(BP) != 936 && REG16(BP) != 938) {
! 4086: REG8(AH) = 0x04; // invalid code page
! 4087: m_CF = 1;
! 4088: } else {
! 4089: REG8(AH) = 0x86; // finally, this function is not supported
! 4090: m_CF = 1;
! 4091: }
! 4092: break;
! 4093: default:
! 4094: 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));
! 4095: REG8(AH) = 0x86;
! 4096: m_CF = 1;
! 4097: break;
! 4098: }
! 4099: }
! 4100:
1.1 root 4101: inline void pcbios_int_15h_86h()
4102: {
4103: UINT32 usec = (REG16(CX) << 16) | REG16(DX);
1.1.1.14 root 4104: UINT32 msec = usec / 1000;
4105:
4106: while(msec) {
4107: UINT32 tmp = min(msec, 100);
4108: if(msec - tmp < 10) {
4109: tmp = msec;
4110: }
4111: Sleep(tmp);
4112:
4113: if(m_halted) {
4114: return;
4115: }
4116: msec -= tmp;
4117: }
1.1 root 4118: }
4119:
4120: inline void pcbios_int_15h_87h()
4121: {
4122: // copy extended memory (from DOSBox)
4123: int len = REG16(CX) * 2;
1.1.1.3 root 4124: int ofs = SREG_BASE(ES) + REG16(SI);
1.1 root 4125: int src = (*(UINT32 *)(mem + ofs + 0x12) & 0xffffff); // + (mem[ofs + 0x16] << 24);
4126: int dst = (*(UINT32 *)(mem + ofs + 0x1a) & 0xffffff); // + (mem[ofs + 0x1e] << 24);
4127: memcpy(mem + dst, mem + src, len);
4128: REG16(AX) = 0x00;
4129: }
4130:
4131: inline void pcbios_int_15h_88h()
4132: {
1.1.1.17 root 4133: REG16(AX) = ((min(MAX_MEM, 0x4000000) - 0x100000) >> 10);
1.1 root 4134: }
4135:
4136: inline void pcbios_int_15h_89h()
4137: {
1.1.1.21 root 4138: #if defined(HAS_I286) || defined(HAS_I386)
1.1 root 4139: // switch to protected mode (from DOSBox)
4140: write_io_byte(0x20, 0x10);
4141: write_io_byte(0x21, REG8(BH));
4142: write_io_byte(0x21, 0x00);
4143: write_io_byte(0xa0, 0x10);
4144: write_io_byte(0xa1, REG8(BL));
4145: write_io_byte(0xa1, 0x00);
1.1.1.3 root 4146: i386_set_a20_line(1);
4147: int ofs = SREG_BASE(ES) + REG16(SI);
4148: m_gdtr.limit = *(UINT16 *)(mem + ofs + 0x08);
4149: m_gdtr.base = *(UINT32 *)(mem + ofs + 0x08 + 0x02) & 0xffffff;
4150: m_idtr.limit = *(UINT16 *)(mem + ofs + 0x10);
4151: m_idtr.base = *(UINT32 *)(mem + ofs + 0x10 + 0x02) & 0xffffff;
4152: #if defined(HAS_I386)
4153: m_cr[0] |= 1;
4154: #else
4155: m_msw |= 1;
4156: #endif
4157: SREG(DS) = 0x18;
4158: SREG(ES) = 0x20;
4159: SREG(SS) = 0x28;
4160: i386_load_segment_descriptor(DS);
4161: i386_load_segment_descriptor(ES);
4162: i386_load_segment_descriptor(SS);
1.1.1.21 root 4163: UINT16 offset = *(UINT16 *)(mem + SREG_BASE(SS) + REG16(SP));
1.1 root 4164: REG16(SP) += 6;
1.1.1.3 root 4165: #if defined(HAS_I386)
1.1.1.21 root 4166: UINT32 flags = get_flags();
4167: flags &= (0x20000 | 0x40000 | 0x80000 | 0x100000 | 0x200000);
4168: set_flags(flags);
1.1.1.3 root 4169: #else
1.1.1.21 root 4170: UINT32 flags = CompressFlags();
4171: flags &= (0x20000 | 0x40000 | 0x80000 | 0x100000 | 0x200000);
4172: ExpandFlags(flags);
1.1.1.3 root 4173: #endif
1.1 root 4174: REG16(AX) = 0x00;
1.1.1.21 root 4175: i386_jmp_far(0x30, /*REG16(CX)*/offset);
1.1 root 4176: #else
1.1.1.21 root 4177: // i86/i186/v30: protected mode is not supported
1.1 root 4178: REG8(AH) = 0x86;
1.1.1.3 root 4179: m_CF = 1;
1.1 root 4180: #endif
4181: }
4182:
1.1.1.21 root 4183: inline void pcbios_int_15h_8ah()
4184: {
4185: UINT32 size = MAX_MEM - 0x100000;
4186: REG16(AX) = size & 0xffff;
4187: REG16(DX) = size >> 16;
4188: }
4189:
1.1.1.3 root 4190: #if defined(HAS_I386)
1.1 root 4191: inline void pcbios_int_15h_c9h()
4192: {
4193: REG8(AH) = 0x00;
4194: REG8(CH) = cpu_type;
4195: REG8(CL) = cpu_step;
4196: }
1.1.1.3 root 4197: #endif
1.1 root 4198:
4199: inline void pcbios_int_15h_cah()
4200: {
4201: switch(REG8(AL)) {
1.1.1.22! root 4202: case 0x00:
1.1 root 4203: if(REG8(BL) > 0x3f) {
4204: REG8(AH) = 0x03;
1.1.1.3 root 4205: m_CF = 1;
1.1 root 4206: } else if(REG8(BL) < 0x0e) {
4207: REG8(AH) = 0x04;
1.1.1.3 root 4208: m_CF = 1;
1.1 root 4209: } else {
1.1.1.8 root 4210: REG8(CL) = cmos_read(REG8(BL));
1.1 root 4211: }
4212: break;
1.1.1.22! root 4213: case 0x01:
1.1 root 4214: if(REG8(BL) > 0x3f) {
4215: REG8(AH) = 0x03;
1.1.1.3 root 4216: m_CF = 1;
1.1 root 4217: } else if(REG8(BL) < 0x0e) {
4218: REG8(AH) = 0x04;
1.1.1.3 root 4219: m_CF = 1;
1.1 root 4220: } else {
1.1.1.8 root 4221: cmos_write(REG8(BL), REG8(CL));
1.1 root 4222: }
4223: break;
4224: default:
1.1.1.22! root 4225: 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 4226: REG8(AH) = 0x86;
1.1.1.3 root 4227: m_CF = 1;
1.1 root 4228: break;
4229: }
4230: }
4231:
1.1.1.22! root 4232: inline void pcbios_int_15h_e8h()
1.1.1.17 root 4233: {
1.1.1.22! root 4234: switch(REG8(AL)) {
! 4235: #if defined(HAS_I386)
! 4236: case 0x01:
! 4237: REG16(AX) = REG16(CX) = ((min(MAX_MEM, 0x1000000) - 0x100000) >> 10);
! 4238: REG16(BX) = REG16(DX) = ((max(MAX_MEM, 0x1000000) - 0x1000000) >> 16);
! 4239: break;
1.1.1.17 root 4240: #endif
1.1.1.22! root 4241: default:
! 4242: 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));
! 4243: REG8(AH) = 0x86;
! 4244: m_CF = 1;
! 4245: break;
! 4246: }
! 4247: }
1.1.1.17 root 4248:
1.1.1.16 root 4249: UINT32 pcbios_get_key_code(bool clear_buffer)
1.1 root 4250: {
4251: UINT32 code = 0;
4252:
4253: if(key_buf_char->count() == 0) {
1.1.1.14 root 4254: if(!update_key_buffer()) {
4255: if(clear_buffer) {
4256: Sleep(10);
4257: } else {
4258: maybe_idle();
4259: }
4260: }
1.1 root 4261: }
4262: if(!clear_buffer) {
4263: key_buf_char->store_buffer();
4264: key_buf_scan->store_buffer();
4265: }
4266: if(key_buf_char->count() != 0) {
4267: code = key_buf_char->read() | (key_buf_scan->read() << 8);
4268: }
4269: if(key_buf_char->count() != 0) {
4270: code |= (key_buf_char->read() << 16) | (key_buf_scan->read() << 24);
4271: }
4272: if(!clear_buffer) {
4273: key_buf_char->restore_buffer();
4274: key_buf_scan->restore_buffer();
4275: }
4276: return code;
4277: }
4278:
4279: inline void pcbios_int_16h_00h()
4280: {
1.1.1.14 root 4281: while(key_code == 0 && !m_halted) {
1.1.1.16 root 4282: key_code = pcbios_get_key_code(true);
1.1 root 4283: }
4284: if((key_code & 0xffff) == 0x0000 || (key_code & 0xffff) == 0xe000) {
4285: if(REG8(AH) == 0x10) {
4286: key_code = ((key_code >> 8) & 0xff) | ((key_code >> 16) & 0xff00);
4287: } else {
4288: key_code = ((key_code >> 16) & 0xff00);
4289: }
4290: }
4291: REG16(AX) = key_code & 0xffff;
4292: key_code >>= 16;
4293: }
4294:
4295: inline void pcbios_int_16h_01h()
4296: {
1.1.1.5 root 4297: UINT32 key_code_tmp = key_code;
1.1 root 4298:
1.1.1.5 root 4299: if(key_code_tmp == 0) {
1.1.1.16 root 4300: key_code_tmp = pcbios_get_key_code(false);
1.1.1.5 root 4301: }
1.1.1.14 root 4302: if((key_code_tmp & 0xffff) == 0x0000 || (key_code_tmp & 0xffff) == 0xe000) {
4303: if(REG8(AH) == 0x11) {
4304: key_code_tmp = ((key_code_tmp >> 8) & 0xff) | ((key_code_tmp >> 16) & 0xff00);
4305: } else {
4306: key_code_tmp = ((key_code_tmp >> 16) & 0xff00);
1.1 root 4307: }
4308: }
1.1.1.5 root 4309: if(key_code_tmp != 0) {
4310: REG16(AX) = key_code_tmp & 0xffff;
1.1 root 4311: }
1.1.1.3 root 4312: #if defined(HAS_I386)
1.1.1.5 root 4313: m_ZF = (key_code_tmp == 0);
1.1.1.3 root 4314: #else
1.1.1.5 root 4315: m_ZeroVal = (key_code_tmp != 0);
1.1.1.3 root 4316: #endif
1.1 root 4317: }
4318:
4319: inline void pcbios_int_16h_02h()
4320: {
4321: REG8(AL) = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
4322: REG8(AL) |= (GetAsyncKeyState(VK_CAPITAL) & 0x0001) ? 0x40 : 0;
4323: REG8(AL) |= (GetAsyncKeyState(VK_NUMLOCK) & 0x0001) ? 0x20 : 0;
4324: REG8(AL) |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
4325: REG8(AL) |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
4326: REG8(AL) |= (GetAsyncKeyState(VK_CONTROL) & 0x8000) ? 0x04 : 0;
4327: REG8(AL) |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
4328: REG8(AL) |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
4329: }
4330:
4331: inline void pcbios_int_16h_03h()
4332: {
4333: static UINT16 status = 0;
4334:
4335: switch(REG8(AL)) {
4336: case 0x05:
4337: status = REG16(BX);
4338: break;
4339: case 0x06:
4340: REG16(BX) = status;
4341: break;
4342: default:
1.1.1.3 root 4343: m_CF = 1;
1.1 root 4344: break;
4345: }
4346: }
4347:
4348: inline void pcbios_int_16h_05h()
4349: {
1.1.1.14 root 4350: key_buf_char->write(REG8(CL));
4351: key_buf_scan->write(REG8(CH));
1.1 root 4352: REG8(AL) = 0x00;
4353: }
4354:
4355: inline void pcbios_int_16h_12h()
4356: {
4357: pcbios_int_16h_02h();
4358:
4359: REG8(AH) = 0;//(GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x80 : 0;
4360: REG8(AH) |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
4361: REG8(AH) |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
4362: REG8(AH) |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
4363: REG8(AH) |= (GetAsyncKeyState(VK_RMENU ) & 0x8000) ? 0x08 : 0;
4364: REG8(AH) |= (GetAsyncKeyState(VK_RCONTROL) & 0x8000) ? 0x04 : 0;
4365: REG8(AH) |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
4366: REG8(AH) |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
4367: }
4368:
4369: inline void pcbios_int_16h_13h()
4370: {
4371: static UINT16 status = 0;
4372:
4373: switch(REG8(AL)) {
4374: case 0x00:
4375: status = REG16(DX);
4376: break;
4377: case 0x01:
4378: REG16(DX) = status;
4379: break;
4380: default:
1.1.1.22! root 4381: 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 4382: m_CF = 1;
1.1 root 4383: break;
4384: }
4385: }
4386:
4387: inline void pcbios_int_16h_14h()
4388: {
4389: static UINT8 status = 0;
4390:
4391: switch(REG8(AL)) {
4392: case 0x00:
4393: case 0x01:
4394: status = REG8(AL);
4395: break;
4396: case 0x02:
4397: REG8(AL) = status;
4398: break;
4399: default:
1.1.1.22! root 4400: 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 4401: m_CF = 1;
1.1 root 4402: break;
4403: }
4404: }
4405:
4406: inline void pcbios_int_1ah_00h()
4407: {
1.1.1.19 root 4408: pcbios_update_daily_timer_counter(timeGetTime());
4409: REG16(CX) = *(UINT16 *)(mem + 0x46e);
4410: REG16(DX) = *(UINT16 *)(mem + 0x46c);
4411: REG8(AL) = mem[0x470];
4412: mem[0x470] = 0;
1.1 root 4413: }
4414:
4415: inline int to_bcd(int t)
4416: {
4417: int u = (t % 100) / 10;
4418: return (u << 4) | (t % 10);
4419: }
4420:
4421: inline void pcbios_int_1ah_02h()
4422: {
4423: SYSTEMTIME time;
4424:
4425: GetLocalTime(&time);
4426: REG8(CH) = to_bcd(time.wHour);
4427: REG8(CL) = to_bcd(time.wMinute);
4428: REG8(DH) = to_bcd(time.wSecond);
4429: REG8(DL) = 0x00;
4430: }
4431:
4432: inline void pcbios_int_1ah_04h()
4433: {
4434: SYSTEMTIME time;
4435:
4436: GetLocalTime(&time);
4437: REG8(CH) = to_bcd(time.wYear / 100);
4438: REG8(CL) = to_bcd(time.wYear);
4439: REG8(DH) = to_bcd(time.wMonth);
4440: REG8(DL) = to_bcd(time.wDay);
4441: }
4442:
4443: inline void pcbios_int_1ah_0ah()
4444: {
4445: SYSTEMTIME time;
4446: FILETIME file_time;
4447: WORD dos_date, dos_time;
4448:
4449: GetLocalTime(&time);
4450: SystemTimeToFileTime(&time, &file_time);
4451: FileTimeToDosDateTime(&file_time, &dos_date, &dos_time);
4452: REG16(CX) = dos_date;
4453: }
4454:
4455: // msdos system call
4456:
4457: inline void msdos_int_21h_00h()
4458: {
1.1.1.3 root 4459: msdos_process_terminate(SREG(CS), retval, 1);
1.1 root 4460: }
4461:
4462: inline void msdos_int_21h_01h()
4463: {
4464: REG8(AL) = msdos_getche();
1.1.1.8 root 4465: // some seconds may be passed in console
1.1 root 4466: hardware_update();
4467: }
4468:
4469: inline void msdos_int_21h_02h()
4470: {
4471: msdos_putch(REG8(DL));
4472: }
4473:
4474: inline void msdos_int_21h_03h()
4475: {
4476: REG8(AL) = msdos_aux_in();
4477: }
4478:
4479: inline void msdos_int_21h_04h()
4480: {
4481: msdos_aux_out(REG8(DL));
4482: }
4483:
4484: inline void msdos_int_21h_05h()
4485: {
4486: msdos_prn_out(REG8(DL));
4487: }
4488:
4489: inline void msdos_int_21h_06h()
4490: {
4491: if(REG8(DL) == 0xff) {
4492: if(msdos_kbhit()) {
4493: REG8(AL) = msdos_getch();
1.1.1.3 root 4494: #if defined(HAS_I386)
4495: m_ZF = 0;
4496: #else
4497: m_ZeroVal = 1;
4498: #endif
1.1 root 4499: } else {
4500: REG8(AL) = 0;
1.1.1.3 root 4501: #if defined(HAS_I386)
4502: m_ZF = 1;
4503: #else
4504: m_ZeroVal = 0;
4505: #endif
1.1.1.14 root 4506: maybe_idle();
1.1 root 4507: }
4508: } else {
4509: msdos_putch(REG8(DL));
4510: }
4511: }
4512:
4513: inline void msdos_int_21h_07h()
4514: {
4515: REG8(AL) = msdos_getch();
1.1.1.8 root 4516: // some seconds may be passed in console
1.1 root 4517: hardware_update();
4518: }
4519:
4520: inline void msdos_int_21h_08h()
4521: {
4522: REG8(AL) = msdos_getch();
1.1.1.8 root 4523: // some seconds may be passed in console
1.1 root 4524: hardware_update();
4525: }
4526:
4527: inline void msdos_int_21h_09h()
4528: {
1.1.1.21 root 4529: msdos_stdio_reopen();
4530:
1.1.1.20 root 4531: process_t *process = msdos_process_info_get(current_psp);
4532: int fd = msdos_psp_get_file_table(1, current_psp);
4533:
1.1.1.14 root 4534: char *str = (char *)(mem + SREG_BASE(DS) + REG16(DX));
4535: int len = 0;
1.1 root 4536:
1.1.1.14 root 4537: while(str[len] != '$' && len < 0x10000) {
4538: len++;
4539: }
1.1.1.20 root 4540: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 4541: // stdout is redirected to file
1.1.1.20 root 4542: msdos_write(fd, str, len);
1.1 root 4543: } else {
4544: for(int i = 0; i < len; i++) {
1.1.1.14 root 4545: msdos_putch(str[i]);
1.1 root 4546: }
4547: }
4548: }
4549:
4550: inline void msdos_int_21h_0ah()
4551: {
1.1.1.3 root 4552: int ofs = SREG_BASE(DS) + REG16(DX);
1.1 root 4553: int max = mem[ofs] - 1;
4554: UINT8 *buf = mem + ofs + 2;
4555: int chr, p = 0;
4556:
4557: while((chr = msdos_getch()) != 0x0d) {
4558: if(chr == 0x00) {
4559: // skip 2nd byte
4560: msdos_getch();
4561: } else if(chr == 0x08) {
4562: // back space
4563: if(p > 0) {
4564: p--;
1.1.1.20 root 4565: if(msdos_ctrl_code_check(buf[p])) {
4566: msdos_putch(chr);
4567: msdos_putch(chr);
4568: msdos_putch(' ');
4569: msdos_putch(' ');
4570: msdos_putch(chr);
4571: msdos_putch(chr);
4572: } else {
4573: msdos_putch(chr);
4574: msdos_putch(' ');
4575: msdos_putch(chr);
4576: }
1.1 root 4577: }
4578: } else if(p < max) {
4579: buf[p++] = chr;
4580: msdos_putch(chr);
4581: }
4582: }
4583: buf[p] = 0x0d;
4584: mem[ofs + 1] = p;
1.1.1.8 root 4585: // some seconds may be passed in console
1.1 root 4586: hardware_update();
4587: }
4588:
4589: inline void msdos_int_21h_0bh()
4590: {
4591: if(msdos_kbhit()) {
4592: REG8(AL) = 0xff;
4593: } else {
4594: REG8(AL) = 0x00;
1.1.1.14 root 4595: maybe_idle();
1.1 root 4596: }
4597: }
4598:
4599: inline void msdos_int_21h_0ch()
4600: {
4601: // clear key buffer
1.1.1.21 root 4602: msdos_stdio_reopen();
4603:
1.1.1.20 root 4604: process_t *process = msdos_process_info_get(current_psp);
4605: int fd = msdos_psp_get_file_table(0, current_psp);
4606:
4607: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 4608: // stdin is redirected to file
4609: } else {
4610: while(msdos_kbhit()) {
4611: msdos_getch();
4612: }
4613: }
4614:
4615: switch(REG8(AL)) {
4616: case 0x01:
4617: msdos_int_21h_01h();
4618: break;
4619: case 0x06:
4620: msdos_int_21h_06h();
4621: break;
4622: case 0x07:
4623: msdos_int_21h_07h();
4624: break;
4625: case 0x08:
4626: msdos_int_21h_08h();
4627: break;
4628: case 0x0a:
4629: msdos_int_21h_0ah();
4630: break;
4631: default:
1.1.1.22! root 4632: // 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));
! 4633: // REG16(AX) = 0x01;
! 4634: // m_CF = 1;
1.1 root 4635: break;
4636: }
4637: }
4638:
4639: inline void msdos_int_21h_0dh()
4640: {
4641: }
4642:
4643: inline void msdos_int_21h_0eh()
4644: {
4645: if(REG8(DL) < 26) {
4646: _chdrive(REG8(DL) + 1);
4647: msdos_cds_update(REG8(DL));
4648: }
4649: REG8(AL) = 26; // zdrive
4650: }
4651:
1.1.1.14 root 4652: inline void msdos_int_21h_0fh()
4653: {
4654: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4655: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
4656: char *path = msdos_fcb_path(fcb);
4657: 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 4658:
1.1.1.14 root 4659: if(hFile == INVALID_HANDLE_VALUE) {
4660: REG8(AL) = 0xff;
4661: } else {
4662: REG8(AL) = 0;
4663: fcb->current_block = 0;
4664: fcb->record_size = 128;
4665: fcb->file_size = GetFileSize(hFile, NULL);
4666: fcb->handle = hFile;
4667: fcb->cur_record = 0;
4668: }
4669: }
4670:
4671: inline void msdos_int_21h_10h()
4672: {
4673: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4674: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
4675:
4676: REG8(AL) = CloseHandle(fcb->handle) ? 0 : 0xff;
4677: }
4678:
1.1 root 4679: inline void msdos_int_21h_11h()
4680: {
1.1.1.3 root 4681: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4682: fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 4683:
4684: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 4685: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
4686: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
4687: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 4688: char *path = msdos_fcb_path(fcb);
4689: WIN32_FIND_DATA fd;
4690:
1.1.1.13 root 4691: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
4692: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
4693: FindClose(dtainfo->find_handle);
4694: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 4695: }
4696: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 4697: dtainfo->allowable_mask = (ext_fcb->flag == 0xff) ? ext_fcb->attribute : 0x20;
4698: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 4699:
1.1.1.14 root 4700: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
4701: dtainfo->allowable_mask &= ~8;
1.1 root 4702: }
1.1.1.14 root 4703: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
4704: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 4705: !msdos_find_file_has_8dot3name(&fd)) {
4706: if(!FindNextFile(dtainfo->find_handle, &fd)) {
4707: FindClose(dtainfo->find_handle);
4708: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 4709: break;
4710: }
4711: }
4712: }
1.1.1.13 root 4713: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 4714: if(ext_fcb->flag == 0xff) {
4715: ext_find->flag = 0xff;
4716: memset(ext_find->reserved, 0, 5);
4717: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
4718: }
4719: find->drive = _getdrive();
1.1.1.13 root 4720: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 4721: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
4722: find->nt_res = 0;
4723: msdos_find_file_conv_local_time(&fd);
4724: find->create_time_ms = 0;
4725: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
4726: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
4727: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
4728: find->cluster_hi = find->cluster_lo = 0;
4729: find->file_size = fd.nFileSizeLow;
4730: REG8(AL) = 0x00;
1.1.1.14 root 4731: } else if(dtainfo->allowable_mask & 8) {
1.1 root 4732: if(ext_fcb->flag == 0xff) {
4733: ext_find->flag = 0xff;
4734: memset(ext_find->reserved, 0, 5);
4735: ext_find->attribute = 8;
4736: }
4737: find->drive = _getdrive();
4738: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
4739: find->attribute = 8;
4740: find->nt_res = 0;
4741: msdos_find_file_conv_local_time(&fd);
4742: find->create_time_ms = 0;
4743: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
4744: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
4745: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
4746: find->cluster_hi = find->cluster_lo = 0;
4747: find->file_size = 0;
1.1.1.14 root 4748: dtainfo->allowable_mask &= ~8;
1.1 root 4749: REG8(AL) = 0x00;
4750: } else {
4751: REG8(AL) = 0xff;
4752: }
4753: }
4754:
4755: inline void msdos_int_21h_12h()
4756: {
1.1.1.3 root 4757: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1.1.14 root 4758: // fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 4759:
4760: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 4761: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
4762: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
4763: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 4764: WIN32_FIND_DATA fd;
4765:
1.1.1.13 root 4766: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
4767: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
4768: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 4769: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 4770: !msdos_find_file_has_8dot3name(&fd)) {
4771: if(!FindNextFile(dtainfo->find_handle, &fd)) {
4772: FindClose(dtainfo->find_handle);
4773: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 4774: break;
4775: }
4776: }
4777: } else {
1.1.1.13 root 4778: FindClose(dtainfo->find_handle);
4779: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 4780: }
4781: }
1.1.1.13 root 4782: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 4783: if(ext_fcb->flag == 0xff) {
4784: ext_find->flag = 0xff;
4785: memset(ext_find->reserved, 0, 5);
4786: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
4787: }
4788: find->drive = _getdrive();
1.1.1.13 root 4789: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 4790: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
4791: find->nt_res = 0;
4792: msdos_find_file_conv_local_time(&fd);
4793: find->create_time_ms = 0;
4794: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
4795: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
4796: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
4797: find->cluster_hi = find->cluster_lo = 0;
4798: find->file_size = fd.nFileSizeLow;
4799: REG8(AL) = 0x00;
1.1.1.14 root 4800: } else if(dtainfo->allowable_mask & 8) {
1.1 root 4801: if(ext_fcb->flag == 0xff) {
4802: ext_find->flag = 0xff;
4803: memset(ext_find->reserved, 0, 5);
4804: ext_find->attribute = 8;
4805: }
4806: find->drive = _getdrive();
4807: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
4808: find->attribute = 8;
4809: find->nt_res = 0;
4810: msdos_find_file_conv_local_time(&fd);
4811: find->create_time_ms = 0;
4812: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
4813: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
4814: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
4815: find->cluster_hi = find->cluster_lo = 0;
4816: find->file_size = 0;
1.1.1.14 root 4817: dtainfo->allowable_mask &= ~8;
1.1 root 4818: REG8(AL) = 0x00;
4819: } else {
4820: REG8(AL) = 0xff;
4821: }
4822: }
4823:
4824: inline void msdos_int_21h_13h()
4825: {
1.1.1.3 root 4826: if(remove(msdos_fcb_path((fcb_t *)(mem + SREG_BASE(DS) + REG16(DX))))) {
1.1 root 4827: REG8(AL) = 0xff;
4828: } else {
4829: REG8(AL) = 0x00;
4830: }
4831: }
4832:
1.1.1.16 root 4833: inline void msdos_int_21h_14h()
4834: {
4835: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4836: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
4837: process_t *process = msdos_process_info_get(current_psp);
4838: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
4839: DWORD num = 0;
4840:
4841: memset(mem + dta_laddr, 0, fcb->record_size);
4842: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
4843: REG8(AL) = 1;
4844: } else {
4845: UINT32 position = fcb->current_block * fcb->record_size + fcb->cur_record + num;
4846: fcb->current_block = (position & 0xffffff) / fcb->record_size;
4847: fcb->cur_record = (position & 0xffffff) % fcb->record_size;
4848: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
4849: }
4850: }
4851:
4852: inline void msdos_int_21h_15h()
1.1.1.14 root 4853: {
4854: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4855: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.16 root 4856: process_t *process = msdos_process_info_get(current_psp);
4857: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
4858: DWORD num = 0;
1.1.1.14 root 4859:
1.1.1.16 root 4860: if(!WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
4861: REG8(AL) = 1;
4862: } else {
4863: fcb->file_size = GetFileSize(fcb->handle, NULL);
4864: UINT32 position = fcb->current_block * fcb->record_size + fcb->cur_record + num;
4865: fcb->current_block = (position & 0xffffff) / fcb->record_size;
4866: fcb->cur_record = (position & 0xffffff) % fcb->record_size;
4867: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
4868: }
4869: }
4870:
4871: inline void msdos_int_21h_16h()
4872: {
4873: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4874: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.14 root 4875: char *path = msdos_fcb_path(fcb);
4876: 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 4877:
1.1.1.14 root 4878: if(hFile == INVALID_HANDLE_VALUE) {
4879: REG8(AL) = 0xff;
4880: } else {
4881: REG8(AL) = 0;
4882: fcb->current_block = 0;
4883: fcb->record_size = 128;
4884: fcb->file_size = 0;
4885: fcb->handle = hFile;
4886: fcb->cur_record = 0;
4887: }
4888: }
4889:
1.1.1.16 root 4890: inline void msdos_int_21h_17h()
4891: {
4892: ext_fcb_t *ext_fcb_src = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4893: fcb_t *fcb_src = (fcb_t *)(ext_fcb_src + (ext_fcb_src->flag == 0xff ? 1 : 0));
4894: char *path_src = msdos_fcb_path(fcb_src);
4895: ext_fcb_t *ext_fcb_dst = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + 16);
4896: fcb_t *fcb_dst = (fcb_t *)(ext_fcb_dst + (ext_fcb_dst->flag == 0xff ? 1 : 0));
4897: char *path_dst = msdos_fcb_path(fcb_dst);
4898:
4899: if(rename(path_src, path_dst)) {
4900: REG8(AL) = 0xff;
4901: } else {
4902: REG8(AL) = 0;
4903: }
4904: }
4905:
1.1 root 4906: inline void msdos_int_21h_18h()
4907: {
4908: REG8(AL) = 0x00;
4909: }
4910:
4911: inline void msdos_int_21h_19h()
4912: {
4913: REG8(AL) = _getdrive() - 1;
4914: }
4915:
4916: inline void msdos_int_21h_1ah()
4917: {
4918: process_t *process = msdos_process_info_get(current_psp);
4919:
4920: process->dta.w.l = REG16(DX);
1.1.1.3 root 4921: process->dta.w.h = SREG(DS);
1.1 root 4922: }
4923:
4924: inline void msdos_int_21h_1bh()
4925: {
4926: int drive_num = _getdrive() - 1;
4927: UINT16 seg, ofs;
4928:
4929: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
4930: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
4931: REG8(AL) = dpb->highest_sector_num + 1;
4932: REG16(CX) = dpb->bytes_per_sector;
4933: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 4934: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 4935: } else {
4936: REG8(AL) = 0xff;
1.1.1.3 root 4937: m_CF = 1;
1.1 root 4938: }
4939:
4940: }
4941:
4942: inline void msdos_int_21h_1ch()
4943: {
4944: int drive_num = REG8(DL) ? (REG8(DL) - 1) : (_getdrive() - 1);
4945: UINT16 seg, ofs;
4946:
4947: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
4948: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
4949: REG8(AL) = dpb->highest_sector_num + 1;
4950: REG16(CX) = dpb->bytes_per_sector;
4951: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 4952: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 4953: } else {
4954: REG8(AL) = 0xff;
1.1.1.3 root 4955: m_CF = 1;
1.1 root 4956: }
4957:
4958: }
4959:
4960: inline void msdos_int_21h_1dh()
4961: {
4962: REG8(AL) = 0;
4963: }
4964:
4965: inline void msdos_int_21h_1eh()
4966: {
4967: REG8(AL) = 0;
4968: }
4969:
4970: inline void msdos_int_21h_1fh()
4971: {
4972: int drive_num = _getdrive() - 1;
4973: UINT16 seg, ofs;
4974:
4975: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
4976: REG8(AL) = 0;
1.1.1.3 root 4977: SREG(DS) = seg;
4978: i386_load_segment_descriptor(DS);
1.1 root 4979: REG16(BX) = ofs;
4980: } else {
4981: REG8(AL) = 0xff;
1.1.1.3 root 4982: m_CF = 1;
1.1 root 4983: }
4984: }
4985:
4986: inline void msdos_int_21h_20h()
4987: {
4988: REG8(AL) = 0;
4989: }
4990:
1.1.1.14 root 4991: inline void msdos_int_21h_21h()
4992: {
4993: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4994: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
4995:
4996: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
4997: REG8(AL) = 1;
4998: } else {
4999: process_t *process = msdos_process_info_get(current_psp);
5000: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5001: memset(mem + dta_laddr, 0, fcb->record_size);
1.1.1.16 root 5002: DWORD num = 0;
1.1.1.14 root 5003: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
5004: REG8(AL) = 1;
5005: } else {
5006: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
5007: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
1.1.1.16 root 5008: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
1.1.1.14 root 5009: }
5010: }
5011: }
5012:
5013: inline void msdos_int_21h_22h()
5014: {
5015: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5016: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5017:
5018: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
5019: REG8(AL) = 0xff;
5020: } else {
5021: process_t *process = msdos_process_info_get(current_psp);
5022: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
1.1.1.16 root 5023: DWORD num = 0;
1.1.1.14 root 5024: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL);
5025: fcb->file_size = GetFileSize(fcb->handle, NULL);
5026: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
5027: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
1.1.1.16 root 5028: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
1.1.1.14 root 5029: }
5030: }
5031:
1.1.1.16 root 5032: inline void msdos_int_21h_23h()
5033: {
5034: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5035: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5036: char *path = msdos_fcb_path(fcb);
5037: HANDLE hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
5038:
5039: if(hFile == INVALID_HANDLE_VALUE) {
5040: REG8(AL) = 0xff;
5041: } else {
5042: UINT32 size = GetFileSize(hFile, NULL);
5043: fcb->rand_record = size / fcb->record_size + ((size % fcb->record_size) != 0);
5044: REG8(AL) = 0;
5045: }
5046: }
5047:
5048: inline void msdos_int_21h_24h()
5049: {
5050: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5051: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5052:
5053: fcb->rand_record = fcb->current_block * fcb->record_size + fcb->cur_record;
5054: }
5055:
1.1 root 5056: inline void msdos_int_21h_25h()
5057: {
5058: *(UINT16 *)(mem + 4 * REG8(AL) + 0) = REG16(DX);
1.1.1.3 root 5059: *(UINT16 *)(mem + 4 * REG8(AL) + 2) = SREG(DS);
1.1 root 5060: }
5061:
5062: inline void msdos_int_21h_26h()
5063: {
5064: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
5065:
5066: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
5067: psp->first_mcb = REG16(DX) + 16;
5068: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
5069: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
5070: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
5071: psp->parent_psp = 0;
5072: }
5073:
1.1.1.16 root 5074: inline void msdos_int_21h_27h()
5075: {
5076: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5077: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5078:
5079: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
5080: REG8(AL) = 1;
5081: } else {
5082: process_t *process = msdos_process_info_get(current_psp);
5083: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5084: memset(mem + dta_laddr, 0, fcb->record_size * REG16(CX));
5085: DWORD num = 0;
5086: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size * REG16(CX), &num, NULL) || num == 0) {
5087: REG8(AL) = 1;
5088: } else {
5089: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
5090: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
5091: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
5092: REG16(CX) = num / fcb->record_size + ((num % fcb->record_size) != 0);
5093: }
5094: }
5095: }
5096:
5097: inline void msdos_int_21h_28h()
5098: {
5099: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5100: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5101:
5102: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
5103: REG8(AL) = 0xff;
5104: } else {
5105: process_t *process = msdos_process_info_get(current_psp);
5106: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5107: DWORD num = 0;
5108: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size * REG16(CX), &num, NULL);
5109: fcb->file_size = GetFileSize(fcb->handle, NULL);
5110: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
5111: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
5112: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
5113: REG16(CX) = num / fcb->record_size + ((num % fcb->record_size) != 0);
5114: }
5115: }
5116:
1.1 root 5117: inline void msdos_int_21h_29h()
5118: {
1.1.1.20 root 5119: int ofs = 0;//SREG_BASE(DS) + REG16(SI);
5120: char buffer[1024], name[MAX_PATH], ext[MAX_PATH];
1.1 root 5121: UINT8 drv = 0;
5122: char sep_chars[] = ":.;,=+";
5123: char end_chars[] = "\\<>|/\"[]";
5124: char spc_chars[] = " \t";
5125:
1.1.1.20 root 5126: memcpy(buffer, mem + SREG_BASE(DS) + REG16(SI), 1023);
5127: buffer[1023] = 0;
5128: memset(name, 0x20, sizeof(name));
5129: memset(ext, 0x20, sizeof(ext));
5130:
1.1 root 5131: if(REG8(AL) & 1) {
1.1.1.20 root 5132: ofs += strspn((char *)(buffer + ofs), spc_chars);
5133: if(my_strchr(sep_chars, buffer[ofs]) && buffer[ofs] != '\0') {
1.1 root 5134: ofs++;
5135: }
5136: }
1.1.1.20 root 5137: ofs += strspn((char *)(buffer + ofs), spc_chars);
1.1 root 5138:
5139: if(mem[ofs + 1] == ':') {
1.1.1.20 root 5140: if(mem[ofs] >= 'a' && mem[ofs] <= 'z') {
5141: drv = mem[ofs] - 'a' + 1;
5142: ofs += 2;
5143: } else if(mem[ofs] >= 'A' && mem[ofs] <= 'Z') {
5144: drv = mem[ofs] - 'A' + 1;
1.1 root 5145: ofs += 2;
5146: }
5147: }
1.1.1.20 root 5148: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) {
5149: UINT8 c = buffer[ofs];
5150: if(is_kanji) {
5151: is_kanji = 0;
5152: } else if(msdos_lead_byte_check(c)) {
5153: is_kanji = 1;
5154: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
1.1 root 5155: break;
5156: } else if(c >= 'a' && c <= 'z') {
5157: c -= 0x20;
5158: }
5159: ofs++;
5160: name[i] = c;
5161: }
1.1.1.20 root 5162: if(buffer[ofs] == '.') {
1.1 root 5163: ofs++;
1.1.1.20 root 5164: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) {
5165: UINT8 c = buffer[ofs];
5166: if(is_kanji) {
5167: is_kanji = 0;
5168: } else if(msdos_lead_byte_check(c)) {
5169: is_kanji = 1;
5170: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
1.1 root 5171: break;
5172: } else if(c >= 'a' && c <= 'z') {
5173: c -= 0x20;
5174: }
5175: ofs++;
5176: ext[i] = c;
5177: }
5178: }
1.1.1.20 root 5179: int si = REG16(SI) + ofs;
1.1.1.3 root 5180: int ds = SREG(DS);
1.1 root 5181: while(si > 0xffff) {
5182: si -= 0x10;
5183: ds++;
5184: }
5185: REG16(SI) = si;
1.1.1.3 root 5186: SREG(DS) = ds;
5187: i386_load_segment_descriptor(DS);
1.1 root 5188:
1.1.1.3 root 5189: UINT8 *fcb = mem + SREG_BASE(ES) + REG16(DI);
1.1.1.20 root 5190: if(!(REG8(AL) & 2) || drv != 0) {
5191: fcb[0] = drv;
5192: }
5193: if(!(REG8(AL) & 4) || name[0] != 0x20) {
5194: memcpy(fcb + 1, name, 8);
5195: }
5196: if(!(REG8(AL) & 8) || ext[0] != 0x20) {
5197: memcpy(fcb + 9, ext, 3);
5198: }
5199: for(int i = 1, found_star = 0; i < 1 + 8; i++) {
1.1 root 5200: if(fcb[i] == '*') {
5201: found_star = 1;
5202: }
5203: if(found_star) {
5204: fcb[i] = '?';
5205: }
5206: }
1.1.1.20 root 5207: for(int i = 9, found_star = 0; i < 9 + 3; i++) {
1.1 root 5208: if(fcb[i] == '*') {
5209: found_star = 1;
5210: }
5211: if(found_star) {
5212: fcb[i] = '?';
5213: }
5214: }
5215:
5216: if(drv == 0 || (drv > 0 && drv <= 26 && (GetLogicalDrives() & ( 1 << (drv - 1) )))) {
5217: if(memchr(fcb + 1, '?', 8 + 3)) {
5218: REG8(AL) = 0x01;
1.1.1.20 root 5219: } else {
5220: REG8(AL) = 0x00;
1.1 root 5221: }
5222: } else {
5223: REG8(AL) = 0xff;
5224: }
5225: }
5226:
5227: inline void msdos_int_21h_2ah()
5228: {
5229: SYSTEMTIME sTime;
5230:
5231: GetLocalTime(&sTime);
5232: REG16(CX) = sTime.wYear;
5233: REG8(DH) = (UINT8)sTime.wMonth;
5234: REG8(DL) = (UINT8)sTime.wDay;
5235: REG8(AL) = (UINT8)sTime.wDayOfWeek;
5236: }
5237:
5238: inline void msdos_int_21h_2bh()
5239: {
1.1.1.14 root 5240: REG8(AL) = 0xff;
1.1 root 5241: }
5242:
5243: inline void msdos_int_21h_2ch()
5244: {
5245: SYSTEMTIME sTime;
5246:
5247: GetLocalTime(&sTime);
5248: REG8(CH) = (UINT8)sTime.wHour;
5249: REG8(CL) = (UINT8)sTime.wMinute;
5250: REG8(DH) = (UINT8)sTime.wSecond;
1.1.1.14 root 5251: REG8(DL) = (UINT8)sTime.wMilliseconds / 10;
1.1 root 5252: }
5253:
5254: inline void msdos_int_21h_2dh()
5255: {
5256: REG8(AL) = 0x00;
5257: }
5258:
5259: inline void msdos_int_21h_2eh()
5260: {
5261: process_t *process = msdos_process_info_get(current_psp);
5262:
5263: process->verify = REG8(AL);
5264: }
5265:
5266: inline void msdos_int_21h_2fh()
5267: {
5268: process_t *process = msdos_process_info_get(current_psp);
5269:
5270: REG16(BX) = process->dta.w.l;
1.1.1.3 root 5271: SREG(ES) = process->dta.w.h;
5272: i386_load_segment_descriptor(ES);
1.1 root 5273: }
5274:
5275: inline void msdos_int_21h_30h()
5276: {
5277: // Version Flag / OEM
5278: if(REG8(AL) == 1) {
5279: REG8(BH) = 0x00; // not in ROM
5280: } else {
5281: REG8(BH) = 0xff; // OEM = Microsoft
5282: }
1.1.1.9 root 5283: REG8(AL) = major_version; // 7
5284: REG8(AH) = minor_version; // 10
1.1 root 5285: }
5286:
5287: inline void msdos_int_21h_31h()
5288: {
1.1.1.14 root 5289: msdos_mem_realloc(current_psp, REG16(DX), NULL);
1.1 root 5290: msdos_process_terminate(current_psp, REG8(AL) | 0x300, 0);
5291: }
5292:
5293: inline void msdos_int_21h_32h()
5294: {
5295: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
5296: UINT16 seg, ofs;
5297:
5298: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
5299: REG8(AL) = 0;
1.1.1.3 root 5300: SREG(DS) = seg;
5301: i386_load_segment_descriptor(DS);
1.1 root 5302: REG16(BX) = ofs;
5303: } else {
5304: REG8(AL) = 0xff;
1.1.1.3 root 5305: m_CF = 1;
1.1 root 5306: }
5307: }
5308:
5309: inline void msdos_int_21h_33h()
5310: {
5311: static UINT8 state = 0x00;
5312: char path[MAX_PATH];
5313:
5314: switch(REG8(AL)) {
5315: case 0x00:
5316: REG8(DL) = state;
5317: break;
5318: case 0x01:
5319: state = REG8(DL);
5320: break;
5321: case 0x05:
5322: GetSystemDirectory(path, MAX_PATH);
5323: if(path[0] >= 'a' && path[0] <= 'z') {
5324: REG8(DL) = path[0] - 'a' + 1;
5325: } else {
5326: REG8(DL) = path[0] - 'A' + 1;
5327: }
5328: break;
5329: case 0x06:
1.1.1.2 root 5330: // MS-DOS version (7.10)
1.1 root 5331: REG8(BL) = 7;
1.1.1.2 root 5332: REG8(BH) = 10;
1.1 root 5333: REG8(DL) = 0;
5334: REG8(DH) = 0x10; // in HMA
5335: break;
1.1.1.6 root 5336: case 0x07:
5337: if(REG8(DL) == 0) {
5338: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag &= ~0x20;
5339: } else if(REG8(DL) == 1) {
5340: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag |= 0x20;
5341: }
5342: break;
1.1 root 5343: default:
1.1.1.22! root 5344: 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 5345: REG16(AX) = 0x01;
1.1.1.3 root 5346: m_CF = 1;
1.1 root 5347: break;
5348: }
5349: }
5350:
5351: inline void msdos_int_21h_35h()
5352: {
5353: REG16(BX) = *(UINT16 *)(mem + 4 * REG8(AL) + 0);
1.1.1.3 root 5354: SREG(ES) = *(UINT16 *)(mem + 4 * REG8(AL) + 2);
5355: i386_load_segment_descriptor(ES);
1.1 root 5356: }
5357:
5358: inline void msdos_int_21h_36h()
5359: {
5360: struct _diskfree_t df = {0};
5361:
5362: if(_getdiskfree(REG8(DL), &df) == 0) {
5363: REG16(AX) = (UINT16)df.sectors_per_cluster;
5364: REG16(CX) = (UINT16)df.bytes_per_sector;
1.1.1.13 root 5365: REG16(BX) = df.avail_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.avail_clusters;
5366: REG16(DX) = df.total_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.total_clusters;
1.1 root 5367: } else {
5368: REG16(AX) = 0xffff;
5369: }
5370: }
5371:
5372: inline void msdos_int_21h_37h()
5373: {
1.1.1.22! root 5374: static UINT8 dev_flag = 0xff;
1.1 root 5375:
5376: switch(REG8(AL)) {
5377: case 0x00:
1.1.1.22! root 5378: {
! 5379: process_t *process = msdos_process_info_get(current_psp);
! 5380: REG8(AL) = 0x00;
! 5381: REG8(DL) = process->switchar;
! 5382: }
1.1 root 5383: break;
5384: case 0x01:
1.1.1.22! root 5385: {
! 5386: process_t *process = msdos_process_info_get(current_psp);
! 5387: REG8(AL) = 0x00;
! 5388: process->switchar = REG8(DL);
! 5389: }
! 5390: break;
! 5391: case 0x02:
! 5392: REG8(DL) = dev_flag;
! 5393: break;
! 5394: case 0x03:
! 5395: dev_flag = REG8(DL);
! 5396: break;
! 5397: case 0xd0:
! 5398: case 0xd1:
! 5399: case 0xd2:
! 5400: case 0xd3:
! 5401: case 0xd4:
! 5402: case 0xd5:
! 5403: case 0xd6:
! 5404: case 0xd7:
! 5405: case 0xdc:
! 5406: case 0xdd:
! 5407: case 0xde:
! 5408: case 0xdf:
! 5409: // diet ???
! 5410: REG16(AX) = 1;
1.1 root 5411: break;
5412: default:
1.1.1.22! root 5413: 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 5414: REG16(AX) = 1;
5415: break;
5416: }
5417: }
5418:
1.1.1.19 root 5419: int get_country_info(country_info_t *ci)
1.1.1.17 root 5420: {
5421: char LCdata[80];
5422:
1.1.1.19 root 5423: ZeroMemory(ci, offsetof(country_info_t, reserved));
1.1.1.17 root 5424: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRDIGITS, LCdata, sizeof(LCdata));
5425: ci->currency_dec_digits = atoi(LCdata);
5426: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRENCY, LCdata, sizeof(LCdata));
5427: ci->currency_format = *LCdata - '0';
5428: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDATE, LCdata, sizeof(LCdata));
5429: ci->date_format = *LCdata - '0';
5430: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SCURRENCY, LCdata, sizeof(LCdata));
5431: memcpy(&ci->currency_symbol, LCdata, 4);
5432: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDATE, LCdata, sizeof(LCdata));
5433: *ci->date_sep = *LCdata;
5434: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, LCdata, sizeof(LCdata));
5435: *ci->dec_sep = *LCdata;
5436: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SLIST, LCdata, sizeof(LCdata));
5437: *ci->list_sep = *LCdata;
5438: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, LCdata, sizeof(LCdata));
5439: *ci->thou_sep = *LCdata;
5440: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIME, LCdata, sizeof(LCdata));
5441: *ci->time_sep = *LCdata;
5442: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIMEFORMAT, LCdata, sizeof(LCdata));
5443: if(strchr(LCdata, 'H') != NULL) {
5444: ci->time_format = 1;
5445: }
1.1.1.19 root 5446: ci->case_map.w.l = 0x000c;
5447: ci->case_map.w.h = 0xffff;
1.1.1.17 root 5448: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICOUNTRY, LCdata, sizeof(LCdata));
5449: return atoi(LCdata);
5450: }
5451:
1.1.1.14 root 5452: inline void msdos_int_21h_38h()
5453: {
5454: switch(REG8(AL)) {
5455: case 0x00:
1.1.1.19 root 5456: REG16(BX) = get_country_info((country_info_t *)(mem + SREG_BASE(DS) + REG16(DX)));
1.1.1.14 root 5457: break;
5458: default:
1.1.1.22! root 5459: 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 5460: REG16(AX) = 2;
5461: m_CF = 1;
5462: break;
5463: }
5464: }
5465:
1.1 root 5466: inline void msdos_int_21h_39h(int lfn)
5467: {
1.1.1.3 root 5468: if(_mkdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 5469: REG16(AX) = errno;
1.1.1.3 root 5470: m_CF = 1;
1.1 root 5471: }
5472: }
5473:
5474: inline void msdos_int_21h_3ah(int lfn)
5475: {
1.1.1.3 root 5476: if(_rmdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 5477: REG16(AX) = errno;
1.1.1.3 root 5478: m_CF = 1;
1.1 root 5479: }
5480: }
5481:
5482: inline void msdos_int_21h_3bh(int lfn)
5483: {
1.1.1.3 root 5484: if(_chdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1.1.17 root 5485: REG16(AX) = 3; // must be 3 (path not found)
1.1.1.3 root 5486: m_CF = 1;
1.1 root 5487: }
5488: }
5489:
5490: inline void msdos_int_21h_3ch()
5491: {
1.1.1.3 root 5492: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 5493: int attr = GetFileAttributes(path);
5494: int fd = -1;
1.1.1.11 root 5495: UINT16 info;
1.1 root 5496:
1.1.1.11 root 5497: if(msdos_is_con_path(path)) {
5498: fd = _open("CON", _O_WRONLY | _O_BINARY);
5499: info = 0x80d3;
1.1.1.14 root 5500: } else if(msdos_is_nul_path(path)) {
5501: fd = _open("NUL", _O_WRONLY | _O_BINARY);
5502: info = 0x80d3;
1.1.1.20 root 5503: } else if(strncmp(path, "EMMXXXX0", 8) == 0) {
5504: fd = _open("NUL", _O_WRONLY | _O_BINARY);
5505: info = 0x80d3;
1.1 root 5506: } else {
5507: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
1.1.1.11 root 5508: info = msdos_drive_number(path);
1.1 root 5509: }
5510: if(fd != -1) {
5511: if(attr == -1) {
5512: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
5513: }
5514: SetFileAttributes(path, attr);
5515: REG16(AX) = fd;
1.1.1.11 root 5516: msdos_file_handler_open(fd, path, _isatty(fd), 2, info, current_psp);
1.1.1.20 root 5517: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 5518: } else {
5519: REG16(AX) = errno;
1.1.1.3 root 5520: m_CF = 1;
1.1 root 5521: }
5522: }
5523:
5524: inline void msdos_int_21h_3dh()
5525: {
1.1.1.3 root 5526: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 5527: int mode = REG8(AL) & 0x03;
1.1.1.11 root 5528: int fd = -1;
5529: UINT16 info;
1.1 root 5530:
5531: if(mode < 0x03) {
1.1.1.11 root 5532: if(msdos_is_con_path(path)) {
1.1.1.13 root 5533: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 5534: info = 0x80d3;
1.1.1.14 root 5535: } else if(msdos_is_nul_path(path)) {
5536: fd = msdos_open("NUL", file_mode[mode].mode);
5537: info = 0x80d3;
1.1.1.20 root 5538: } else if(strncmp(path, "EMMXXXX0", 8) == 0) {
5539: fd = msdos_open("NUL", file_mode[mode].mode);
5540: info = 0x80d3;
1.1.1.11 root 5541: } else {
1.1.1.13 root 5542: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 5543: info = msdos_drive_number(path);
5544: }
1.1 root 5545: if(fd != -1) {
5546: REG16(AX) = fd;
1.1.1.11 root 5547: msdos_file_handler_open(fd, path, _isatty(fd), mode, info, current_psp);
1.1.1.20 root 5548: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 5549: } else {
5550: REG16(AX) = errno;
1.1.1.3 root 5551: m_CF = 1;
1.1 root 5552: }
5553: } else {
5554: REG16(AX) = 0x0c;
1.1.1.3 root 5555: m_CF = 1;
1.1 root 5556: }
5557: }
5558:
5559: inline void msdos_int_21h_3eh()
5560: {
5561: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 5562: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 5563:
1.1.1.20 root 5564: if(fd < process->max_files && file_handler[fd].valid) {
5565: _close(fd);
5566: msdos_file_handler_close(fd);
5567: msdos_psp_set_file_table(REG16(BX), 0x0ff, current_psp);
1.1 root 5568: } else {
5569: REG16(AX) = 0x06;
1.1.1.3 root 5570: m_CF = 1;
1.1 root 5571: }
5572: }
5573:
5574: inline void msdos_int_21h_3fh()
5575: {
5576: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 5577: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 5578:
1.1.1.20 root 5579: if(fd < process->max_files && file_handler[fd].valid) {
5580: if(file_mode[file_handler[fd].mode].in) {
5581: if(file_handler[fd].atty) {
1.1 root 5582: // BX is stdin or is redirected to stdin
1.1.1.3 root 5583: UINT8 *buf = mem + SREG_BASE(DS) + REG16(DX);
1.1 root 5584: int max = REG16(CX);
5585: int p = 0;
5586:
5587: while(max > p) {
5588: int chr = msdos_getch();
5589:
5590: if(chr == 0x00) {
5591: // skip 2nd byte
5592: msdos_getch();
5593: } else if(chr == 0x0d) {
5594: // carriage return
5595: buf[p++] = 0x0d;
5596: if(max > p) {
5597: buf[p++] = 0x0a;
5598: }
1.1.1.14 root 5599: msdos_putch('\n');
1.1 root 5600: break;
5601: } else if(chr == 0x08) {
5602: // back space
5603: if(p > 0) {
5604: p--;
1.1.1.20 root 5605: if(msdos_ctrl_code_check(buf[p])) {
5606: msdos_putch(chr);
5607: msdos_putch(chr);
5608: msdos_putch(' ');
5609: msdos_putch(' ');
5610: msdos_putch(chr);
5611: msdos_putch(chr);
5612: } else {
5613: msdos_putch(chr);
5614: msdos_putch(' ');
5615: msdos_putch(chr);
5616: }
1.1 root 5617: }
5618: } else {
5619: buf[p++] = chr;
5620: msdos_putch(chr);
5621: }
5622: }
5623: REG16(AX) = p;
1.1.1.8 root 5624: // some seconds may be passed in console
1.1 root 5625: hardware_update();
5626: } else {
1.1.1.20 root 5627: REG16(AX) = _read(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 5628: }
5629: } else {
5630: REG16(AX) = 0x05;
1.1.1.3 root 5631: m_CF = 1;
1.1 root 5632: }
5633: } else {
5634: REG16(AX) = 0x06;
1.1.1.3 root 5635: m_CF = 1;
1.1 root 5636: }
5637: }
5638:
5639: inline void msdos_int_21h_40h()
5640: {
5641: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 5642: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 5643:
1.1.1.20 root 5644: if(fd < process->max_files && file_handler[fd].valid) {
5645: if(file_mode[file_handler[fd].mode].out) {
1.1 root 5646: if(REG16(CX)) {
1.1.1.20 root 5647: if(file_handler[fd].atty) {
1.1 root 5648: // BX is stdout/stderr or is redirected to stdout
5649: for(int i = 0; i < REG16(CX); i++) {
1.1.1.3 root 5650: msdos_putch(mem[SREG_BASE(DS) + REG16(DX) + i]);
1.1 root 5651: }
5652: REG16(AX) = REG16(CX);
5653: } else {
1.1.1.20 root 5654: REG16(AX) = msdos_write(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 5655: }
5656: } else {
1.1.1.20 root 5657: UINT32 pos = _tell(fd);
5658: _lseek(fd, 0, SEEK_END);
5659: UINT32 size = _tell(fd);
1.1 root 5660: REG16(AX) = 0;
1.1.1.12 root 5661: if(pos < size) {
1.1.1.20 root 5662: _lseek(fd, pos, SEEK_SET);
5663: SetEndOfFile((HANDLE)_get_osfhandle(fd));
1.1.1.12 root 5664: } else {
5665: for(UINT32 i = size; i < pos; i++) {
5666: UINT8 tmp = 0;
1.1.1.20 root 5667: REG16(AX) += msdos_write(fd, &tmp, 1);
1.1.1.12 root 5668: }
1.1.1.20 root 5669: _lseek(fd, pos, SEEK_SET);
1.1 root 5670: }
5671: }
5672: } else {
5673: REG16(AX) = 0x05;
1.1.1.3 root 5674: m_CF = 1;
1.1 root 5675: }
5676: } else {
5677: REG16(AX) = 0x06;
1.1.1.3 root 5678: m_CF = 1;
1.1 root 5679: }
5680: }
5681:
5682: inline void msdos_int_21h_41h(int lfn)
5683: {
1.1.1.3 root 5684: if(remove(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 5685: REG16(AX) = errno;
1.1.1.3 root 5686: m_CF = 1;
1.1 root 5687: }
5688: }
5689:
5690: inline void msdos_int_21h_42h()
5691: {
5692: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 5693: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 5694:
1.1.1.20 root 5695: if(fd < process->max_files && file_handler[fd].valid) {
1.1 root 5696: if(REG8(AL) < 0x03) {
5697: static int ptrname[] = { SEEK_SET, SEEK_CUR, SEEK_END };
1.1.1.20 root 5698: _lseek(fd, (REG16(CX) << 16) | REG16(DX), ptrname[REG8(AL)]);
5699: UINT32 pos = _tell(fd);
1.1 root 5700: REG16(AX) = pos & 0xffff;
5701: REG16(DX) = (pos >> 16);
5702: } else {
5703: REG16(AX) = 0x01;
1.1.1.3 root 5704: m_CF = 1;
1.1 root 5705: }
5706: } else {
5707: REG16(AX) = 0x06;
1.1.1.3 root 5708: m_CF = 1;
1.1 root 5709: }
5710: }
5711:
5712: inline void msdos_int_21h_43h(int lfn)
5713: {
1.1.1.3 root 5714: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn);
1.1 root 5715: int attr;
5716:
1.1.1.14 root 5717: if(!lfn && REG8(AL) > 2) {
5718: REG16(AX) = 0x01;
5719: m_CF = 1;
5720: return;
5721: }
5722: switch(REG8(lfn ? BL : AL)) {
1.1 root 5723: case 0x00:
5724: if((attr = GetFileAttributes(path)) != -1) {
1.1.1.14 root 5725: REG16(CX) = (UINT16)msdos_file_attribute_create((UINT16)attr);
5726: } else {
5727: REG16(AX) = (UINT16)GetLastError();
5728: m_CF = 1;
5729: }
5730: break;
5731: case 0x01:
5732: if(!SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)))) {
5733: REG16(AX) = (UINT16)GetLastError();
5734: m_CF = 1;
5735: }
5736: break;
5737: case 0x02:
5738: {
5739: DWORD size = GetCompressedFileSize(path, NULL);
5740: if(size != INVALID_FILE_SIZE) {
5741: if(size != 0 && size == GetFileSize(path, NULL)) {
5742: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
5743: // this isn't correct if the file is in the NTFS MFT
5744: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
5745: size = ((size - 1) | (sectors_per_cluster * bytes_per_sector - 1)) + 1;
5746: }
5747: }
5748: REG16(AX) = LOWORD(size);
5749: REG16(DX) = HIWORD(size);
5750: } else {
5751: REG16(AX) = (UINT16)GetLastError();
5752: m_CF = 1;
1.1 root 5753: }
1.1.1.14 root 5754: }
5755: break;
5756: case 0x03:
5757: case 0x05:
5758: case 0x07:
5759: {
5760: HANDLE hFile = CreateFile(path, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
5761: if(hFile != INVALID_HANDLE_VALUE) {
5762: FILETIME local, time;
5763: DosDateTimeToFileTime(REG16(DI), /*REG8(BL) == 5 ? 0 : */REG16(CX), &local);
5764: if(REG8(BL) == 7) {
5765: ULARGE_INTEGER hund;
5766: hund.LowPart = local.dwLowDateTime;
5767: hund.HighPart = local.dwHighDateTime;
5768: hund.QuadPart += REG16(SI) * 100000;
5769: local.dwLowDateTime = hund.LowPart;
5770: local.dwHighDateTime = hund.HighPart;
5771: }
5772: LocalFileTimeToFileTime(&local, &time);
5773: if(!SetFileTime(hFile, REG8(BL) == 0x07 ? &time : NULL,
5774: REG8(BL) == 0x05 ? &time : NULL,
5775: REG8(BL) == 0x03 ? &time : NULL)) {
5776: REG16(AX) = (UINT16)GetLastError();
5777: m_CF = 1;
5778: }
5779: CloseHandle(hFile);
5780: } else {
5781: REG16(AX) = (UINT16)GetLastError();
5782: m_CF = 1;
1.1 root 5783: }
1.1.1.14 root 5784: }
5785: break;
5786: case 0x04:
5787: case 0x06:
5788: case 0x08:
5789: {
5790: WIN32_FILE_ATTRIBUTE_DATA fad;
5791: if(GetFileAttributesEx(path, GetFileExInfoStandard, (LPVOID)&fad)) {
5792: FILETIME *time, local;
5793: time = REG8(BL) == 0x04 ? &fad.ftLastWriteTime :
5794: 0x06 ? &fad.ftLastAccessTime :
5795: &fad.ftCreationTime;
5796: FileTimeToLocalFileTime(time, &local);
5797: FileTimeToDosDateTime(&local, ®16(DI), ®16(CX));
5798: if(REG8(BL) == 0x08) {
5799: ULARGE_INTEGER hund;
5800: hund.LowPart = local.dwLowDateTime;
5801: hund.HighPart = local.dwHighDateTime;
5802: hund.QuadPart /= 100000;
5803: REG16(SI) = (UINT16)(hund.QuadPart % 200);
5804: }
5805: } else {
5806: REG16(AX) = (UINT16)GetLastError();
5807: m_CF = 1;
1.1 root 5808: }
1.1.1.14 root 5809: }
5810: break;
5811: default:
1.1.1.22! root 5812: 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 5813: REG16(AX) = 0x01;
5814: m_CF = 1;
5815: break;
5816: }
5817: }
5818:
5819: inline void msdos_int_21h_44h()
5820: {
1.1.1.22! root 5821: static UINT16 iteration_count = 0;
! 5822:
1.1.1.20 root 5823: process_t *process = msdos_process_info_get(current_psp);
5824: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
5825:
1.1.1.14 root 5826: UINT32 val = DRIVE_NO_ROOT_DIR;
5827:
5828: switch(REG8(AL)) {
5829: case 0x00:
5830: case 0x01:
5831: case 0x02:
5832: case 0x03:
5833: case 0x04:
5834: case 0x05:
5835: case 0x06:
5836: case 0x07:
1.1.1.20 root 5837: if(fd >= process->max_files || !file_handler[fd].valid) {
5838: REG16(AX) = 0x06;
5839: m_CF = 1;
5840: return;
1.1.1.14 root 5841: }
5842: break;
5843: case 0x08:
5844: case 0x09:
5845: if(REG8(BL) >= ('Z' - 'A' + 1)) {
5846: // invalid drive number
5847: REG16(AX) = 0x0f;
5848: m_CF = 1;
5849: return;
5850: } else {
5851: if(REG8(BL) == 0) {
5852: val = GetDriveType(NULL);
5853: } else {
5854: char tmp[8];
5855: sprintf(tmp, "%c:\\", 'A' + REG8(BL) - 1);
5856: val = GetDriveType(tmp);
5857: }
5858: if(val == DRIVE_NO_ROOT_DIR) {
5859: // no drive
5860: REG16(AX) = 0x0f;
5861: m_CF = 1;
5862: return;
1.1 root 5863: }
5864: }
5865: break;
5866: }
5867: switch(REG8(AL)) {
5868: case 0x00: // get ioctrl data
1.1.1.20 root 5869: REG16(DX) = file_handler[fd].info;
1.1 root 5870: break;
5871: case 0x01: // set ioctrl data
1.1.1.20 root 5872: file_handler[fd].info |= REG8(DL);
1.1 root 5873: break;
5874: case 0x02: // recv from character device
5875: case 0x03: // send to character device
5876: case 0x04: // recv from block device
5877: case 0x05: // send to block device
5878: REG16(AX) = 0x05;
1.1.1.3 root 5879: m_CF = 1;
1.1 root 5880: break;
5881: case 0x06: // get read status
1.1.1.20 root 5882: if(file_mode[file_handler[fd].mode].in) {
5883: if(file_handler[fd].atty) {
1.1.1.14 root 5884: REG8(AL) = msdos_kbhit() ? 0xff : 0x00;
1.1 root 5885: } else {
1.1.1.20 root 5886: REG8(AL) = eof(fd) ? 0x00 : 0xff;
1.1 root 5887: }
1.1.1.14 root 5888: } else {
5889: REG8(AL) = 0x00;
1.1 root 5890: }
5891: break;
5892: case 0x07: // get write status
1.1.1.20 root 5893: if(file_mode[file_handler[fd].mode].out) {
1.1.1.14 root 5894: REG8(AL) = 0xff;
5895: } else {
5896: REG8(AL) = 0x00;
1.1 root 5897: }
5898: break;
5899: case 0x08: // check removable drive
1.1.1.14 root 5900: if(val == DRIVE_REMOVABLE || val == DRIVE_CDROM) {
5901: // removable drive
5902: REG16(AX) = 0x00;
1.1 root 5903: } else {
1.1.1.14 root 5904: // fixed drive
5905: REG16(AX) = 0x01;
1.1 root 5906: }
5907: break;
5908: case 0x09: // check remote drive
1.1.1.14 root 5909: if(val == DRIVE_REMOTE) {
5910: // remote drive
5911: REG16(DX) = 0x1000;
1.1 root 5912: } else {
1.1.1.14 root 5913: // local drive
5914: REG16(DX) = 0x00;
1.1 root 5915: }
5916: break;
1.1.1.21 root 5917: case 0x0a: // check remote handle
5918: REG16(DX) = 0x00; // FIXME
5919: break;
1.1 root 5920: case 0x0b: // set retry count
5921: break;
1.1.1.22! root 5922: case 0x0c: // generic character device request
! 5923: if(REG8(CL) == 0x45) {
! 5924: // set iteration (retry) count
! 5925: iteration_count = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX));
! 5926: } else if(REG8(CL) == 0x4a) {
! 5927: // select code page
! 5928: active_code_page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2);
! 5929: msdos_nls_tables_update();
! 5930: } else if(REG8(CL) == 0x65) {
! 5931: // get iteration (retry) count
! 5932: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX)) = iteration_count;
! 5933: } else if(REG8(CL) == 0x6a) {
! 5934: // query selected code page
! 5935: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = 2; // FIXME
! 5936: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2) = active_code_page;
! 5937:
! 5938: CPINFO info;
! 5939: GetCPInfo(active_code_page, &info);
! 5940:
! 5941: if(info.MaxCharSize != 1) {
! 5942: for(int i = 0;; i++) {
! 5943: UINT8 lo = info.LeadByte[2 * i + 0];
! 5944: UINT8 hi = info.LeadByte[2 * i + 1];
! 5945:
! 5946: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4 + 4 * i + 0) = lo;
! 5947: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4 + 4 * i + 2) = hi;
! 5948: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) + 4;
! 5949:
! 5950: if(lo == 0 && hi == 0) {
! 5951: break;
! 5952: }
! 5953: }
! 5954: }
! 5955: } else if(REG8(CL) == 0x7f) {
! 5956: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x00) = 0;
! 5957: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x01) = 0;
! 5958: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02) = 14;
! 5959: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x04) = 1;
! 5960: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x06) = 1;
! 5961: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x07) = 0;
! 5962: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x08) = 4;
! 5963: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0a) = 8 * (*(UINT16 *)(mem + 0x44a));
! 5964: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0c) = 16 * (*(UINT8 *)(mem + 0x484) + 1);
! 5965: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0e) = *(UINT16 *)(mem + 0x44a);
! 5966: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x10) = *(UINT8 *)(mem + 0x484) + 1;
! 5967: } else {
! 5968: 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));
! 5969: REG16(AX) = 0x01; // invalid function
! 5970: m_CF = 1;
! 5971: }
! 5972: break;
! 5973: case 0x0d: // generic block device request
! 5974: if(REG8(CL) == 0x40) {
! 5975: // set device parameters
! 5976: } else if(REG8(CL) == 0x46) {
! 5977: // set volume serial number
! 5978: } else if(REG8(CL) == 0x4a) {
! 5979: // lock logical volume
! 5980: } else if(REG8(CL) == 0x4b) {
! 5981: // lock physical volume
! 5982: } else if(REG8(CL) == 0x60) {
! 5983: // get device parameters
! 5984: char dev[] = "\\\\.\\A:";
! 5985: dev[4] = 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
! 5986:
! 5987: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
! 5988: if(hFile != INVALID_HANDLE_VALUE) {
! 5989: DISK_GEOMETRY geo;
! 5990: DWORD dwSize;
! 5991: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
! 5992: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x07; // ???
! 5993: switch(geo.MediaType) {
! 5994: case F5_360_512:
! 5995: case F5_320_512:
! 5996: case F5_320_1024:
! 5997: case F5_180_512:
! 5998: case F5_160_512:
! 5999: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x00; // 320K/360K disk
! 6000: break;
! 6001: case F5_1Pt2_512:
! 6002: case F3_1Pt2_512:
! 6003: case F3_1Pt23_1024:
! 6004: case F5_1Pt23_1024:
! 6005: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x01; // 1.2M disk
! 6006: break;
! 6007: case F3_720_512:
! 6008: case F3_640_512:
! 6009: case F5_640_512:
! 6010: case F5_720_512:
! 6011: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x02; // 720K disk
! 6012: break;
! 6013: case F8_256_128:
! 6014: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x03; // single-density 8-inch disk
! 6015: break;
! 6016: case FixedMedia:
! 6017: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // fixed disk
! 6018: break;
! 6019: case F3_1Pt44_512:
! 6020: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x07; // (DOS 3.3+) other type of block device, normally 1.44M floppy
! 6021: break;
! 6022: case F3_2Pt88_512:
! 6023: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x09; // (DOS 5+) 2.88M floppy
! 6024: break;
! 6025: default:
! 6026: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // fixed disk
! 6027: // *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // (DOS 3.3+) other type of block device, normally 1.44M floppy
! 6028: break;
! 6029: }
! 6030: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x02) = (geo.MediaType == FixedMedia) ? 0x01 : 0x00;
! 6031: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04) = (geo.Cylinders.QuadPart > 0xffff) ? 0xffff : geo.Cylinders.QuadPart;
! 6032: switch(geo.MediaType) {
! 6033: case F5_360_512:
! 6034: case F5_320_512:
! 6035: case F5_320_1024:
! 6036: case F5_180_512:
! 6037: case F5_160_512:
! 6038: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06) = 0x01; // 320K/360K disk
! 6039: break;
! 6040: default:
! 6041: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06) = 0x00; // other drive types
! 6042: break;
! 6043: }
! 6044: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x00) = geo.BytesPerSector;
! 6045: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x02) = geo.SectorsPerTrack * geo.TracksPerCylinder;
! 6046: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x03) = 0;
! 6047: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x05) = 0;
! 6048: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x06) = 0;
! 6049: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x08) = 0;
! 6050: switch(geo.MediaType) {
! 6051: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K)
! 6052: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xff;
! 6053: break;
! 6054: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K)
! 6055: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfe;
! 6056: break;
! 6057: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K)
! 6058: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfd;
! 6059: break;
! 6060: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K)
! 6061: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfc;
! 6062: break;
! 6063: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M)
! 6064: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5")
! 6065: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf9;
! 6066: break;
! 6067: case FixedMedia: // hard disk
! 6068: case RemovableMedia:
! 6069: case Unknown:
! 6070: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf8;
! 6071: break;
! 6072: default:
! 6073: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf0;
! 6074: break;
! 6075: }
! 6076: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0d) = geo.SectorsPerTrack;
! 6077: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0f) = 1;
! 6078: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x11) = 0;
! 6079: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x15) = geo.TracksPerCylinder * geo.Cylinders.QuadPart;
! 6080: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x1f) = geo.Cylinders.QuadPart;
! 6081: // 21h BYTE device type
! 6082: // 22h WORD device attributes (removable or not, etc)
! 6083: } else {
! 6084: REG16(AX) = 0x0f; // invalid drive
! 6085: m_CF = 1;
! 6086: }
! 6087: CloseHandle(hFile);
! 6088: } else {
! 6089: REG16(AX) = 0x0f; // invalid drive
! 6090: m_CF = 1;
! 6091: }
! 6092: } else if(REG8(CL) == 0x66) {
! 6093: // get volume serial number
! 6094: char path[] = "A:\\";
! 6095: char volume_label[MAX_PATH];
! 6096: DWORD serial_number = 0;
! 6097: char file_system[MAX_PATH];
! 6098:
! 6099: path[0] = 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
! 6100:
! 6101: if(GetVolumeInformation(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) {
! 6102: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0;
! 6103: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x02) = serial_number;
! 6104: memset(mem + SREG_BASE(DS) + REG16(SI) + 0x06, 0x20, 11);
! 6105: memcpy(mem + SREG_BASE(DS) + REG16(SI) + 0x06, volume_label, min(strlen(volume_label), 11));
! 6106: memset(mem + SREG_BASE(DS) + REG16(SI) + 0x11, 0x20, 8);
! 6107: memcpy(mem + SREG_BASE(DS) + REG16(SI) + 0x11, file_system, min(strlen(file_system), 8));
! 6108: } else {
! 6109: REG16(AX) = 0x0f; // invalid drive
! 6110: m_CF = 1;
! 6111: }
! 6112: } else if(REG8(CL) == 0x67) {
! 6113: // get access flag
! 6114: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0;
! 6115: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 1;
! 6116: } else if(REG8(CL) == 0x68) {
! 6117: // sense media type
! 6118: char dev[64];
! 6119: sprintf(dev, "\\\\.\\%c:", 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1);
! 6120:
! 6121: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
! 6122: if(hFile != INVALID_HANDLE_VALUE) {
! 6123: DISK_GEOMETRY geo;
! 6124: DWORD dwSize;
! 6125: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
! 6126: switch(geo.MediaType) {
! 6127: case F3_720_512:
! 6128: case F5_720_512:
! 6129: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
! 6130: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x02;
! 6131: break;
! 6132: case F3_1Pt44_512:
! 6133: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
! 6134: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x07;
! 6135: break;
! 6136: case F3_2Pt88_512:
! 6137: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
! 6138: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x09;
! 6139: break;
! 6140: default:
! 6141: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x00;
! 6142: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x00; // ???
! 6143: break;
! 6144: }
! 6145: } else {
! 6146: REG16(AX) = 0x0f; // invalid drive
! 6147: m_CF = 1;
! 6148: }
! 6149: CloseHandle(hFile);
! 6150: } else {
! 6151: REG16(AX) = 0x0f; // invalid drive
! 6152: m_CF = 1;
! 6153: }
! 6154: } else if(REG8(CL) == 0x6a) {
! 6155: // unlock logical volume
! 6156: } else if(REG8(CL) == 0x6b) {
! 6157: // unlock physical volume
! 6158: } else {
! 6159: 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));
! 6160: REG16(AX) = 0x01; // invalid function
! 6161: m_CF = 1;
! 6162: }
! 6163: break;
! 6164: case 0x0e: // get logical drive map
! 6165: {
! 6166: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
! 6167: if(!(GetLogicalDrives() & bits)) {
! 6168: REG16(AX) = 0x0f; // invalid drive
! 6169: m_CF = 1;
! 6170: } else {
! 6171: REG8(AL) = 0;
! 6172: }
! 6173: }
! 6174: break;
! 6175: case 0x0f: // set logical drive map
! 6176: {
! 6177: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
! 6178: if(!(GetLogicalDrives() & bits)) {
! 6179: REG16(AX) = 0x0f; // invalid drive
! 6180: m_CF = 1;
! 6181: }
! 6182: }
! 6183: break;
! 6184: case 0x10: // query generic ioctrl capability (handle)
! 6185: switch(REG8(CL)) {
! 6186: case 0x45:
! 6187: case 0x4a:
! 6188: case 0x65:
! 6189: case 0x6a:
! 6190: case 0x7f:
! 6191: REG16(AX) = 0x0000; // supported
! 6192: break;
! 6193: default:
! 6194: REG8(AL) = 0x01; // ioctl capability not available
! 6195: m_CF = 1;
! 6196: break;
! 6197: }
! 6198: break;
! 6199: case 0x11: // query generic ioctrl capability (drive)
! 6200: switch(REG8(CL)) {
! 6201: case 0x40:
! 6202: case 0x46:
! 6203: case 0x4a:
! 6204: case 0x4b:
! 6205: case 0x60:
! 6206: case 0x66:
! 6207: case 0x67:
! 6208: case 0x68:
! 6209: case 0x6a:
! 6210: case 0x6b:
! 6211: REG16(AX) = 0x0000; // supported
! 6212: break;
! 6213: default:
! 6214: REG8(AL) = 0x01; // ioctl capability not available
! 6215: m_CF = 1;
! 6216: break;
! 6217: }
! 6218: break;
! 6219: case 0x12: // determine dos type
! 6220: case 0x51: // concurrent dos v3.2+ - installation check
! 6221: case 0x52: // determine dos type/get dr dos versuin
! 6222: REG16(AX) = 0x01; // this is not DR-DOS
! 6223: m_CF = 1;
! 6224: break;
1.1 root 6225: default:
1.1.1.22! root 6226: 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 6227: REG16(AX) = 0x01;
1.1.1.3 root 6228: m_CF = 1;
1.1 root 6229: break;
6230: }
6231: }
6232:
6233: inline void msdos_int_21h_45h()
6234: {
6235: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 6236: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 6237:
1.1.1.20 root 6238: if(fd < process->max_files && file_handler[fd].valid) {
6239: int dup_fd = _dup(fd);
6240: if(dup_fd != -1) {
6241: REG16(AX) = dup_fd;
6242: msdos_file_handler_dup(dup_fd, fd, current_psp);
6243: // msdos_psp_set_file_table(dup_fd, fd, current_psp);
6244: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp);
1.1 root 6245: } else {
6246: REG16(AX) = errno;
1.1.1.3 root 6247: m_CF = 1;
1.1 root 6248: }
6249: } else {
6250: REG16(AX) = 0x06;
1.1.1.3 root 6251: m_CF = 1;
1.1 root 6252: }
6253: }
6254:
6255: inline void msdos_int_21h_46h()
6256: {
6257: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 6258: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
6259: int dup_fd = REG16(CX);
6260: int tmp_fd = msdos_psp_get_file_table(REG16(CX), current_psp);
1.1 root 6261:
1.1.1.20 root 6262: if(REG16(BX) == REG16(CX)) {
6263: REG16(AX) = 0x06;
6264: m_CF = 1;
6265: } else if(fd < process->max_files && file_handler[fd].valid && dup_fd < process->max_files) {
6266: if(tmp_fd < process->max_files && file_handler[tmp_fd].valid) {
6267: _close(tmp_fd);
6268: msdos_file_handler_close(tmp_fd);
6269: msdos_psp_set_file_table(dup_fd, 0x0ff, current_psp);
6270: }
6271: if(_dup2(fd, dup_fd) != -1) {
6272: msdos_file_handler_dup(dup_fd, fd, current_psp);
6273: // msdos_psp_set_file_table(dup_fd, fd, current_psp);
6274: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp);
1.1 root 6275: } else {
6276: REG16(AX) = errno;
1.1.1.3 root 6277: m_CF = 1;
1.1 root 6278: }
6279: } else {
6280: REG16(AX) = 0x06;
1.1.1.3 root 6281: m_CF = 1;
1.1 root 6282: }
6283: }
6284:
6285: inline void msdos_int_21h_47h(int lfn)
6286: {
6287: char path[MAX_PATH];
6288:
6289: if(_getdcwd(REG8(DL), path, MAX_PATH) != NULL) {
6290: if(path[1] == ':') {
6291: // the returned path does not include a drive or the initial backslash
1.1.1.3 root 6292: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), (lfn ? path : msdos_short_path(path)) + 3);
1.1 root 6293: } else {
1.1.1.3 root 6294: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn ? path : msdos_short_path(path));
1.1 root 6295: }
6296: } else {
6297: REG16(AX) = errno;
1.1.1.3 root 6298: m_CF = 1;
1.1 root 6299: }
6300: }
6301:
6302: inline void msdos_int_21h_48h()
6303: {
1.1.1.19 root 6304: int seg, umb_linked;
1.1 root 6305:
1.1.1.8 root 6306: if((malloc_strategy & 0xf0) == 0x00) {
1.1.1.19 root 6307: // unlink umb not to allocate memory in umb
6308: if((umb_linked = msdos_mem_get_umb_linked()) != 0) {
6309: msdos_mem_unlink_umb();
6310: }
1.1.1.8 root 6311: if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
6312: REG16(AX) = seg;
6313: } else {
6314: REG16(AX) = 0x08;
6315: REG16(BX) = msdos_mem_get_free(first_mcb, 0);
6316: m_CF = 1;
6317: }
1.1.1.19 root 6318: if(umb_linked != 0) {
6319: msdos_mem_link_umb();
6320: }
1.1.1.8 root 6321: } else if((malloc_strategy & 0xf0) == 0x40) {
6322: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
6323: REG16(AX) = seg;
6324: } else {
6325: REG16(AX) = 0x08;
6326: REG16(BX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
6327: m_CF = 1;
6328: }
6329: } else if((malloc_strategy & 0xf0) == 0x80) {
6330: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
6331: REG16(AX) = seg;
6332: } else if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
6333: REG16(AX) = seg;
6334: } else {
6335: REG16(AX) = 0x08;
6336: REG16(BX) = max(msdos_mem_get_free(UMB_TOP >> 4, 0), msdos_mem_get_free(first_mcb, 0));
6337: m_CF = 1;
6338: }
1.1 root 6339: }
6340: }
6341:
6342: inline void msdos_int_21h_49h()
6343: {
1.1.1.14 root 6344: int mcb_seg = SREG(ES) - 1;
6345: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
6346:
6347: if(mcb->mz == 'M' || mcb->mz == 'Z') {
6348: msdos_mem_free(SREG(ES));
6349: } else {
6350: REG16(AX) = 9;
6351: m_CF = 1;
6352: }
1.1 root 6353: }
6354:
6355: inline void msdos_int_21h_4ah()
6356: {
1.1.1.14 root 6357: int mcb_seg = SREG(ES) - 1;
6358: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1 root 6359: int max_paragraphs;
6360:
1.1.1.14 root 6361: if(mcb->mz == 'M' || mcb->mz == 'Z') {
6362: if(msdos_mem_realloc(SREG(ES), REG16(BX), &max_paragraphs)) {
6363: REG16(AX) = 0x08;
6364: REG16(BX) = max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs;
6365: m_CF = 1;
6366: }
6367: } else {
6368: REG16(AX) = 7;
1.1.1.3 root 6369: m_CF = 1;
1.1 root 6370: }
6371: }
6372:
6373: inline void msdos_int_21h_4bh()
6374: {
1.1.1.3 root 6375: char *command = (char *)(mem + SREG_BASE(DS) + REG16(DX));
6376: param_block_t *param = (param_block_t *)(mem + SREG_BASE(ES) + REG16(BX));
1.1 root 6377:
6378: switch(REG8(AL)) {
6379: case 0x00:
6380: case 0x01:
6381: if(msdos_process_exec(command, param, REG8(AL))) {
6382: REG16(AX) = 0x02;
1.1.1.3 root 6383: m_CF = 1;
1.1 root 6384: }
6385: break;
1.1.1.14 root 6386: case 0x03:
6387: {
6388: int fd;
6389: if((fd = _open(command, _O_RDONLY | _O_BINARY)) == -1) {
6390: REG16(AX) = 0x02;
6391: m_CF = 1;
6392: break;
6393: }
6394: int size = _read(fd, file_buffer, sizeof(file_buffer));
6395: _close(fd);
6396:
6397: UINT16 *overlay = (UINT16 *)param;
6398:
6399: // check exe header
6400: exe_header_t *header = (exe_header_t *)file_buffer;
6401: int header_size = 0;
6402: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
6403: header_size = header->header_size * 16;
6404: // relocation
6405: int start_seg = overlay[1];
6406: for(int i = 0; i < header->relocations; i++) {
6407: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
6408: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
6409: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
6410: }
6411: }
6412: memcpy(mem + (overlay[0] << 4), file_buffer + header_size, size - header_size);
6413: }
6414: break;
1.1 root 6415: default:
1.1.1.22! root 6416: 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 6417: REG16(AX) = 0x01;
1.1.1.3 root 6418: m_CF = 1;
1.1 root 6419: break;
6420: }
6421: }
6422:
6423: inline void msdos_int_21h_4ch()
6424: {
6425: msdos_process_terminate(current_psp, REG8(AL), 1);
6426: }
6427:
6428: inline void msdos_int_21h_4dh()
6429: {
6430: REG16(AX) = retval;
6431: }
6432:
6433: inline void msdos_int_21h_4eh()
6434: {
6435: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 6436: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
6437: find_t *find = (find_t *)(mem + dta_laddr);
1.1.1.3 root 6438: char *path = msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 6439: WIN32_FIND_DATA fd;
6440:
1.1.1.14 root 6441: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
6442: find->find_magic = FIND_MAGIC;
6443: find->dta_index = dtainfo - dtalist;
1.1 root 6444: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 6445: dtainfo->allowable_mask = REG8(CL);
6446: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 6447:
1.1.1.14 root 6448: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
6449: dtainfo->allowable_mask &= ~8;
1.1 root 6450: }
1.1.1.14 root 6451: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
6452: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 6453: !msdos_find_file_has_8dot3name(&fd)) {
6454: if(!FindNextFile(dtainfo->find_handle, &fd)) {
6455: FindClose(dtainfo->find_handle);
6456: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6457: break;
6458: }
6459: }
6460: }
1.1.1.13 root 6461: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 6462: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
6463: msdos_find_file_conv_local_time(&fd);
6464: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
6465: find->size = fd.nFileSizeLow;
1.1.1.13 root 6466: strcpy(find->name, msdos_short_name(&fd));
1.1 root 6467: REG16(AX) = 0;
1.1.1.14 root 6468: } else if(dtainfo->allowable_mask & 8) {
1.1 root 6469: find->attrib = 8;
6470: find->size = 0;
6471: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 6472: dtainfo->allowable_mask &= ~8;
1.1 root 6473: REG16(AX) = 0;
6474: } else {
6475: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 6476: m_CF = 1;
1.1 root 6477: }
6478: }
6479:
6480: inline void msdos_int_21h_4fh()
6481: {
6482: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 6483: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
6484: find_t *find = (find_t *)(mem + dta_laddr);
1.1 root 6485: WIN32_FIND_DATA fd;
6486:
1.1.1.14 root 6487: if(find->find_magic != FIND_MAGIC || find->dta_index >= MAX_DTAINFO) {
6488: REG16(AX) = 0x12;
6489: m_CF = 1;
6490: return;
6491: }
6492: dtainfo_t *dtainfo = &dtalist[find->dta_index];
1.1.1.13 root 6493: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
6494: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 6495: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 6496: !msdos_find_file_has_8dot3name(&fd)) {
6497: if(!FindNextFile(dtainfo->find_handle, &fd)) {
6498: FindClose(dtainfo->find_handle);
6499: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6500: break;
6501: }
6502: }
6503: } else {
1.1.1.13 root 6504: FindClose(dtainfo->find_handle);
6505: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6506: }
6507: }
1.1.1.13 root 6508: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 6509: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
6510: msdos_find_file_conv_local_time(&fd);
6511: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
6512: find->size = fd.nFileSizeLow;
1.1.1.13 root 6513: strcpy(find->name, msdos_short_name(&fd));
1.1 root 6514: REG16(AX) = 0;
1.1.1.14 root 6515: } else if(dtainfo->allowable_mask & 8) {
1.1 root 6516: find->attrib = 8;
6517: find->size = 0;
6518: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 6519: dtainfo->allowable_mask &= ~8;
1.1 root 6520: REG16(AX) = 0;
6521: } else {
6522: REG16(AX) = 0x12;
1.1.1.3 root 6523: m_CF = 1;
1.1 root 6524: }
6525: }
6526:
6527: inline void msdos_int_21h_50h()
6528: {
1.1.1.8 root 6529: if(current_psp != REG16(BX)) {
6530: process_t *process = msdos_process_info_get(current_psp);
6531: if(process != NULL) {
6532: process->psp = REG16(BX);
6533: }
6534: current_psp = REG16(BX);
6535: }
1.1 root 6536: }
6537:
6538: inline void msdos_int_21h_51h()
6539: {
6540: REG16(BX) = current_psp;
6541: }
6542:
6543: inline void msdos_int_21h_52h()
6544: {
1.1.1.3 root 6545: SREG(ES) = (DOS_INFO_BASE >> 4);
6546: i386_load_segment_descriptor(ES);
1.1 root 6547: REG16(BX) = (DOS_INFO_BASE & 0x0f);
6548: }
6549:
6550: inline void msdos_int_21h_54h()
6551: {
6552: process_t *process = msdos_process_info_get(current_psp);
6553:
6554: REG8(AL) = process->verify;
6555: }
6556:
6557: inline void msdos_int_21h_55h()
6558: {
6559: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
6560:
6561: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
6562: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
6563: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
6564: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
6565: psp->parent_psp = current_psp;
6566: }
6567:
6568: inline void msdos_int_21h_56h(int lfn)
6569: {
6570: char src[MAX_PATH], dst[MAX_PATH];
1.1.1.3 root 6571: strcpy(src, msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn));
6572: strcpy(dst, msdos_trimmed_path((char *)(mem + SREG_BASE(ES) + REG16(DI)), lfn));
1.1 root 6573:
6574: if(rename(src, dst)) {
6575: REG16(AX) = errno;
1.1.1.3 root 6576: m_CF = 1;
1.1 root 6577: }
6578: }
6579:
6580: inline void msdos_int_21h_57h()
6581: {
6582: FILETIME time, local;
1.1.1.14 root 6583: FILETIME *ctime, *atime, *mtime;
1.1.1.21 root 6584: HANDLE hHandle;
1.1 root 6585:
1.1.1.21 root 6586: if((hHandle = (HANDLE)_get_osfhandle(REG16(BX))) == INVALID_HANDLE_VALUE) {
1.1.1.14 root 6587: REG16(AX) = (UINT16)GetLastError();
6588: m_CF = 1;
6589: return;
6590: }
6591: ctime = atime = mtime = NULL;
6592:
1.1 root 6593: switch(REG8(AL)) {
6594: case 0x00:
1.1.1.6 root 6595: case 0x01:
1.1.1.14 root 6596: mtime = &time;
1.1.1.6 root 6597: break;
6598: case 0x04:
6599: case 0x05:
1.1.1.14 root 6600: atime = &time;
1.1 root 6601: break;
1.1.1.6 root 6602: case 0x06:
6603: case 0x07:
1.1.1.14 root 6604: ctime = &time;
6605: break;
6606: default:
1.1.1.22! root 6607: 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 6608: REG16(AX) = 0x01;
6609: m_CF = 1;
6610: return;
6611: }
6612: if(REG8(AL) & 1) {
1.1 root 6613: DosDateTimeToFileTime(REG16(DX), REG16(CX), &local);
6614: LocalFileTimeToFileTime(&local, &time);
1.1.1.21 root 6615: if(!SetFileTime(hHandle, ctime, atime, mtime)) {
1.1 root 6616: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 6617: m_CF = 1;
1.1 root 6618: }
1.1.1.14 root 6619: } else {
1.1.1.21 root 6620: if(!GetFileTime(hHandle, ctime, atime, mtime)) {
1.1.1.14 root 6621: // assume a device and use the current time
6622: GetSystemTimeAsFileTime(&time);
6623: }
6624: FileTimeToLocalFileTime(&time, &local);
6625: FileTimeToDosDateTime(&local, ®16(DX), ®16(CX));
1.1 root 6626: }
6627: }
6628:
6629: inline void msdos_int_21h_58h()
6630: {
6631: switch(REG8(AL)) {
6632: case 0x00:
1.1.1.7 root 6633: REG16(AX) = malloc_strategy;
6634: break;
6635: case 0x01:
6636: switch(REG16(BX)) {
6637: case 0x0000:
6638: case 0x0001:
6639: case 0x0002:
6640: case 0x0040:
6641: case 0x0041:
6642: case 0x0042:
6643: case 0x0080:
6644: case 0x0081:
6645: case 0x0082:
6646: malloc_strategy = REG16(BX);
6647: break;
6648: default:
1.1.1.22! root 6649: 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 6650: REG16(AX) = 0x01;
6651: m_CF = 1;
6652: break;
6653: }
6654: break;
6655: case 0x02:
1.1.1.19 root 6656: REG8(AL) = msdos_mem_get_umb_linked() ? 1 : 0;
1.1.1.7 root 6657: break;
6658: case 0x03:
6659: switch(REG16(BX)) {
6660: case 0x0000:
1.1.1.19 root 6661: msdos_mem_unlink_umb();
6662: break;
1.1.1.7 root 6663: case 0x0001:
1.1.1.19 root 6664: msdos_mem_link_umb();
1.1.1.7 root 6665: break;
6666: default:
1.1.1.22! root 6667: 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 6668: REG16(AX) = 0x01;
6669: m_CF = 1;
6670: break;
6671: }
1.1 root 6672: break;
6673: default:
1.1.1.22! root 6674: 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 6675: REG16(AX) = 0x01;
1.1.1.3 root 6676: m_CF = 1;
1.1 root 6677: break;
6678: }
6679: }
6680:
6681: inline void msdos_int_21h_59h()
6682: {
6683: REG16(AX) = error_code;
6684: switch(error_code) {
6685: case 4: // Too many open files
6686: case 8: // Insufficient memory
6687: REG8(BH) = 1; // Out of resource
6688: break;
6689: case 5: // Access denied
6690: REG8(BH) = 3; // Authorization
6691: break;
6692: case 7: // Memory control block destroyed
6693: REG8(BH) = 4; // Internal
6694: break;
6695: case 2: // File not found
6696: case 3: // Path not found
6697: case 15: // Invaid drive specified
6698: case 18: // No more files
6699: REG8(BH) = 8; // Not found
6700: break;
6701: case 32: // Sharing violation
6702: case 33: // Lock violation
6703: REG8(BH) = 10; // Locked
6704: break;
6705: // case 16: // Removal of current directory attempted
6706: case 19: // Attempted write on protected disk
6707: case 21: // Drive not ready
6708: // case 29: // Write failure
6709: // case 30: // Read failure
6710: // case 82: // Cannot create subdirectory
6711: REG8(BH) = 11; // Media
6712: break;
6713: case 80: // File already exists
6714: REG8(BH) = 12; // Already exist
6715: break;
6716: default:
6717: REG8(BH) = 13; // Unknown
6718: break;
6719: }
6720: REG8(BL) = 1; // Retry
6721: REG8(CH) = 1; // Unknown
6722: }
6723:
6724: inline void msdos_int_21h_5ah()
6725: {
1.1.1.3 root 6726: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 6727: int len = strlen(path);
6728: char tmp[MAX_PATH];
6729:
6730: if(GetTempFileName(path, "TMP", 0, tmp)) {
6731: int fd = _open(tmp, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
6732:
6733: SetFileAttributes(tmp, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
6734: REG16(AX) = fd;
6735: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 6736: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 6737:
6738: strcpy(path, tmp);
6739: int dx = REG16(DX) + len;
1.1.1.3 root 6740: int ds = SREG(DS);
1.1 root 6741: while(dx > 0xffff) {
6742: dx -= 0x10;
6743: ds++;
6744: }
6745: REG16(DX) = dx;
1.1.1.3 root 6746: SREG(DS) = ds;
6747: i386_load_segment_descriptor(DS);
1.1 root 6748: } else {
6749: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 6750: m_CF = 1;
1.1 root 6751: }
6752: }
6753:
6754: inline void msdos_int_21h_5bh()
6755: {
1.1.1.3 root 6756: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 6757:
6758: if(_access(path, 0) == 0) {
6759: // already exists
6760: REG16(AX) = 0x50;
1.1.1.3 root 6761: m_CF = 1;
1.1 root 6762: } else {
6763: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
6764:
6765: if(fd != -1) {
6766: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
6767: REG16(AX) = fd;
6768: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 6769: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 6770: } else {
6771: REG16(AX) = errno;
1.1.1.3 root 6772: m_CF = 1;
1.1 root 6773: }
6774: }
6775: }
6776:
6777: inline void msdos_int_21h_5ch()
6778: {
6779: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 6780: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 6781:
1.1.1.20 root 6782: if(fd < process->max_files && file_handler[fd].valid) {
1.1 root 6783: if(REG8(AL) == 0 || REG8(AL) == 1) {
6784: static int modes[2] = {_LK_LOCK, _LK_UNLCK};
1.1.1.20 root 6785: UINT32 pos = _tell(fd);
6786: _lseek(fd, (REG16(CX) << 16) | REG16(DX), SEEK_SET);
6787: if(_locking(fd, modes[REG8(AL)], (REG16(SI) << 16) | REG16(DI))) {
1.1 root 6788: REG16(AX) = errno;
1.1.1.3 root 6789: m_CF = 1;
1.1 root 6790: }
1.1.1.20 root 6791: _lseek(fd, pos, SEEK_SET);
1.1 root 6792: // some seconds may be passed in _locking()
6793: hardware_update();
6794: } else {
6795: REG16(AX) = 0x01;
1.1.1.3 root 6796: m_CF = 1;
1.1 root 6797: }
6798: } else {
6799: REG16(AX) = 0x06;
1.1.1.3 root 6800: m_CF = 1;
1.1 root 6801: }
6802: }
6803:
1.1.1.22! root 6804: inline void msdos_int_21h_5dh()
! 6805: {
! 6806: switch(REG8(AL)) {
! 6807: case 0x06: // get address of dos swappable data area
! 6808: case 0x0b: // get dos swappable data reas
! 6809: REG16(AX) = 0x01;
! 6810: m_CF = 1;
! 6811: break;
! 6812: case 0x08: // set redirected printer mode
! 6813: case 0x09: // flush redirected printer output
! 6814: case 0x0a: // set extended error information
! 6815: break;
! 6816: default:
! 6817: 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));
! 6818: REG16(AX) = 0x01;
! 6819: m_CF = 1;
! 6820: break;
! 6821: }
! 6822: }
! 6823:
1.1 root 6824: inline void msdos_int_21h_60h(int lfn)
6825: {
1.1.1.14 root 6826: char full[MAX_PATH], *path;
6827:
1.1 root 6828: if(lfn) {
1.1.1.14 root 6829: char *name;
6830: *full = '\0';
1.1.1.3 root 6831: GetFullPathName((char *)(mem + SREG_BASE(DS) + REG16(SI)), MAX_PATH, full, &name);
1.1.1.14 root 6832: switch(REG8(CL)) {
6833: case 1:
6834: GetShortPathName(full, full, MAX_PATH);
6835: my_strupr(full);
6836: break;
6837: case 2:
6838: GetLongPathName(full, full, MAX_PATH);
6839: break;
6840: }
6841: path = full;
6842: } else {
6843: path = msdos_short_full_path((char *)(mem + SREG_BASE(DS) + REG16(SI)));
6844: }
6845: if(*path != '\0') {
6846: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), path);
1.1 root 6847: } else {
1.1.1.14 root 6848: REG16(AX) = (UINT16)GetLastError();
6849: m_CF = 1;
1.1 root 6850: }
6851: }
6852:
6853: inline void msdos_int_21h_61h()
6854: {
6855: REG8(AL) = 0;
6856: }
6857:
6858: inline void msdos_int_21h_62h()
6859: {
6860: REG16(BX) = current_psp;
6861: }
6862:
6863: inline void msdos_int_21h_63h()
6864: {
6865: switch(REG8(AL)) {
6866: case 0x00:
1.1.1.3 root 6867: SREG(DS) = (DBCS_TABLE >> 4);
6868: i386_load_segment_descriptor(DS);
1.1 root 6869: REG16(SI) = (DBCS_TABLE & 0x0f);
6870: REG8(AL) = 0x00;
6871: break;
1.1.1.22! root 6872: case 0x01: // set korean input mode
! 6873: case 0x02: // get korean input mode
! 6874: REG8(AL) = 0xff; // not supported
! 6875: break;
1.1 root 6876: default:
1.1.1.22! root 6877: 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 6878: REG16(AX) = 0x01;
1.1.1.3 root 6879: m_CF = 1;
1.1 root 6880: break;
6881: }
6882: }
6883:
6884: inline void msdos_int_21h_65h()
6885: {
6886: char tmp[0x10000];
6887:
6888: switch(REG8(AL)) {
1.1.1.17 root 6889: case 0x01:
6890: if(REG16(CX) >= 5) {
1.1.1.19 root 6891: UINT8 data[1 + 2 + 2 + 2 + sizeof(country_info_t)];
1.1.1.17 root 6892: if(REG16(CX) > sizeof(data)) // cx = actual transfer size
6893: REG16(CX) = sizeof(data);
6894: ZeroMemory(data, sizeof(data));
6895: data[0] = 0x01;
6896: *(UINT16 *)(data + 1) = REG16(CX) - 3;
1.1.1.19 root 6897: *(UINT16 *)(data + 3) = get_country_info((country_info_t*)(data + 7));
1.1.1.17 root 6898: *(UINT16 *)(data + 5) = active_code_page;
6899: memcpy(mem + SREG_BASE(ES) + REG16(DI), data, REG16(CX));
6900: REG16(AX) = active_code_page;
6901: } else {
6902: REG16(AX) = 1;
6903: m_CF = 1;
6904: }
6905: break;
6906: case 0x02:
6907: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x02;
6908: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (UPPERTABLE_TOP & 0x0f);
6909: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (UPPERTABLE_TOP >> 4);
6910: REG16(AX) = active_code_page;
6911: REG16(CX) = 0x05;
6912: break;
6913: case 0x04:
6914: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x04;
6915: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_UPPERTABLE_TOP & 0x0f);
6916: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_UPPERTABLE_TOP >> 4);
6917: REG16(AX) = active_code_page;
6918: REG16(CX) = 0x05;
6919: break;
6920: case 0x05:
6921: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x05;
6922: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_TERMINATOR_TOP & 0x0f);
6923: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_TERMINATOR_TOP >> 4);
6924: REG16(AX) = active_code_page;
6925: REG16(CX) = 0x05;
6926: break;
6927: case 0x06:
6928: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x06;
6929: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (COLLATING_TABLE_TOP & 0x0f);
6930: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (COLLATING_TABLE_TOP >> 4);
6931: REG16(AX) = active_code_page;
6932: REG16(CX) = 0x05;
6933: break;
1.1 root 6934: case 0x07:
1.1.1.3 root 6935: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x07;
6936: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (DBCS_TOP & 0x0f);
6937: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (DBCS_TOP >> 4);
1.1.1.17 root 6938: REG16(AX) = active_code_page;
1.1 root 6939: REG16(CX) = 0x05;
6940: break;
6941: case 0x20:
1.1.1.19 root 6942: memset(tmp, 0, sizeof(tmp));
6943: tmp[0] = REG8(DL);
1.1 root 6944: my_strupr(tmp);
6945: REG8(DL) = tmp[0];
6946: break;
6947: case 0x21:
6948: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 6949: memcpy(tmp, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 6950: my_strupr(tmp);
1.1.1.3 root 6951: memcpy(mem + SREG_BASE(DS) + REG16(DX), tmp, REG16(CX));
1.1 root 6952: break;
6953: case 0x22:
1.1.1.3 root 6954: my_strupr((char *)(mem + SREG_BASE(DS) + REG16(DX)));
1.1 root 6955: break;
6956: default:
1.1.1.22! root 6957: 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 6958: REG16(AX) = 0x01;
1.1.1.3 root 6959: m_CF = 1;
1.1 root 6960: break;
6961: }
6962: }
6963:
6964: inline void msdos_int_21h_66h()
6965: {
6966: switch(REG8(AL)) {
6967: case 0x01:
6968: REG16(BX) = active_code_page;
6969: REG16(DX) = system_code_page;
6970: break;
6971: case 0x02:
6972: if(active_code_page == REG16(BX)) {
6973: REG16(AX) = 0xeb41;
6974: } else if(_setmbcp(REG16(BX)) == 0) {
6975: active_code_page = REG16(BX);
1.1.1.17 root 6976: msdos_nls_tables_update();
1.1 root 6977: REG16(AX) = 0xeb41;
6978: } else {
6979: REG16(AX) = 0x25;
1.1.1.3 root 6980: m_CF = 1;
1.1 root 6981: }
6982: break;
6983: default:
1.1.1.22! root 6984: 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 6985: REG16(AX) = 0x01;
1.1.1.3 root 6986: m_CF = 1;
1.1 root 6987: break;
6988: }
6989: }
6990:
6991: inline void msdos_int_21h_67h()
6992: {
6993: process_t *process = msdos_process_info_get(current_psp);
6994:
6995: if(REG16(BX) <= MAX_FILES) {
6996: process->max_files = max(REG16(BX), 20);
6997: } else {
6998: REG16(AX) = 0x08;
1.1.1.3 root 6999: m_CF = 1;
1.1 root 7000: }
7001: }
7002:
7003: inline void msdos_int_21h_68h()
7004: {
7005: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 7006: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 7007:
1.1.1.20 root 7008: if(fd < process->max_files && file_handler[fd].valid) {
7009: // fflush(_fdopen(fd, ""));
1.1 root 7010: } else {
7011: REG16(AX) = 0x06;
1.1.1.3 root 7012: m_CF = 1;
1.1 root 7013: }
7014: }
7015:
7016: inline void msdos_int_21h_69h()
7017: {
1.1.1.3 root 7018: drive_info_t *info = (drive_info_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 7019: char path[] = "A:\\";
7020: char volume_label[MAX_PATH];
7021: DWORD serial_number = 0;
7022: char file_system[MAX_PATH];
7023:
7024: if(REG8(BL) == 0) {
7025: path[0] = 'A' + _getdrive() - 1;
7026: } else {
7027: path[0] = 'A' + REG8(BL) - 1;
7028: }
7029:
7030: switch(REG8(AL)) {
7031: case 0x00:
7032: if(GetVolumeInformation(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) {
7033: info->info_level = 0;
7034: info->serial_number = serial_number;
7035: memset(info->volume_label, 0x20, 11);
7036: memcpy(info->volume_label, volume_label, min(strlen(volume_label), 11));
7037: memset(info->file_system, 0x20, 8);
7038: memcpy(info->file_system, file_system, min(strlen(file_system), 8));
7039: } else {
7040: REG16(AX) = errno;
1.1.1.3 root 7041: m_CF = 1;
1.1 root 7042: }
7043: break;
7044: case 0x01:
7045: REG16(AX) = 0x03;
1.1.1.3 root 7046: m_CF = 1;
1.1 root 7047: }
7048: }
7049:
7050: inline void msdos_int_21h_6ah()
7051: {
7052: REG8(AH) = 0x68;
7053: msdos_int_21h_68h();
7054: }
7055:
7056: inline void msdos_int_21h_6bh()
7057: {
7058: REG8(AL) = 0;
7059: }
7060:
7061: inline void msdos_int_21h_6ch(int lfn)
7062: {
1.1.1.3 root 7063: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn);
1.1 root 7064: int mode = REG8(BL) & 0x03;
7065:
7066: if(mode < 0x03) {
1.1.1.20 root 7067: if(_access(path, 0) == 0 || strncmp(path, "EMMXXXX0", 8) == 0) {
1.1 root 7068: // file exists
7069: if(REG8(DL) & 1) {
1.1.1.11 root 7070: int fd = -1;
7071: UINT16 info;
1.1 root 7072:
1.1.1.11 root 7073: if(msdos_is_con_path(path)) {
1.1.1.13 root 7074: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 7075: info = 0x80d3;
1.1.1.14 root 7076: } else if(msdos_is_nul_path(path)) {
7077: fd = msdos_open("NUL", file_mode[mode].mode);
7078: info = 0x80d3;
1.1.1.20 root 7079: } else if(strncmp(path, "EMMXXXX0", 8) == 0) {
7080: fd = msdos_open("NUL", file_mode[mode].mode);
7081: info = 0x80d3;
1.1.1.11 root 7082: } else {
1.1.1.13 root 7083: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 7084: info = msdos_drive_number(path);
7085: }
1.1 root 7086: if(fd != -1) {
7087: REG16(AX) = fd;
7088: REG16(CX) = 1;
1.1.1.11 root 7089: msdos_file_handler_open(fd, path, _isatty(fd), mode, info, current_psp);
1.1.1.20 root 7090: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 7091: } else {
7092: REG16(AX) = errno;
1.1.1.3 root 7093: m_CF = 1;
1.1 root 7094: }
7095: } else if(REG8(DL) & 2) {
7096: int attr = GetFileAttributes(path);
7097: int fd = -1;
1.1.1.11 root 7098: UINT16 info;
1.1 root 7099:
1.1.1.11 root 7100: if(msdos_is_con_path(path)) {
1.1.1.13 root 7101: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 7102: info = 0x80d3;
1.1.1.14 root 7103: } else if(msdos_is_nul_path(path)) {
7104: fd = msdos_open("NUL", file_mode[mode].mode);
7105: info = 0x80d3;
1.1.1.20 root 7106: } else if(strncmp(path, "EMMXXXX0", 8) == 0) {
7107: fd = msdos_open("NUL", file_mode[mode].mode);
7108: info = 0x80d3;
1.1 root 7109: } else {
7110: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
1.1.1.11 root 7111: info = msdos_drive_number(path);
1.1 root 7112: }
7113: if(fd != -1) {
7114: if(attr == -1) {
7115: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
7116: }
7117: SetFileAttributes(path, attr);
7118: REG16(AX) = fd;
7119: REG16(CX) = 3;
1.1.1.11 root 7120: msdos_file_handler_open(fd, path, _isatty(fd), 2, info, current_psp);
1.1.1.20 root 7121: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 7122: } else {
7123: REG16(AX) = errno;
1.1.1.3 root 7124: m_CF = 1;
1.1 root 7125: }
7126: } else {
7127: REG16(AX) = 0x50;
1.1.1.3 root 7128: m_CF = 1;
1.1 root 7129: }
7130: } else {
7131: // file not exists
7132: if(REG8(DL) & 0x10) {
7133: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
7134:
7135: if(fd != -1) {
7136: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
7137: REG16(AX) = fd;
7138: REG16(CX) = 2;
7139: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 7140: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 7141: } else {
7142: REG16(AX) = errno;
1.1.1.3 root 7143: m_CF = 1;
1.1 root 7144: }
7145: } else {
7146: REG16(AX) = 0x02;
1.1.1.3 root 7147: m_CF = 1;
1.1 root 7148: }
7149: }
7150: } else {
7151: REG16(AX) = 0x0c;
1.1.1.3 root 7152: m_CF = 1;
1.1 root 7153: }
7154: }
7155:
7156: inline void msdos_int_21h_710dh()
7157: {
7158: // reset drive
7159: }
7160:
1.1.1.17 root 7161: inline void msdos_int_21h_7141h(int lfn)
7162: {
7163: if(REG16(SI) == 0) {
7164: msdos_int_21h_41h(lfn);
7165: return;
7166: }
7167: if(REG16(SI) != 1) {
7168: REG16(AX) = 5;
7169: m_CF = 1;
7170: }
7171: /* wild card and matching attributes... */
7172: char tmp[MAX_PATH * 2];
7173: // copy search pathname (and quick check overrun)
7174: ZeroMemory(tmp, sizeof(tmp));
7175: tmp[MAX_PATH - 1] = '\0';
7176: tmp[MAX_PATH] = 1;
7177: strncpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(DX)), MAX_PATH);
7178:
7179: if(tmp[MAX_PATH - 1] != '\0' || tmp[MAX_PATH] != 1) {
7180: REG16(AX) = 1;
7181: m_CF = 1;
7182: return;
7183: }
7184: for(char *s = tmp; *s; ++s) {
7185: if(*s == '/') {
7186: *s = '\\';
7187: }
7188: }
7189: char *tmp_name = (char *)_mbsrchr((unsigned char *)tmp, '\\');
7190: if(tmp_name) {
7191: ++tmp_name;
7192: } else {
7193: tmp_name = strchr(tmp, ':');
7194: tmp_name = tmp_name ? tmp_name + 1 : tmp;
7195: }
7196:
7197: WIN32_FIND_DATAA fd;
7198: HANDLE fh = FindFirstFileA(tmp, &fd);
7199: if(fh == INVALID_HANDLE_VALUE) {
7200: REG16(AX) = 2;
7201: m_CF = 1;
7202: return;
7203: }
7204: do {
7205: if(msdos_find_file_check_attribute(fd.dwFileAttributes, REG8(CL), REG8(CH)) && msdos_find_file_has_8dot3name(&fd)) {
7206: strcpy(tmp_name, fd.cFileName);
7207: if(remove(msdos_trimmed_path(tmp, lfn))) {
7208: REG16(AX) = 5;
7209: m_CF = 1;
7210: break;
7211: }
7212: }
7213: } while(FindNextFileA(fh, &fd));
7214: if(!m_CF) {
7215: if(GetLastError() != ERROR_NO_MORE_FILES) {
7216: m_CF = 1;
7217: REG16(AX) = 2;
7218: }
7219: }
7220: FindClose(fh);
7221: }
7222:
1.1 root 7223: inline void msdos_int_21h_714eh()
7224: {
7225: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 7226: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
7227: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 7228: WIN32_FIND_DATA fd;
7229:
1.1.1.13 root 7230: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
7231: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
7232: FindClose(dtainfo->find_handle);
7233: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7234: }
7235: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 7236: dtainfo->allowable_mask = REG8(CL);
7237: dtainfo->required_mask = REG8(CH);
7238: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 7239:
1.1.1.14 root 7240: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
7241: dtainfo->allowable_mask &= ~8;
1.1 root 7242: }
1.1.1.14 root 7243: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
7244: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 7245: if(!FindNextFile(dtainfo->find_handle, &fd)) {
7246: FindClose(dtainfo->find_handle);
7247: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7248: break;
7249: }
7250: }
7251: }
1.1.1.13 root 7252: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 7253: find->attrib = fd.dwFileAttributes;
7254: msdos_find_file_conv_local_time(&fd);
7255: if(REG16(SI) == 0) {
7256: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
7257: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
7258: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
7259: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
7260: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
7261: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
7262: } else {
7263: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
7264: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
7265: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
7266: }
7267: find->size_hi = fd.nFileSizeHigh;
7268: find->size_lo = fd.nFileSizeLow;
7269: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 7270: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14 root 7271: REG16(AX) = dtainfo - dtalist + 1;
7272: } else if(dtainfo->allowable_mask & 8) {
1.1 root 7273: // volume label
7274: find->attrib = 8;
7275: find->size_hi = find->size_lo = 0;
7276: strcpy(find->full_name, process->volume_label);
7277: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 7278: dtainfo->allowable_mask &= ~8;
7279: REG16(AX) = dtainfo - dtalist + 1;
1.1 root 7280: } else {
7281: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 7282: m_CF = 1;
1.1 root 7283: }
7284: }
7285:
7286: inline void msdos_int_21h_714fh()
7287: {
7288: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 7289: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 7290: WIN32_FIND_DATA fd;
7291:
1.1.1.14 root 7292: if(REG16(BX) - 1u >= MAX_DTAINFO) {
7293: REG16(AX) = 6;
1.1.1.13 root 7294: m_CF = 1;
7295: return;
7296: }
1.1.1.14 root 7297: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 7298: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
7299: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 7300: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 7301: if(!FindNextFile(dtainfo->find_handle, &fd)) {
7302: FindClose(dtainfo->find_handle);
7303: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7304: break;
7305: }
7306: }
7307: } else {
1.1.1.13 root 7308: FindClose(dtainfo->find_handle);
7309: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7310: }
7311: }
1.1.1.13 root 7312: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 7313: find->attrib = fd.dwFileAttributes;
7314: msdos_find_file_conv_local_time(&fd);
7315: if(REG16(SI) == 0) {
7316: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
7317: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
7318: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
7319: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
7320: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
7321: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
7322: } else {
7323: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
7324: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
7325: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
7326: }
7327: find->size_hi = fd.nFileSizeHigh;
7328: find->size_lo = fd.nFileSizeLow;
7329: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 7330: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14 root 7331: } else if(dtainfo->allowable_mask & 8) {
1.1 root 7332: // volume label
7333: find->attrib = 8;
7334: find->size_hi = find->size_lo = 0;
7335: strcpy(find->full_name, process->volume_label);
7336: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 7337: dtainfo->allowable_mask &= ~8;
1.1 root 7338: } else {
7339: REG16(AX) = 0x12;
1.1.1.3 root 7340: m_CF = 1;
1.1 root 7341: }
7342: }
7343:
7344: inline void msdos_int_21h_71a0h()
7345: {
7346: DWORD max_component_len, file_sys_flag;
7347:
1.1.1.14 root 7348: 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))) {
7349: REG16(BX) = (UINT16)file_sys_flag & (FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK | FILE_VOLUME_IS_COMPRESSED);
7350: REG16(BX) |= 0x4000; // supports LFN functions
1.1 root 7351: REG16(CX) = (UINT16)max_component_len; // 255
7352: REG16(DX) = (UINT16)max_component_len + 5; // 260
7353: } else {
7354: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 7355: m_CF = 1;
1.1 root 7356: }
7357: }
7358:
7359: inline void msdos_int_21h_71a1h()
7360: {
1.1.1.14 root 7361: if(REG16(BX) - 1u >= MAX_DTAINFO) {
7362: REG16(AX) = 6;
1.1.1.13 root 7363: m_CF = 1;
7364: return;
7365: }
1.1.1.14 root 7366: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 7367: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
7368: FindClose(dtainfo->find_handle);
7369: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7370: }
7371: }
7372:
7373: inline void msdos_int_21h_71a6h()
7374: {
7375: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 7376: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
7377:
1.1.1.3 root 7378: UINT8 *buffer = (UINT8 *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 7379: struct _stat64 status;
7380: DWORD serial_number = 0;
7381:
1.1.1.20 root 7382: if(fd < process->max_files && file_handler[fd].valid) {
7383: if(_fstat64(fd, &status) == 0) {
7384: if(file_handler[fd].path[1] == ':') {
1.1 root 7385: // NOTE: we need to consider the network file path "\\host\share\"
7386: char volume[] = "A:\\";
1.1.1.20 root 7387: volume[0] = file_handler[fd].path[1];
1.1 root 7388: GetVolumeInformation(volume, NULL, 0, &serial_number, NULL, NULL, NULL, 0);
7389: }
1.1.1.20 root 7390: *(UINT32 *)(buffer + 0x00) = GetFileAttributes(file_handler[fd].path);
1.1 root 7391: *(UINT32 *)(buffer + 0x04) = (UINT32)(status.st_ctime & 0xffffffff);
7392: *(UINT32 *)(buffer + 0x08) = (UINT32)((status.st_ctime >> 32) & 0xffffffff);
7393: *(UINT32 *)(buffer + 0x0c) = (UINT32)(status.st_atime & 0xffffffff);
7394: *(UINT32 *)(buffer + 0x10) = (UINT32)((status.st_atime >> 32) & 0xffffffff);
7395: *(UINT32 *)(buffer + 0x14) = (UINT32)(status.st_mtime & 0xffffffff);
7396: *(UINT32 *)(buffer + 0x18) = (UINT32)((status.st_mtime >> 32) & 0xffffffff);
7397: *(UINT32 *)(buffer + 0x1c) = serial_number;
7398: *(UINT32 *)(buffer + 0x20) = (UINT32)((status.st_size >> 32) & 0xffffffff);
7399: *(UINT32 *)(buffer + 0x24) = (UINT32)(status.st_size & 0xffffffff);
7400: *(UINT32 *)(buffer + 0x28) = status.st_nlink;
1.1.1.14 root 7401: // this is dummy id and it will be changed when it is reopened...
1.1 root 7402: *(UINT32 *)(buffer + 0x2c) = 0;
1.1.1.20 root 7403: *(UINT32 *)(buffer + 0x30) = file_handler[fd].id;
1.1 root 7404: } else {
7405: REG16(AX) = errno;
1.1.1.3 root 7406: m_CF = 1;
1.1 root 7407: }
7408: } else {
7409: REG16(AX) = 0x06;
1.1.1.3 root 7410: m_CF = 1;
1.1 root 7411: }
7412: }
7413:
7414: inline void msdos_int_21h_71a7h()
7415: {
7416: switch(REG8(BL)) {
7417: case 0x00:
1.1.1.3 root 7418: if(!FileTimeToDosDateTime((FILETIME *)(mem + SREG_BASE(DS) + REG16(SI)), ®16(DX), ®16(CX))) {
1.1 root 7419: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 7420: m_CF = 1;
1.1 root 7421: }
7422: break;
7423: case 0x01:
7424: // NOTE: we need to check BH that shows 10-millisecond untils past time in CX
1.1.1.3 root 7425: if(!DosDateTimeToFileTime(REG16(DX), REG16(CX), (FILETIME *)(mem + SREG_BASE(ES) + REG16(DI)))) {
1.1 root 7426: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 7427: m_CF = 1;
1.1 root 7428: }
7429: break;
7430: default:
1.1.1.22! root 7431: 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 7432: REG16(AX) = 0x01;
1.1.1.3 root 7433: m_CF = 1;
1.1 root 7434: break;
7435: }
7436: }
7437:
7438: inline void msdos_int_21h_71a8h()
7439: {
7440: if(REG8(DH) == 0) {
7441: char tmp[MAX_PATH], fcb[MAX_PATH];
1.1.1.3 root 7442: strcpy(tmp, msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 7443: memset(fcb, 0x20, sizeof(fcb));
7444: int len = strlen(tmp);
1.1.1.21 root 7445: for(int i = 0, pos = 0; i < len; i++) {
1.1 root 7446: if(tmp[i] == '.') {
7447: pos = 8;
7448: } else {
7449: if(msdos_lead_byte_check(tmp[i])) {
7450: fcb[pos++] = tmp[i++];
7451: }
7452: fcb[pos++] = tmp[i];
7453: }
7454: }
1.1.1.3 root 7455: memcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), fcb, 11);
1.1 root 7456: } else {
1.1.1.3 root 7457: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 7458: }
7459: }
7460:
1.1.1.22! root 7461: inline void msdos_int_21h_71aah()
! 7462: {
! 7463: char drv[] = "A:", path[MAX_PATH];
! 7464: char *hoge=(char *)(mem + SREG_BASE(DS) + REG16(DX));
! 7465:
! 7466: if(REG8(BL) == 0) {
! 7467: drv[0] = 'A' + _getdrive() - 1;
! 7468: } else {
! 7469: drv[0] = 'A' + REG8(BL) - 1;
! 7470: }
! 7471: switch(REG8(BH)) {
! 7472: case 0x00:
! 7473: if(DefineDosDevice(0, drv, (char *)(mem + SREG_BASE(DS) + REG16(DX))) == 0) {
! 7474: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
! 7475: if(GetLogicalDrives() & bits) {
! 7476: REG16(AX) = 0x0f; // invalid drive
! 7477: } else {
! 7478: REG16(AX) = 0x03; // path not found
! 7479: }
! 7480: m_CF = 1;
! 7481: }
! 7482: break;
! 7483: case 0x01:
! 7484: if(DefineDosDevice(DDD_REMOVE_DEFINITION, drv, NULL) == 0) {
! 7485: REG16(AX) = 0x0f; // invalid drive
! 7486: m_CF = 1;
! 7487: }
! 7488: break;
! 7489: case 0x02:
! 7490: if(QueryDosDevice(drv, path, MAX_PATH) == 0) {
! 7491: REG16(AX) = 0x0f; // invalid drive
! 7492: m_CF = 1;
! 7493: } else if(strncmp(path, "\\??\\", 4) != 0) {
! 7494: REG16(AX) = 0x0f; // invalid drive
! 7495: m_CF = 1;
! 7496: } else {
! 7497: strcpy((char *)(mem + SREG_BASE(DS) + REG16(DX)), path + 4);
! 7498: }
! 7499: break;
! 7500: default:
! 7501: 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));
! 7502: REG16(AX) = 0x01;
! 7503: m_CF = 1;
! 7504: break;
! 7505: }
! 7506: }
! 7507:
1.1.1.14 root 7508: inline void msdos_int_21h_7300h()
7509: {
7510: if(REG8(AL) == 0) {
7511: REG8(AL) = REG8(CL);
7512: REG8(AH) = 0;
7513: } else {
7514: REG16(AX) = 0x01;
7515: m_CF = 1;
7516: }
7517: }
7518:
7519: inline void msdos_int_21h_7302h()
7520: {
7521: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
7522: UINT16 seg, ofs;
7523:
7524: if(REG16(CX) < 0x3f) {
7525: REG8(AL) = 0x18;
7526: m_CF = 1;
7527: } else if(!msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
7528: REG8(AL) = 0xff;
7529: m_CF = 1;
7530: } else {
7531: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 2, mem + (seg << 4) + ofs, sizeof(dpb_t));
7532: }
7533: }
7534:
1.1 root 7535: inline void msdos_int_21h_7303h()
7536: {
1.1.1.3 root 7537: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
7538: ext_space_info_t *info = (ext_space_info_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 7539: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
7540:
7541: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
7542: info->size_of_structure = sizeof(ext_space_info_t);
7543: info->structure_version = 0;
7544: info->sectors_per_cluster = sectors_per_cluster;
7545: info->bytes_per_sector = bytes_per_sector;
7546: info->available_clusters_on_drive = free_clusters;
7547: info->total_clusters_on_drive = total_clusters;
7548: info->available_sectors_on_drive = sectors_per_cluster * free_clusters;
7549: info->total_sectors_on_drive = sectors_per_cluster * total_clusters;
7550: info->available_allocation_units = free_clusters; // ???
7551: info->total_allocation_units = total_clusters; // ???
7552: } else {
7553: REG16(AX) = errno;
1.1.1.3 root 7554: m_CF = 1;
1.1 root 7555: }
7556: }
7557:
7558: inline void msdos_int_25h()
7559: {
7560: UINT16 seg, ofs;
7561: DWORD dwSize;
7562:
1.1.1.3 root 7563: #if defined(HAS_I386)
7564: I386OP(pushf)();
7565: #else
7566: PREFIX86(_pushf());
7567: #endif
1.1 root 7568:
7569: if(!(REG8(AL) < 26)) {
7570: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 7571: m_CF = 1;
1.1 root 7572: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
7573: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 7574: m_CF = 1;
1.1 root 7575: } else {
7576: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
7577: char dev[64];
7578: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
7579:
7580: HANDLE hFile = CreateFile(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
7581: if(hFile == INVALID_HANDLE_VALUE) {
7582: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 7583: m_CF = 1;
1.1 root 7584: } else {
1.1.1.19 root 7585: UINT32 top_sector = REG16(DX);
7586: UINT16 sector_num = REG16(CX);
7587: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX);
7588:
7589: if(sector_num == 0xffff) {
7590: top_sector = *(UINT32 *)(mem + buffer_addr + 0);
7591: sector_num = *(UINT16 *)(mem + buffer_addr + 4);
7592: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6);
7593: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8);
7594: buffer_addr = (seg << 4) + ofs;
7595: }
7596: // if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
7597: // REG8(AL) = 0x02; // drive not ready
7598: // m_CF = 1;
7599: // } else
7600: if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1.1 root 7601: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 7602: m_CF = 1;
1.1.1.19 root 7603: } else if(ReadFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 7604: REG8(AL) = 0x0b; // read error
1.1.1.3 root 7605: m_CF = 1;
1.1 root 7606: }
7607: CloseHandle(hFile);
7608: }
7609: }
7610: }
7611:
7612: inline void msdos_int_26h()
7613: {
7614: // this operation may cause serious damage for drives, so always returns error...
7615: UINT16 seg, ofs;
7616: DWORD dwSize;
7617:
1.1.1.3 root 7618: #if defined(HAS_I386)
7619: I386OP(pushf)();
7620: #else
7621: PREFIX86(_pushf());
7622: #endif
1.1 root 7623:
7624: if(!(REG8(AL) < 26)) {
7625: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 7626: m_CF = 1;
1.1 root 7627: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
7628: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 7629: m_CF = 1;
1.1 root 7630: } else {
7631: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
7632: char dev[64];
7633: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
7634:
7635: if(dpb->media_type == 0xf8) {
7636: // this drive is not a floppy
1.1.1.6 root 7637: // if(!(((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag & 0x40)) {
7638: // fatalerror("This application tried the absolute disk write to drive %c:\n", 'A' + REG8(AL));
7639: // }
1.1 root 7640: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 7641: m_CF = 1;
1.1 root 7642: } else {
7643: HANDLE hFile = CreateFile(dev, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
7644: if(hFile == INVALID_HANDLE_VALUE) {
7645: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 7646: m_CF = 1;
1.1 root 7647: } else {
1.1.1.19 root 7648: UINT32 top_sector = REG16(DX);
7649: UINT16 sector_num = REG16(CX);
7650: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX);
7651:
7652: if(sector_num == 0xffff) {
7653: top_sector = *(UINT32 *)(mem + buffer_addr + 0);
7654: sector_num = *(UINT16 *)(mem + buffer_addr + 4);
7655: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6);
7656: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8);
7657: buffer_addr = (seg << 4) + ofs;
7658: }
1.1 root 7659: if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
7660: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 7661: m_CF = 1;
1.1.1.19 root 7662: } else if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1.1 root 7663: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 7664: m_CF = 1;
1.1.1.19 root 7665: } else if(WriteFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 7666: REG8(AL) = 0x0a; // write error
1.1.1.3 root 7667: m_CF = 1;
1.1 root 7668: }
7669: CloseHandle(hFile);
7670: }
7671: }
7672: }
7673: }
7674:
7675: inline void msdos_int_27h()
7676: {
1.1.1.14 root 7677: msdos_mem_realloc(SREG(CS), (REG16(DX) + 15) >> 4, NULL);
1.1.1.3 root 7678: msdos_process_terminate(SREG(CS), retval | 0x300, 0);
1.1.1.14 root 7679:
7680: // int_21h_4bh succeeded
7681: m_CF = 0;
1.1 root 7682: }
7683:
7684: inline void msdos_int_29h()
7685: {
1.1.1.14 root 7686: #if 1
7687: // need to check escape sequences
1.1 root 7688: msdos_putch(REG8(AL));
1.1.1.14 root 7689: #else
7690: DWORD num;
7691:
7692: vram_flush();
7693: WriteConsole(hStdout, ®8(AL), 1, &num, NULL);
7694: cursor_moved = true;
7695: #endif
1.1 root 7696: }
7697:
7698: inline void msdos_int_2eh()
7699: {
7700: char tmp[MAX_PATH], command[MAX_PATH], opt[MAX_PATH];
7701: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 7702: strcpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(SI)));
1.1 root 7703: char *token = my_strtok(tmp, " ");
7704: strcpy(command, token);
7705: strcpy(opt, token + strlen(token) + 1);
7706:
7707: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
7708: param->env_seg = 0;
7709: param->cmd_line.w.l = 44;
7710: param->cmd_line.w.h = (WORK_TOP >> 4);
7711: param->fcb1.w.l = 24;
7712: param->fcb1.w.h = (WORK_TOP >> 4);
7713: param->fcb2.w.l = 24;
7714: param->fcb2.w.h = (WORK_TOP >> 4);
7715:
7716: memset(mem + WORK_TOP + 24, 0x20, 20);
7717:
7718: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
7719: cmd_line->len = strlen(opt);
7720: strcpy(cmd_line->cmd, opt);
7721: cmd_line->cmd[cmd_line->len] = 0x0d;
7722:
7723: msdos_process_exec(command, param, 0);
7724: REG8(AL) = 0;
7725: }
7726:
1.1.1.22! root 7727: inline void msdos_int_2fh_01h()
! 7728: {
! 7729: switch(REG8(AL)) {
! 7730: case 0x00:
! 7731: REG8(AL) = 0x01; // print.com is not installed, can't install
! 7732: break;
! 7733: default:
! 7734: 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));
! 7735: REG16(AX) = 0x01;
! 7736: m_CF = 1;
! 7737: break;
! 7738: }
! 7739: }
! 7740:
! 7741: inline void msdos_int_2fh_05h()
! 7742: {
! 7743: switch(REG8(AL)) {
! 7744: case 0x00:
! 7745: REG8(AL) = 0x01; // critical error handler is not installed, can't install
! 7746: break;
! 7747: default:
! 7748: 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));
! 7749: REG16(AX) = 0x01;
! 7750: m_CF = 1;
! 7751: break;
! 7752: }
! 7753: }
! 7754:
! 7755: inline void msdos_int_2fh_06h()
! 7756: {
! 7757: switch(REG8(AL)) {
! 7758: case 0x00:
! 7759: REG8(AL) = 0x01; // assign is not installed, can't install
! 7760: break;
! 7761: default:
! 7762: 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));
! 7763: REG16(AX) = 0x01;
! 7764: m_CF = 1;
! 7765: break;
! 7766: }
! 7767: }
! 7768:
! 7769: inline void msdos_int_2fh_08h()
! 7770: {
! 7771: switch(REG8(AL)) {
! 7772: case 0x00:
! 7773: REG8(AL) = 0x01; // driver.sys is not installed, can't install
! 7774: break;
! 7775: default:
! 7776: 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));
! 7777: REG16(AX) = 0x01;
! 7778: m_CF = 1;
! 7779: break;
! 7780: }
! 7781: }
! 7782:
! 7783: inline void msdos_int_2fh_10h()
! 7784: {
! 7785: switch(REG8(AL)) {
! 7786: case 0x00:
! 7787: REG8(AL) = 0x01; // share is not installed, can't install
! 7788: break;
! 7789: default:
! 7790: 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));
! 7791: REG16(AX) = 0x01;
! 7792: m_CF = 1;
! 7793: break;
! 7794: }
! 7795: }
! 7796:
! 7797: inline void msdos_int_2fh_11h()
! 7798: {
! 7799: switch(REG8(AL)) {
! 7800: case 0x00:
! 7801: REG8(AL) = 0x01; // mscdex is not installed, can't install
! 7802: break;
! 7803: default:
! 7804: 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));
! 7805: REG16(AX) = 0x01;
! 7806: m_CF = 1;
! 7807: break;
! 7808: }
! 7809: }
! 7810:
1.1.1.21 root 7811: inline void msdos_int_2fh_12h()
7812: {
7813: switch(REG8(AL)) {
1.1.1.22! root 7814: case 0x00:
! 7815: REG8(AL) = 0xff;
! 7816: break;
1.1.1.21 root 7817: case 0x16:
7818: if(REG16(BX) < 20) {
7819: SREG(ES) = SFT_TOP >> 4;
7820: i386_load_segment_descriptor(ES);
7821: REG16(DI) = 6 + 0x3b * REG16(BX);
7822:
7823: // update system file table
7824: UINT8* sft = mem + SFT_TOP + 6 + 0x3b * REG16(BX);
7825: if(file_handler[REG16(BX)].valid) {
7826: int count = 0;
7827: for(int i = 0; i < 20; i++) {
7828: if(msdos_psp_get_file_table(i, current_psp) == REG16(BX)) {
7829: count++;
7830: }
7831: }
7832: *(UINT16 *)(sft + 0x00) = count ? count : 0xffff;
7833: *(UINT32 *)(sft + 0x15) = _tell(REG16(BX));
7834: _lseek(REG16(BX), 0, SEEK_END);
7835: *(UINT32 *)(sft + 0x11) = _tell(REG16(BX));
7836: _lseek(REG16(BX), *(UINT32 *)(sft + 0x15), SEEK_SET);
7837: } else {
7838: memset(sft, 0, 0x3b);
7839: }
7840: } else {
7841: REG16(AX) = 0x06;
7842: m_CF = 1;
7843: }
7844: break;
7845: case 0x20:
7846: {
7847: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
7848:
7849: if(fd < 20) {
7850: SREG(ES) = current_psp;
7851: i386_load_segment_descriptor(ES);
7852: REG16(DI) = offsetof(psp_t, file_table) + fd;
7853: } else {
7854: REG16(AX) = 0x06;
7855: m_CF = 1;
7856: }
7857: }
7858: break;
1.1.1.22! root 7859: case 0x2e:
! 7860: if(REG8(DL) == 0x00 || REG8(DL) == 0x02 || REG8(DL) == 0x04 || REG8(DL) == 0x06) {
! 7861: SREG(ES) = ERR_TABLE_TOP >> 4;
! 7862: i386_load_segment_descriptor(ES);
! 7863: REG16(DI) = 0;
! 7864: }
! 7865: break;
! 7866: default:
! 7867: 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));
! 7868: REG16(AX) = 0x01;
! 7869: m_CF = 1;
! 7870: break;
! 7871: }
! 7872: }
! 7873:
! 7874: inline void msdos_int_2fh_14h()
! 7875: {
! 7876: switch(REG8(AL)) {
! 7877: case 0x00:
! 7878: REG8(AL) = 0x01; // nlsfunc.com is not installed, can't install
! 7879: break;
! 7880: default:
! 7881: 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));
! 7882: REG16(AX) = 0x01;
! 7883: m_CF = 1;
! 7884: break;
! 7885: }
! 7886: }
! 7887:
! 7888: inline void msdos_int_2fh_15h()
! 7889: {
! 7890: switch(REG8(AL)) {
! 7891: case 0x00:
! 7892: // function not supported, do not clear AX
! 7893: break;
! 7894: case 0x0b:
! 7895: // mscdex.exe is not installed
! 7896: break;
! 7897: case 0xff:
! 7898: // corelcdx is not installed
! 7899: break;
1.1.1.21 root 7900: default:
1.1.1.22! root 7901: 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 7902: REG16(AX) = 0x01;
7903: m_CF = 1;
7904: break;
7905: }
7906: }
7907:
1.1 root 7908: inline void msdos_int_2fh_16h()
7909: {
7910: switch(REG8(AL)) {
7911: case 0x00:
1.1.1.14 root 7912: if(no_windows) {
7913: REG8(AL) = 0;
7914: } else {
1.1 root 7915: OSVERSIONINFO osvi;
7916: ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
7917: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
7918: GetVersionEx(&osvi);
7919: REG8(AL) = osvi.dwMajorVersion;
7920: REG8(AH) = osvi.dwMinorVersion;
7921: }
7922: break;
1.1.1.22! root 7923: case 0x0a:
! 7924: if(!no_windows) {
! 7925: OSVERSIONINFO osvi;
! 7926: ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
! 7927: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
! 7928: GetVersionEx(&osvi);
! 7929: REG16(AX) = 0x0000;
! 7930: REG8(BH) = osvi.dwMajorVersion;
! 7931: REG8(BL) = osvi.dwMinorVersion;
! 7932: REG16(CX) = 0x0003; // enhanced
! 7933: }
! 7934: break;
! 7935: case 0x0e:
! 7936: case 0x0f:
! 7937: case 0x11:
! 7938: case 0x12:
! 7939: case 0x13:
! 7940: case 0x14:
! 7941: case 0x87:
! 7942: // function not supported, do not clear AX
! 7943: break;
1.1.1.14 root 7944: case 0x80:
7945: Sleep(10);
7946: hardware_update();
7947: REG8(AL) = 0;
7948: break;
1.1.1.22! root 7949: case 0x8e:
! 7950: REG16(AX) = 0x00; // failed
! 7951: break;
1.1.1.20 root 7952: case 0x8f:
7953: switch(REG8(DH)) {
7954: case 0x00:
7955: case 0x02:
7956: case 0x03:
7957: REG16(AX) = 0x00;
7958: break;
7959: case 0x01:
7960: REG16(AX) = 0x168f;
7961: break;
7962: }
7963: break;
1.1 root 7964: default:
1.1.1.22! root 7965: 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));
! 7966: REG16(AX) = 0x01;
! 7967: m_CF = 1;
! 7968: break;
! 7969: }
! 7970: }
! 7971:
! 7972: inline void msdos_int_2fh_19h()
! 7973: {
! 7974: switch(REG8(AL)) {
! 7975: case 0x00:
! 7976: // shellb.com is not installed
! 7977: REG8(AL) = 0x00;
! 7978: break;
! 7979: case 0x01:
! 7980: case 0x02:
! 7981: case 0x03:
! 7982: case 0x04:
! 7983: REG16(AX) = 0x01;
! 7984: m_CF = 1;
! 7985: break;
! 7986: default:
! 7987: 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 7988: REG16(AX) = 0x01;
1.1.1.3 root 7989: m_CF = 1;
1.1 root 7990: break;
7991: }
7992: }
7993:
7994: inline void msdos_int_2fh_1ah()
7995: {
7996: switch(REG8(AL)) {
7997: case 0x00:
7998: // ansi.sys is installed
7999: REG8(AL) = 0xff;
8000: break;
8001: default:
1.1.1.22! root 8002: 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));
! 8003: REG16(AX) = 0x01;
! 8004: m_CF = 1;
! 8005: break;
! 8006: }
! 8007: }
! 8008:
! 8009: inline void msdos_int_2fh_1bh()
! 8010: {
! 8011: switch(REG8(AL)) {
! 8012: case 0x00:
! 8013: // xma2ems.sys is not installed
! 8014: REG8(AL) = 0x00;
! 8015: break;
! 8016: default:
! 8017: 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 8018: REG16(AX) = 0x01;
1.1.1.3 root 8019: m_CF = 1;
1.1 root 8020: break;
8021: }
8022: }
8023:
8024: inline void msdos_int_2fh_43h()
8025: {
8026: switch(REG8(AL)) {
8027: case 0x00:
1.1.1.19 root 8028: // xms is installed ?
8029: #ifdef SUPPORT_XMS
8030: if(support_xms) {
8031: REG8(AL) = 0x80;
8032: } else
8033: #endif
8034: REG8(AL) = 0x00;
8035: break;
8036: case 0x10:
8037: REG16(BX) = XMS_OFFSET;
8038: SREG(ES) = XMS_TOP >> 4;
8039: i386_load_segment_descriptor(ES);
1.1 root 8040: break;
8041: default:
1.1.1.22! root 8042: 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));
! 8043: REG16(AX) = 0x01;
! 8044: m_CF = 1;
! 8045: break;
! 8046: }
! 8047: }
! 8048:
! 8049: inline void msdos_int_2fh_46h()
! 8050: {
! 8051: switch(REG8(AL)) {
! 8052: case 0x80:
! 8053: // windows v3.0 is not installed
! 8054: break;
! 8055: default:
! 8056: 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));
! 8057: REG16(AX) = 0x01;
! 8058: m_CF = 1;
! 8059: break;
! 8060: }
! 8061: }
! 8062:
! 8063: inline void msdos_int_2fh_48h()
! 8064: {
! 8065: switch(REG8(AL)) {
! 8066: case 0x00:
! 8067: // doskey is not installed
! 8068: break;
! 8069: case 0x10:
! 8070: msdos_int_21h_0ah();
! 8071: REG16(AX) = 0x00;
! 8072: break;
! 8073: default:
! 8074: 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 8075: REG16(AX) = 0x01;
1.1.1.3 root 8076: m_CF = 1;
1.1 root 8077: break;
8078: }
8079: }
8080:
8081: inline void msdos_int_2fh_4ah()
8082: {
1.1.1.19 root 8083: // hma is not installed
1.1 root 8084: switch(REG8(AL)) {
8085: case 0x01:
8086: case 0x02:
1.1.1.19 root 8087: // hma is not used
1.1 root 8088: REG16(BX) = 0;
1.1.1.3 root 8089: SREG(ES) = 0xffff;
8090: i386_load_segment_descriptor(ES);
1.1 root 8091: REG16(DI) = 0xffff;
8092: break;
1.1.1.19 root 8093: case 0x03:
8094: // unable to allocate
8095: REG16(DI) = 0xffff;
8096: break;
8097: case 0x04:
8098: // function not supported, do not clear AX
8099: break;
1.1.1.22! root 8100: case 0x10: // smartdrv installation check
! 8101: case 0x11: // dblspace installation check
! 8102: break;
! 8103: default:
! 8104: 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));
! 8105: REG16(AX) = 0x01;
! 8106: m_CF = 1;
! 8107: break;
! 8108: }
! 8109: }
! 8110:
! 8111: inline void msdos_int_2fh_4bh()
! 8112: {
! 8113: switch(REG8(AL)) {
! 8114: case 0x02:
! 8115: // task switcher not loaded, do not clear AX
! 8116: break;
1.1 root 8117: default:
1.1.1.22! root 8118: 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 8119: REG16(AX) = 0x01;
1.1.1.3 root 8120: m_CF = 1;
1.1 root 8121: break;
8122: }
8123: }
8124:
8125: inline void msdos_int_2fh_4fh()
8126: {
8127: switch(REG8(AL)) {
8128: case 0x00:
8129: REG16(AX) = 0;
8130: REG8(DL) = 1; // major version
8131: REG8(DH) = 0; // minor version
8132: break;
8133: case 0x01:
8134: REG16(AX) = 0;
8135: REG16(BX) = active_code_page;
8136: break;
8137: default:
1.1.1.22! root 8138: 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));
! 8139: REG16(AX) = 0x01;
! 8140: m_CF = 1;
! 8141: break;
! 8142: }
! 8143: }
! 8144:
! 8145: inline void msdos_int_2fh_55h()
! 8146: {
! 8147: switch(REG8(AL)) {
! 8148: case 0x00:
! 8149: case 0x01:
! 8150: // 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));
! 8151: break;
! 8152: default:
! 8153: 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 8154: REG16(AX) = 0x01;
1.1.1.3 root 8155: m_CF = 1;
1.1 root 8156: break;
8157: }
8158: }
8159:
8160: inline void msdos_int_2fh_aeh()
8161: {
8162: switch(REG8(AL)) {
8163: case 0x00:
8164: REG8(AL) = 0;
8165: break;
8166: case 0x01:
8167: {
8168: char command[MAX_PATH];
8169: memset(command, 0, sizeof(command));
1.1.1.3 root 8170: memcpy(command, mem + SREG_BASE(DS) + REG16(SI) + 1, mem[SREG_BASE(DS) + REG16(SI)]);
1.1 root 8171:
8172: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
8173: param->env_seg = 0;
8174: param->cmd_line.w.l = 44;
8175: param->cmd_line.w.h = (WORK_TOP >> 4);
8176: param->fcb1.w.l = 24;
8177: param->fcb1.w.h = (WORK_TOP >> 4);
8178: param->fcb2.w.l = 24;
8179: param->fcb2.w.h = (WORK_TOP >> 4);
8180:
8181: memset(mem + WORK_TOP + 24, 0x20, 20);
8182:
8183: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
1.1.1.3 root 8184: cmd_line->len = mem[SREG_BASE(DS) + REG16(BX) + 1];
8185: memcpy(cmd_line->cmd, mem + SREG_BASE(DS) + REG16(BX) + 2, cmd_line->len);
1.1 root 8186: cmd_line->cmd[cmd_line->len] = 0x0d;
8187:
8188: if(msdos_process_exec(command, param, 0)) {
8189: REG16(AX) = 0x02;
1.1.1.3 root 8190: m_CF = 1;
1.1 root 8191: }
8192: }
8193: break;
8194: default:
1.1.1.22! root 8195: 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 8196: REG16(AX) = 0x01;
1.1.1.3 root 8197: m_CF = 1;
1.1 root 8198: break;
8199: }
8200: }
8201:
8202: inline void msdos_int_2fh_b7h()
8203: {
8204: switch(REG8(AL)) {
8205: case 0x00:
8206: // append is not installed
8207: REG8(AL) = 0;
8208: break;
1.1.1.22! root 8209: case 0x07:
! 8210: case 0x11:
! 8211: break;
1.1 root 8212: default:
1.1.1.22! root 8213: 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 8214: REG16(AX) = 0x01;
1.1.1.3 root 8215: m_CF = 1;
1.1 root 8216: break;
8217: }
8218: }
8219:
1.1.1.19 root 8220: inline void msdos_int_67h_40h()
8221: {
8222: if(!support_ems) {
8223: REG8(AH) = 0x84;
8224: } else {
8225: REG8(AH) = 0x00;
8226: }
8227: }
8228:
8229: inline void msdos_int_67h_41h()
8230: {
8231: if(!support_ems) {
8232: REG8(AH) = 0x84;
8233: } else {
8234: REG8(AH) = 0x00;
8235: REG16(BX) = EMS_TOP >> 4;
8236: }
8237: }
8238:
8239: inline void msdos_int_67h_42h()
8240: {
8241: if(!support_ems) {
8242: REG8(AH) = 0x84;
8243: } else {
8244: REG8(AH) = 0x00;
8245: REG16(BX) = free_ems_pages;
8246: REG16(DX) = MAX_EMS_PAGES;
8247: }
8248: }
8249:
8250: inline void msdos_int_67h_43h()
8251: {
8252: if(!support_ems) {
8253: REG8(AH) = 0x84;
8254: } else if(REG16(BX) > MAX_EMS_PAGES) {
8255: REG8(AH) = 0x87;
8256: } else if(REG16(BX) > free_ems_pages) {
8257: REG8(AH) = 0x88;
8258: } else if(REG16(BX) == 0) {
8259: REG8(AH) = 0x89;
8260: } else {
8261: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
8262: if(!ems_handles[i].allocated) {
8263: ems_allocate_pages(i, REG16(BX));
8264: REG8(AH) = 0x00;
8265: REG16(DX) = i;
8266: return;
8267: }
8268: }
8269: REG8(AH) = 0x85;
8270: }
8271: }
8272:
8273: inline void msdos_int_67h_44h()
8274: {
8275: if(!support_ems) {
8276: REG8(AH) = 0x84;
8277: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
8278: REG8(AH) = 0x83;
8279: } else if(!(REG16(BX) == 0xffff || REG16(BX) < ems_handles[REG16(DX)].pages)) {
8280: REG8(AH) = 0x8a;
8281: // } else if(!(REG8(AL) < 4)) {
8282: // REG8(AH) = 0x8b;
8283: } else if(REG16(BX) == 0xffff) {
8284: ems_unmap_page(REG8(AL) & 3);
8285: REG8(AH) = 0x00;
8286: } else {
8287: ems_map_page(REG8(AL) & 3, REG16(DX), REG16(BX));
8288: REG8(AH) = 0x00;
8289: }
8290: }
8291:
8292: inline void msdos_int_67h_45h()
8293: {
8294: if(!support_ems) {
8295: REG8(AH) = 0x84;
8296: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
8297: REG8(AH) = 0x83;
8298: } else {
8299: ems_release_pages(REG16(DX));
8300: REG8(AH) = 0x00;
8301: }
8302: }
8303:
8304: inline void msdos_int_67h_46h()
8305: {
8306: if(!support_ems) {
8307: REG8(AH) = 0x84;
8308: } else {
8309: REG16(AX) = 0x0032; // EMS 3.2
8310: // REG16(AX) = 0x0040; // EMS 4.0
8311: }
8312: }
8313:
8314: inline void msdos_int_67h_47h()
8315: {
8316: // NOTE: the map data should be stored in the specified ems page, not process data
8317: process_t *process = msdos_process_info_get(current_psp);
8318:
8319: if(!support_ems) {
8320: REG8(AH) = 0x84;
8321: // } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
8322: // REG8(AH) = 0x83;
8323: } else if(process->ems_pages_stored) {
8324: REG8(AH) = 0x8d;
8325: } else {
8326: for(int i = 0; i < 4; i++) {
8327: process->ems_pages[i].handle = ems_pages[i].handle;
8328: process->ems_pages[i].page = ems_pages[i].page;
8329: process->ems_pages[i].mapped = ems_pages[i].mapped;
8330: }
8331: process->ems_pages_stored = true;
8332: REG8(AH) = 0x00;
8333: }
8334: }
8335:
8336: inline void msdos_int_67h_48h()
8337: {
8338: // NOTE: the map data should be restored from the specified ems page, not process data
8339: process_t *process = msdos_process_info_get(current_psp);
8340:
8341: if(!support_ems) {
8342: REG8(AH) = 0x84;
8343: // } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
8344: // REG8(AH) = 0x83;
8345: } else if(!process->ems_pages_stored) {
8346: REG8(AH) = 0x8e;
8347: } else {
8348: for(int i = 0; i < 4; i++) {
8349: if(process->ems_pages[i].mapped) {
8350: ems_map_page(i, process->ems_pages[i].handle, process->ems_pages[i].page);
8351: } else {
8352: ems_unmap_page(i);
8353: }
8354: }
8355: process->ems_pages_stored = false;
8356: REG8(AH) = 0x00;
8357: }
8358: }
8359:
8360: inline void msdos_int_67h_4bh()
8361: {
8362: if(!support_ems) {
8363: REG8(AH) = 0x84;
8364: } else {
8365: REG8(AH) = 0x00;
8366: REG16(BX) = 0;
8367: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
8368: if(ems_handles[i].allocated) {
8369: REG16(BX)++;
8370: }
8371: }
8372: }
8373: }
8374:
8375: inline void msdos_int_67h_4ch()
8376: {
8377: if(!support_ems) {
8378: REG8(AH) = 0x84;
8379: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
8380: REG8(AH) = 0x83;
8381: } else {
8382: REG8(AH) = 0x00;
8383: REG16(BX) = ems_handles[REG16(DX)].pages;
8384: }
8385: }
8386:
8387: inline void msdos_int_67h_4dh()
8388: {
8389: if(!support_ems) {
8390: REG8(AH) = 0x84;
8391: } else {
8392: REG8(AH) = 0x00;
8393: REG16(BX) = 0;
8394: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
8395: if(ems_handles[i].allocated) {
8396: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 0) = i;
8397: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 2) = ems_handles[i].pages;
8398: REG16(BX)++;
8399: }
8400: }
8401: }
8402: }
8403:
1.1.1.20 root 8404: inline void msdos_int_67h_4eh()
8405: {
8406: if(!support_ems) {
8407: REG8(AH) = 0x84;
8408: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01 || REG8(AL) == 0x02) {
8409: if(REG8(AL) == 0x00 || REG8(AL) == 0x02) {
8410: // save page map
8411: for(int i = 0; i < 4; i++) {
8412: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = ems_pages[i].mapped ? ems_pages[i].handle : 0xffff;
8413: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = ems_pages[i].mapped ? ems_pages[i].page : 0xffff;
8414: }
8415: }
8416: if(REG8(AL) == 0x01 || REG8(AL) == 0x02) {
8417: // restore page map
8418: for(int i = 0; i < 4; i++) {
8419: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0);
8420: UINT16 page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2);
8421:
8422: if(handle < MAX_EMS_HANDLES && ems_handles[handle].allocated && page < ems_handles[handle].pages) {
8423: ems_map_page(i, handle, page);
8424: } else {
8425: ems_unmap_page(i);
8426: }
8427: }
8428: }
8429: REG8(AH) = 0x00;
8430: } else if(REG8(AL) == 0x03) {
8431: REG8(AH) = 0x00;
1.1.1.21 root 8432: REG8(AL) = 4 * 4;
8433: } else {
1.1.1.22! root 8434: 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 8435: REG8(AH) = 0x8f;
8436: }
8437: }
8438:
8439: inline void msdos_int_67h_4fh()
8440: {
8441: if(!support_ems) {
8442: REG8(AH) = 0x84;
8443: } else if(REG8(AL) == 0x00) {
8444: int count = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI));
8445:
8446: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI)) = count;
8447: for(int i = 0; i < count; i++) {
8448: UINT16 segment = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 2 * i);
8449: UINT16 physical = ((segment << 4) - EMS_TOP) / 0x4000;
8450:
8451: // if(!(physical < 4)) {
8452: // REG8(AH) = 0x8b;
8453: // return;
8454: // }
8455: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 0) = segment;
8456: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 2) = ems_pages[physical & 3].handle;
8457: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 4) = ems_pages[physical & 3].mapped ? ems_pages[physical & 3].page : 0xffff;
8458: }
8459: REG8(AH) = 0x00;
8460: } else if(REG8(AL) == 0x01) {
8461: int count = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI));
8462:
8463: for(int i = 0; i < count; i++) {
8464: UINT16 segment = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 0);
8465: UINT16 physical = ((segment << 4) - EMS_TOP) / 0x4000;
8466: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 2);
8467: UINT16 logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 4);
8468:
8469: // if(!(physical < 4)) {
8470: // REG8(AH) = 0x8b;
8471: // return;
8472: // } else
8473: if(!(handle < MAX_EMS_HANDLES && ems_handles[handle].allocated)) {
8474: REG8(AH) = 0x83;
8475: return;
8476: } else if(logical == 0xffff) {
8477: ems_unmap_page(physical & 3);
8478: } else if(logical < ems_handles[handle].pages) {
8479: ems_map_page(physical & 3, handle, logical);
8480: } else {
8481: REG8(AH) = 0x8a;
8482: return;
8483: }
8484: }
8485: REG8(AH) = 0x00;
8486: } else if(REG8(AL) == 0x02) {
8487: REG8(AH) = 0x00;
8488: REG8(AL) = 2 + REG16(BX) * 6;
1.1.1.20 root 8489: } else {
1.1.1.22! root 8490: 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 8491: REG8(AH) = 0x8f;
8492: }
8493: }
8494:
8495: inline void msdos_int_67h_50h()
8496: {
8497: if(!support_ems) {
8498: REG8(AH) = 0x84;
8499: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
8500: REG8(AH) = 0x83;
8501: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
8502: for(int i = 0; i < REG16(CX); i++) {
8503: int logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0);
8504: int physical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2);
8505:
8506: if(REG8(AL) == 0x01) {
8507: physical = ((physical << 4) - EMS_TOP) / 0x4000;
8508: }
8509: // if(!(physical < 4)) {
8510: // REG8(AH) = 0x8b;
8511: // return;
8512: // } else
8513: if(logical == 0xffff) {
8514: ems_unmap_page(physical & 3);
8515: } else if(logical < ems_handles[REG16(DX)].pages) {
8516: ems_map_page(physical & 3, REG16(DX), logical);
8517: } else {
8518: REG8(AH) = 0x8a;
8519: return;
8520: }
8521: }
8522: REG8(AH) = 0x00;
8523: } else {
1.1.1.22! root 8524: 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 8525: REG8(AH) = 0x8f;
8526: }
8527: }
8528:
1.1.1.19 root 8529: inline void msdos_int_67h_51h()
8530: {
8531: if(!support_ems) {
8532: REG8(AH) = 0x84;
8533: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
8534: REG8(AH) = 0x83;
8535: } else if(REG16(BX) > MAX_EMS_PAGES) {
8536: REG8(AH) = 0x87;
8537: } else if(REG16(BX) > free_ems_pages + ems_handles[REG16(DX)].pages) {
8538: REG8(AH) = 0x88;
8539: } else {
8540: ems_reallocate_pages(REG16(DX), REG16(BX));
8541: REG8(AH) = 0x00;
8542: }
8543: }
8544:
1.1.1.20 root 8545: inline void msdos_int_67h_52h()
8546: {
8547: if(!support_ems) {
8548: REG8(AH) = 0x84;
8549: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
8550: REG8(AH) = 0x83;
8551: } else if(REG8(AL) == 0x00) {
8552: REG8(AL) = 0x00; // handle is volatile
8553: REG8(AH) = 0x00;
8554: } else if(REG8(AL) == 0x01) {
8555: if(REG8(BL) == 0x00) {
8556: REG8(AH) = 0x00;
8557: } else {
8558: REG8(AH) = 0x90; // undefined attribute type
8559: }
8560: } else if(REG8(AL) == 0x02) {
8561: REG8(AL) = 0x00; // only volatile handles supported
8562: REG8(AH) = 0x00;
8563: } else {
1.1.1.22! root 8564: 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 8565: REG8(AH) = 0x8f;
8566: }
8567: }
8568:
1.1.1.19 root 8569: inline void msdos_int_67h_53h()
8570: {
8571: if(!support_ems) {
8572: REG8(AH) = 0x84;
8573: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
8574: REG8(AH) = 0x83;
8575: } else if(REG8(AL) == 0x00) {
8576: memcpy(mem + SREG_BASE(ES) + REG16(DI), ems_handles[REG16(DX)].name, 8);
8577: REG8(AH) = 0x00;
8578: } else if(REG8(AL) == 0x01) {
8579: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
8580: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) {
8581: REG8(AH) = 0xa1;
8582: return;
8583: }
8584: }
8585: REG8(AH) = 0x00;
8586: memcpy(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8);
8587: } else {
1.1.1.22! root 8588: 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 8589: REG8(AH) = 0x8f;
1.1.1.19 root 8590: }
8591: }
8592:
8593: inline void msdos_int_67h_54h()
8594: {
8595: if(!support_ems) {
8596: REG8(AH) = 0x84;
8597: } else if(REG8(AL) == 0x00) {
8598: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
8599: if(ems_handles[i].allocated) {
8600: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, ems_handles[i].name, 10);
8601: } else {
8602: memset(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, 0, 10);
8603: }
8604: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 0) = i;
8605: }
8606: REG8(AH) = 0x00;
8607: REG8(AL) = MAX_EMS_HANDLES;
8608: } else if(REG8(AL) == 0x01) {
8609: REG8(AH) = 0xa0; // not found
8610: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
8611: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) {
8612: REG8(AH) = 0x00;
8613: REG16(DX) = i;
8614: break;
8615: }
8616: }
8617: } else if(REG8(AL) == 0x02) {
8618: REG8(AH) = 0x00;
8619: REG16(BX) = MAX_EMS_HANDLES;
8620: } else {
1.1.1.22! root 8621: 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 8622: REG8(AH) = 0x8f;
8623: }
8624: }
8625:
8626: inline void msdos_int_67h_57h_tmp()
8627: {
8628: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00);
8629: UINT8 src_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04);
8630: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x05);
8631: UINT16 src_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07);
8632: UINT16 src_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x09);
8633: UINT8 dest_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0b);
8634: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c);
8635: UINT16 dest_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0e);
8636: UINT16 dest_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x10);
8637:
8638: UINT8 *src_buffer, *dest_buffer;
8639: UINT32 src_addr, dest_addr;
8640: UINT32 src_addr_max, dest_addr_max;
8641:
8642: if(src_type == 0) {
8643: src_buffer = mem;
8644: src_addr = (src_seg << 4) + src_ofs;
8645: src_addr_max = MAX_MEM;
8646: } else {
8647: if(!(src_handle < MAX_EMS_HANDLES && ems_handles[src_handle].allocated)) {
8648: REG8(AH) = 0x83;
8649: return;
8650: } else if(!(src_seg < ems_handles[src_handle].pages)) {
8651: REG8(AH) = 0x8a;
8652: return;
8653: }
8654: src_buffer = ems_handles[src_handle].buffer + 0x4000 * src_seg;
8655: src_addr = src_ofs;
8656: src_addr_max = 0x4000;
8657: }
8658: if(dest_type == 0) {
8659: dest_buffer = mem;
8660: dest_addr = (dest_seg << 4) + dest_ofs;
8661: dest_addr_max = MAX_MEM;
8662: } else {
8663: if(!(dest_handle < MAX_EMS_HANDLES && ems_handles[dest_handle].allocated)) {
8664: REG8(AH) = 0x83;
8665: return;
8666: } else if(!(dest_seg < ems_handles[dest_handle].pages)) {
8667: REG8(AH) = 0x8a;
8668: return;
8669: }
8670: dest_buffer = ems_handles[dest_handle].buffer + 0x4000 * dest_seg;
8671: dest_addr = dest_ofs;
8672: dest_addr_max = 0x4000;
8673: }
8674: for(int i = 0; i < copy_length; i++) {
8675: if(src_addr < src_addr_max && dest_addr < dest_addr_max) {
8676: if(REG8(AL) == 0x00) {
8677: dest_buffer[dest_addr++] = src_buffer[src_addr++];
8678: } else if(REG8(AL) == 0x01) {
8679: UINT8 tmp = dest_buffer[dest_addr];
8680: dest_buffer[dest_addr++] = src_buffer[src_addr];
8681: src_buffer[src_addr++] = tmp;
8682: }
8683: } else {
8684: REG8(AH) = 0x93;
8685: return;
8686: }
8687: }
8688: REG8(AH) = 0x80;
8689: }
8690:
8691: inline void msdos_int_67h_57h()
8692: {
8693: if(!support_ems) {
8694: REG8(AH) = 0x84;
8695: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
8696: struct {
8697: UINT16 handle;
8698: UINT16 page;
8699: bool mapped;
8700: } tmp_pages[4];
8701:
8702: // unmap pages to copy memory data to ems buffer
8703: for(int i = 0; i < 4; i++) {
8704: tmp_pages[i].handle = ems_pages[i].handle;
8705: tmp_pages[i].page = ems_pages[i].page;
8706: tmp_pages[i].mapped = ems_pages[i].mapped;
8707: ems_unmap_page(i);
8708: }
8709:
8710: // run move/exchange operation
8711: msdos_int_67h_57h_tmp();
8712:
8713: // restore unmapped pages
8714: for(int i = 0; i < 4; i++) {
8715: if(tmp_pages[i].mapped) {
8716: ems_map_page(i, tmp_pages[i].handle, tmp_pages[i].page);
8717: }
8718: }
8719: } else {
1.1.1.22! root 8720: 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 8721: REG8(AH) = 0x8f;
8722: }
8723: }
8724:
8725: inline void msdos_int_67h_58h()
8726: {
8727: if(!support_ems) {
8728: REG8(AH) = 0x84;
8729: } else if(REG8(AL) == 0x00) {
8730: for(int i = 0; i < 4; i++) {
8731: *(UINT16 *)(mem +SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = (EMS_TOP + 0x4000 * i) >> 4;
8732: *(UINT16 *)(mem +SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = i;
8733: }
8734: REG8(AH) = 0x00;
8735: REG16(CX) = 4;
8736: } else if(REG8(AL) == 0x01) {
8737: REG8(AH) = 0x00;
8738: REG16(CX) = 4;
8739: } else {
1.1.1.22! root 8740: 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 8741: REG8(AH) = 0x8f;
8742: }
8743: }
8744:
8745: inline void msdos_int_67h_5ah()
8746: {
8747: if(!support_ems) {
1.1.1.19 root 8748: REG8(AH) = 0x84;
1.1.1.20 root 8749: } else if(REG16(BX) > MAX_EMS_PAGES) {
8750: REG8(AH) = 0x87;
8751: } else if(REG16(BX) > free_ems_pages) {
8752: REG8(AH) = 0x88;
8753: // } else if(REG16(BX) == 0) {
8754: // REG8(AH) = 0x89;
8755: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
8756: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
8757: if(!ems_handles[i].allocated) {
8758: ems_allocate_pages(i, REG16(BX));
8759: REG8(AH) = 0x00;
8760: REG16(DX) = i;
8761: return;
8762: }
8763: }
8764: REG8(AH) = 0x85;
8765: } else {
1.1.1.22! root 8766: 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 8767: REG8(AH) = 0x8f;
1.1.1.19 root 8768: }
8769: }
8770:
8771: #ifdef SUPPORT_XMS
8772:
8773: inline void msdos_call_xms_00h()
8774: {
8775: REG16(AX) = 0x0270; // V2.70
8776: REG16(BX) = 0x0000;
8777: // REG16(DX) = 0x0000; // hma does not exist
8778: REG16(DX) = 0x0001; // hma does exist
8779: }
8780:
8781: inline void msdos_call_xms_01h()
8782: {
8783: REG16(AX) = 0x0000;
8784: // REG8(BL) = 0x90; // hma does not exist
8785: REG8(BL) = 0x91; // hma is already used
8786: }
8787:
8788: inline void msdos_call_xms_02h()
8789: {
8790: REG16(AX) = 0x0000;
8791: // REG8(BL) = 0x90; // hma does not exist
8792: REG8(BL) = 0x91; // hma is already used
8793: }
8794:
8795: inline void msdos_call_xms_03h()
8796: {
8797: i386_set_a20_line(1);
8798: REG16(AX) = 0x0001;
8799: REG8(BL) = 0x00;
8800: }
8801:
8802: inline void msdos_call_xms_04h()
8803: {
1.1.1.21 root 8804: i386_set_a20_line(0);
8805: REG16(AX) = 0x0001;
8806: REG8(BL) = 0x00;
1.1.1.19 root 8807: }
8808:
8809: inline void msdos_call_xms_05h()
8810: {
8811: i386_set_a20_line(1);
8812: REG16(AX) = 0x0001;
8813: REG8(BL) = 0x00;
1.1.1.21 root 8814: xms_a20_local_enb_count++;
1.1.1.19 root 8815: }
8816:
8817: void msdos_call_xms_06h()
8818: {
1.1.1.21 root 8819: if(xms_a20_local_enb_count > 0) {
8820: xms_a20_local_enb_count--;
8821: }
8822: if(xms_a20_local_enb_count == 0) {
1.1.1.19 root 8823: i386_set_a20_line(0);
1.1.1.21 root 8824: }
8825: if((m_a20_mask >> 20) & 1) {
1.1.1.19 root 8826: REG16(AX) = 0x0000;
8827: REG8(BL) = 0x94;
1.1.1.21 root 8828: } else {
8829: REG16(AX) = 0x0001;
8830: REG8(BL) = 0x00;
1.1.1.19 root 8831: }
8832: }
8833:
8834: inline void msdos_call_xms_07h()
8835: {
8836: REG16(AX) = (m_a20_mask >> 20) & 1;
8837: REG8(BL) = 0x00;
8838: }
8839:
8840: inline void msdos_call_xms_08h()
8841: {
8842: REG16(AX) = REG16(DX) = 0x0000;
8843:
8844: int mcb_seg = EMB_TOP >> 4;
8845:
8846: while(1) {
8847: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
8848:
8849: if(mcb->psp == 0) {
8850: if(REG16(AX) < mcb->size_kb()) {
8851: REG16(AX) = mcb->size_kb();
8852: }
8853: REG16(DX) += mcb->size_kb();
8854: }
8855: if(mcb->mz == 'Z') {
8856: break;
8857: }
8858: mcb_seg += 1 + mcb->paragraphs();
8859: }
8860:
8861: if(REG16(AX) == 0 && REG16(DX) == 0) {
8862: REG8(BL) = 0xa0;
8863: } else {
8864: REG8(BL) = 0x00;
8865: }
8866: }
8867:
8868: inline void msdos_call_xms_09h()
8869: {
8870: for(int i = 1; i <= MAX_XMS_HANDLES; i++) {
8871: if(!xms_handles[i].allocated) {
8872: if((xms_handles[i].seg = msdos_mem_alloc(EMB_TOP >> 4, REG16(DX) * 64, 0)) != -1) {
8873: xms_handles[i].size_kb = REG16(DX);
8874: xms_handles[i].lock = 0;
8875: xms_handles[i].allocated = true;
8876:
8877: REG16(AX) = 0x0001;
8878: REG16(DX) = i;
8879: REG8(BL) = 0x00;
8880: } else {
8881: REG16(AX) = REG16(DX) = 0x0000;
8882: REG8(BL) = 0xa0;
8883: }
8884: return;
8885: }
8886: }
8887: REG16(AX) = REG16(DX) = 0x0000;
8888: REG8(BL) = 0xa1;
8889: }
8890:
8891: inline void msdos_call_xms_0ah()
8892: {
8893: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
8894: REG16(AX) = 0x0000;
8895: REG8(BL) = 0xa2;
8896: } else if(xms_handles[REG16(DX)].lock > 0) {
8897: REG16(AX) = 0x0000;
8898: REG8(BL) = 0xab;
8899: } else {
8900: msdos_mem_free(xms_handles[REG16(DX)].seg);
8901: xms_handles[REG16(DX)].allocated = false;
8902:
8903: REG16(AX) = 0x0001;
8904: REG8(BL) = 0x00;
8905: }
8906: }
8907:
8908: inline void msdos_call_xms_0bh()
8909: {
8910: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00);
8911: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04);
8912: UINT32 src_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06);
8913: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0a);
8914: UINT32 dest_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c);
8915:
8916: UINT8 *src_buffer, *dest_buffer;
8917: UINT32 src_addr_max, dest_addr_max;
8918:
8919: if(src_handle == 0) {
8920: src_buffer = mem;
8921: src_addr = (((src_addr >> 16) & 0xffff) << 4) + (src_addr & 0xffff);
8922: src_addr_max = MAX_MEM;
8923: } else {
8924: if(!(src_handle >= 1 && src_handle <= MAX_XMS_HANDLES && xms_handles[src_handle].allocated)) {
8925: REG16(AX) = 0x0000;
8926: REG8(BL) = 0xa3;
8927: return;
8928: }
8929: src_buffer = mem + (xms_handles[src_handle].seg << 4);
8930: src_addr_max = xms_handles[src_handle].size_kb * 1024;
8931: }
8932: if(dest_handle == 0) {
8933: dest_buffer = mem;
8934: dest_addr = (((dest_addr >> 16) & 0xffff) << 4) + (dest_addr & 0xffff);
8935: dest_addr_max = MAX_MEM;
8936: } else {
8937: if(!(dest_handle >= 1 && dest_handle <= MAX_XMS_HANDLES && xms_handles[dest_handle].allocated)) {
8938: REG16(AX) = 0x0000;
8939: REG8(BL) = 0xa5;
8940: return;
8941: }
8942: dest_buffer = mem + (xms_handles[dest_handle].seg << 4);
8943: dest_addr_max = xms_handles[dest_handle].size_kb * 1024;
8944: }
8945: for(int i = 0; i < copy_length; i++) {
8946: if(src_addr < src_addr_max && dest_addr < dest_addr_max) {
8947: dest_buffer[dest_addr++] = src_buffer[src_addr++];
8948: } else {
8949: break;
8950: }
8951: }
8952: REG16(AX) = 0x0001;
8953: REG8(BL) = 0x00;
8954: }
8955:
8956: inline void msdos_call_xms_0ch()
8957: {
8958: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
8959: REG16(AX) = 0x0000;
8960: REG8(BL) = 0xa2;
8961: } else {
8962: xms_handles[REG16(DX)].lock++;
8963: REG16(AX) = 0x0001;
8964: REG8(BL) = 0x00;
8965: UINT32 addr = xms_handles[REG16(DX)].seg << 4;
8966: REG16(DX) = (addr >> 16) & 0xffff;
8967: REG16(BX) = (addr ) & 0xffff;
8968: }
8969: }
8970:
8971: inline void msdos_call_xms_0dh()
8972: {
8973: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
8974: REG16(AX) = 0x0000;
8975: REG8(BL) = 0xa2;
8976: } else if(!(xms_handles[REG16(DX)].lock > 0)) {
8977: REG16(AX) = 0x0000;
8978: REG8(BL) = 0xaa;
8979: } else {
8980: xms_handles[REG16(DX)].lock--;
8981: REG16(AX) = 0x0001;
8982: REG8(BL) = 0x00;
8983: }
8984: }
8985:
8986: inline void msdos_call_xms_0eh()
8987: {
8988: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
8989: REG16(AX) = 0x0000;
8990: REG8(BL) = 0xa2;
8991: } else {
8992: REG16(AX) = 0x0001;
8993: REG8(BH) = xms_handles[REG16(DX)].lock;
8994: REG8(BL) = 0x00;
8995: for(int i = 1; i <= MAX_XMS_HANDLES; i++) {
8996: if(!xms_handles[i].allocated) {
8997: REG8(BL)++;
8998: }
8999: }
9000: REG16(DX) = xms_handles[REG16(DX)].size_kb;
9001: }
9002: }
9003:
9004: inline void msdos_call_xms_0fh()
9005: {
9006: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
9007: REG16(AX) = 0x0000;
9008: REG8(BL) = 0xa2;
9009: } else if(xms_handles[REG16(DX)].lock > 0) {
9010: REG16(AX) = 0x0000;
9011: REG8(BL) = 0xab;
9012: } else if(msdos_mem_realloc(xms_handles[REG16(DX)].seg, REG16(BX) * 64, NULL)) {
9013: REG16(AX) = 0x0000;
9014: REG8(BL) = 0xa0;
9015: } else {
9016: REG16(AX) = 0x0001;
9017: REG8(BL) = 0x00;
9018: }
9019: }
9020:
9021: inline void msdos_call_xms_10h()
9022: {
9023: int seg;
9024:
9025: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(DX), 0)) != -1) {
9026: REG16(AX) = 0x0001;
9027: REG16(BX) = seg;
9028: } else {
9029: REG16(AX) = 0x0000;
9030: REG8(BL) = 0xb0;
9031: REG16(DX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
9032: }
9033: }
9034:
9035: inline void msdos_call_xms_11h()
9036: {
9037: int mcb_seg = REG16(DX) - 1;
9038: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
9039:
9040: if(mcb->mz == 'M' || mcb->mz == 'Z') {
9041: msdos_mem_free(REG16(DX));
9042: REG16(AX) = 0x0001;
9043: REG8(BL) = 0x00;
9044: } else {
9045: REG16(AX) = 0x0000;
9046: REG8(BL) = 0xb2;
9047: }
9048: }
9049:
9050: inline void msdos_call_xms_12h()
9051: {
9052: int mcb_seg = REG16(DX) - 1;
9053: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
9054: int max_paragraphs;
9055:
9056: if(mcb->mz == 'M' || mcb->mz == 'Z') {
9057: if(!msdos_mem_realloc(REG16(DX), REG16(BX), &max_paragraphs)) {
9058: REG16(AX) = 0x0001;
9059: REG8(BL) = 0x00;
9060: } else {
9061: REG16(AX) = 0x0000;
9062: REG8(BL) = 0xb0;
9063: REG16(DX) = max_paragraphs;
9064: }
9065: } else {
9066: REG16(AX) = 0x0000;
9067: REG8(BL) = 0xb2;
9068: }
9069: }
9070:
9071: #endif
9072:
1.1 root 9073: void msdos_syscall(unsigned num)
9074: {
1.1.1.22! root 9075: #ifdef ENABLE_DEBUG_SYSCALL
! 9076: if(num == 0x68) {
! 9077: // dummy interrupt for EMS (int 67h)
! 9078: fprintf(fdebug, "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));
! 9079: } else if(num == 0x69) {
! 9080: // dummy interrupt for XMS (call far)
! 9081: fprintf(fdebug, "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));
! 9082: } else if(num == 0x6a) {
! 9083: // dummy interrupt for case map routine pointed in the country info
! 9084: } else {
! 9085: fprintf(fdebug, "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));
! 9086: }
! 9087: #endif
! 9088:
1.1 root 9089: switch(num) {
9090: case 0x00:
9091: error("division by zero\n");
9092: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
9093: break;
9094: case 0x04:
9095: error("overflow\n");
9096: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
9097: break;
9098: case 0x06:
9099: // NOTE: ish.com has illegal instruction...
1.1.1.14 root 9100: if(!ignore_illegal_insn) {
9101: error("illegal instruction\n");
9102: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
9103: } else {
9104: #if defined(HAS_I386)
9105: m_eip++;
9106: #else
9107: m_pc++;
9108: #endif
9109: }
1.1 root 9110: break;
1.1.1.8 root 9111: case 0x08:
1.1.1.14 root 9112: // pcbios_irq0(); // this causes too slow emulation...
1.1.1.8 root 9113: case 0x09:
9114: case 0x0a:
9115: case 0x0b:
9116: case 0x0c:
9117: case 0x0d:
9118: case 0x0e:
9119: case 0x0f:
9120: // EOI
9121: pic[0].isr &= ~(1 << (num - 0x08));
9122: pic_update();
9123: break;
1.1 root 9124: case 0x10:
9125: // PC BIOS - Video
1.1.1.14 root 9126: if(!restore_console_on_exit) {
1.1.1.15 root 9127: change_console_size(scr_width, scr_height);
1.1 root 9128: }
1.1.1.3 root 9129: m_CF = 0;
1.1 root 9130: switch(REG8(AH)) {
1.1.1.16 root 9131: case 0x00: pcbios_int_10h_00h(); break;
1.1 root 9132: case 0x01: pcbios_int_10h_01h(); break;
9133: case 0x02: pcbios_int_10h_02h(); break;
9134: case 0x03: pcbios_int_10h_03h(); break;
9135: case 0x05: pcbios_int_10h_05h(); break;
9136: case 0x06: pcbios_int_10h_06h(); break;
9137: case 0x07: pcbios_int_10h_07h(); break;
9138: case 0x08: pcbios_int_10h_08h(); break;
9139: case 0x09: pcbios_int_10h_09h(); break;
9140: case 0x0a: pcbios_int_10h_0ah(); break;
9141: case 0x0b: break;
9142: case 0x0c: break;
9143: case 0x0d: break;
9144: case 0x0e: pcbios_int_10h_0eh(); break;
9145: case 0x0f: pcbios_int_10h_0fh(); break;
9146: case 0x10: break;
1.1.1.14 root 9147: case 0x11: pcbios_int_10h_11h(); break;
9148: case 0x12: pcbios_int_10h_12h(); break;
1.1 root 9149: case 0x13: pcbios_int_10h_13h(); break;
9150: case 0x18: REG8(AL) = 0x86; break;
1.1.1.14 root 9151: case 0x1a: pcbios_int_10h_1ah(); break;
1.1.1.11 root 9152: case 0x1b: break;
1.1 root 9153: case 0x1c: REG8(AL) = 0x00; break;
9154: case 0x1d: pcbios_int_10h_1dh(); break;
1.1.1.22! root 9155: case 0x4f: pcbios_int_10h_4fh(); break;
! 9156: case 0x80: m_CF = 1; break; // unknown
! 9157: case 0x81: m_CF = 1; break; // unknown
1.1 root 9158: case 0x82: pcbios_int_10h_82h(); break;
1.1.1.22! root 9159: case 0x83: pcbios_int_10h_83h(); break;
! 9160: case 0x8b: break;
! 9161: case 0x8c: m_CF = 1; break; // unknown
! 9162: case 0x8d: m_CF = 1; break; // unknown
! 9163: case 0x8e: m_CF = 1; break; // unknown
! 9164: case 0x90: pcbios_int_10h_90h(); break;
! 9165: case 0x91: pcbios_int_10h_91h(); break;
! 9166: case 0x92: break;
! 9167: case 0x93: break;
! 9168: case 0xef: pcbios_int_10h_efh(); break;
1.1 root 9169: case 0xfe: pcbios_int_10h_feh(); break;
9170: case 0xff: pcbios_int_10h_ffh(); break;
9171: default:
1.1.1.22! root 9172: 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));
! 9173: m_CF = 1;
1.1 root 9174: break;
9175: }
9176: break;
9177: case 0x11:
9178: // PC BIOS - Get Equipment List
1.1.1.11 root 9179: #ifdef SUPPORT_FPU
9180: REG16(AX) = 0x22;
9181: #else
1.1 root 9182: REG16(AX) = 0x20;
1.1.1.11 root 9183: #endif
1.1 root 9184: break;
9185: case 0x12:
9186: // PC BIOS - Get Memory Size
9187: REG16(AX) = MEMORY_END / 1024;
9188: break;
9189: case 0x13:
9190: // PC BIOS - Disk
1.1.1.22! root 9191: // 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 9192: REG8(AH) = 0xff;
1.1.1.3 root 9193: m_CF = 1;
1.1 root 9194: break;
9195: case 0x14:
9196: // PC BIOS - Serial I/O
1.1.1.22! root 9197: // 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 9198: REG8(AH) = 0xff;
1.1.1.3 root 9199: m_CF = 1;
1.1 root 9200: break;
9201: case 0x15:
9202: // PC BIOS
1.1.1.3 root 9203: m_CF = 0;
1.1 root 9204: switch(REG8(AH)) {
1.1.1.14 root 9205: case 0x10: pcbios_int_15h_10h(); break;
1.1 root 9206: case 0x23: pcbios_int_15h_23h(); break;
9207: case 0x24: pcbios_int_15h_24h(); break;
9208: case 0x49: pcbios_int_15h_49h(); break;
1.1.1.22! root 9209: case 0x50: pcbios_int_15h_50h(); break;
1.1 root 9210: case 0x86: pcbios_int_15h_86h(); break;
9211: case 0x87: pcbios_int_15h_87h(); break;
9212: case 0x88: pcbios_int_15h_88h(); break;
9213: case 0x89: pcbios_int_15h_89h(); break;
1.1.1.21 root 9214: case 0x8a: pcbios_int_15h_8ah(); break;
1.1.1.22! root 9215: case 0xc0: // PS/2 ???
! 9216: case 0xc1:
! 9217: case 0xc2:
! 9218: REG8(AH) = 0x86;
! 9219: m_CF = 1;
! 9220: break;
1.1.1.3 root 9221: #if defined(HAS_I386)
1.1 root 9222: case 0xc9: pcbios_int_15h_c9h(); break;
1.1.1.3 root 9223: #endif
1.1 root 9224: case 0xca: pcbios_int_15h_cah(); break;
1.1.1.22! root 9225: case 0xe8: pcbios_int_15h_e8h(); break;
1.1 root 9226: default:
1.1.1.22! root 9227: 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));
! 9228: REG8(AH) = 0x86;
1.1.1.3 root 9229: m_CF = 1;
1.1 root 9230: break;
9231: }
9232: break;
9233: case 0x16:
9234: // PC BIOS - Keyboard
1.1.1.3 root 9235: m_CF = 0;
1.1 root 9236: switch(REG8(AH)) {
9237: case 0x00: pcbios_int_16h_00h(); break;
9238: case 0x01: pcbios_int_16h_01h(); break;
9239: case 0x02: pcbios_int_16h_02h(); break;
9240: case 0x03: pcbios_int_16h_03h(); break;
9241: case 0x05: pcbios_int_16h_05h(); break;
9242: case 0x10: pcbios_int_16h_00h(); break;
9243: case 0x11: pcbios_int_16h_01h(); break;
9244: case 0x12: pcbios_int_16h_12h(); break;
9245: case 0x13: pcbios_int_16h_13h(); break;
9246: case 0x14: pcbios_int_16h_14h(); break;
1.1.1.22! root 9247: case 0xda: break; // unknown
! 9248: case 0xff: break; // unknown
1.1 root 9249: default:
1.1.1.22! root 9250: 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 9251: break;
9252: }
9253: break;
9254: case 0x17:
9255: // PC BIOS - Printer
1.1.1.22! root 9256: // 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 9257: break;
9258: case 0x1a:
9259: // PC BIOS - Timer
1.1.1.3 root 9260: m_CF = 0;
1.1 root 9261: switch(REG8(AH)) {
9262: case 0x00: pcbios_int_1ah_00h(); break;
9263: case 0x01: break;
9264: case 0x02: pcbios_int_1ah_02h(); break;
9265: case 0x03: break;
9266: case 0x04: pcbios_int_1ah_04h(); break;
9267: case 0x05: break;
9268: case 0x0a: pcbios_int_1ah_0ah(); break;
9269: case 0x0b: break;
1.1.1.14 root 9270: case 0x35: break; // Word Perfect Third Party Interface?
9271: case 0x36: break; // Word Perfect Third Party Interface
9272: case 0x70: break; // SNAP? (Simple Network Application Protocol)
1.1 root 9273: default:
1.1.1.22! root 9274: 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 9275: break;
9276: }
9277: break;
9278: case 0x20:
1.1.1.3 root 9279: msdos_process_terminate(SREG(CS), retval, 1);
1.1 root 9280: break;
9281: case 0x21:
9282: // MS-DOS System Call
1.1.1.3 root 9283: m_CF = 0;
1.1 root 9284: switch(REG8(AH)) {
9285: case 0x00: msdos_int_21h_00h(); break;
9286: case 0x01: msdos_int_21h_01h(); break;
9287: case 0x02: msdos_int_21h_02h(); break;
9288: case 0x03: msdos_int_21h_03h(); break;
9289: case 0x04: msdos_int_21h_04h(); break;
9290: case 0x05: msdos_int_21h_05h(); break;
9291: case 0x06: msdos_int_21h_06h(); break;
9292: case 0x07: msdos_int_21h_07h(); break;
9293: case 0x08: msdos_int_21h_08h(); break;
9294: case 0x09: msdos_int_21h_09h(); break;
9295: case 0x0a: msdos_int_21h_0ah(); break;
9296: case 0x0b: msdos_int_21h_0bh(); break;
9297: case 0x0c: msdos_int_21h_0ch(); break;
9298: case 0x0d: msdos_int_21h_0dh(); break;
9299: case 0x0e: msdos_int_21h_0eh(); break;
1.1.1.14 root 9300: case 0x0f: msdos_int_21h_0fh(); break;
9301: case 0x10: msdos_int_21h_10h(); break;
1.1 root 9302: case 0x11: msdos_int_21h_11h(); break;
9303: case 0x12: msdos_int_21h_12h(); break;
9304: case 0x13: msdos_int_21h_13h(); break;
1.1.1.16 root 9305: case 0x14: msdos_int_21h_14h(); break;
9306: case 0x15: msdos_int_21h_15h(); break;
1.1.1.14 root 9307: case 0x16: msdos_int_21h_16h(); break;
1.1.1.16 root 9308: case 0x17: msdos_int_21h_17h(); break;
1.1 root 9309: case 0x18: msdos_int_21h_18h(); break;
9310: case 0x19: msdos_int_21h_19h(); break;
9311: case 0x1a: msdos_int_21h_1ah(); break;
9312: case 0x1b: msdos_int_21h_1bh(); break;
9313: case 0x1c: msdos_int_21h_1ch(); break;
9314: case 0x1d: msdos_int_21h_1dh(); break;
9315: case 0x1e: msdos_int_21h_1eh(); break;
9316: case 0x1f: msdos_int_21h_1fh(); break;
9317: case 0x20: msdos_int_21h_20h(); break;
1.1.1.14 root 9318: case 0x21: msdos_int_21h_21h(); break;
9319: case 0x22: msdos_int_21h_22h(); break;
1.1.1.16 root 9320: case 0x23: msdos_int_21h_23h(); break;
9321: case 0x24: msdos_int_21h_24h(); break;
1.1 root 9322: case 0x25: msdos_int_21h_25h(); break;
9323: case 0x26: msdos_int_21h_26h(); break;
1.1.1.16 root 9324: case 0x27: msdos_int_21h_27h(); break;
9325: case 0x28: msdos_int_21h_28h(); break;
1.1 root 9326: case 0x29: msdos_int_21h_29h(); break;
9327: case 0x2a: msdos_int_21h_2ah(); break;
9328: case 0x2b: msdos_int_21h_2bh(); break;
9329: case 0x2c: msdos_int_21h_2ch(); break;
9330: case 0x2d: msdos_int_21h_2dh(); break;
9331: case 0x2e: msdos_int_21h_2eh(); break;
9332: case 0x2f: msdos_int_21h_2fh(); break;
9333: case 0x30: msdos_int_21h_30h(); break;
9334: case 0x31: msdos_int_21h_31h(); break;
9335: case 0x32: msdos_int_21h_32h(); break;
9336: case 0x33: msdos_int_21h_33h(); break;
9337: // 0x34: get address of indos flag
9338: case 0x35: msdos_int_21h_35h(); break;
9339: case 0x36: msdos_int_21h_36h(); break;
9340: case 0x37: msdos_int_21h_37h(); break;
1.1.1.14 root 9341: case 0x38: msdos_int_21h_38h(); break;
1.1 root 9342: case 0x39: msdos_int_21h_39h(0); break;
9343: case 0x3a: msdos_int_21h_3ah(0); break;
9344: case 0x3b: msdos_int_21h_3bh(0); break;
9345: case 0x3c: msdos_int_21h_3ch(); break;
9346: case 0x3d: msdos_int_21h_3dh(); break;
9347: case 0x3e: msdos_int_21h_3eh(); break;
9348: case 0x3f: msdos_int_21h_3fh(); break;
9349: case 0x40: msdos_int_21h_40h(); break;
9350: case 0x41: msdos_int_21h_41h(0); break;
9351: case 0x42: msdos_int_21h_42h(); break;
9352: case 0x43: msdos_int_21h_43h(0); break;
9353: case 0x44: msdos_int_21h_44h(); break;
9354: case 0x45: msdos_int_21h_45h(); break;
9355: case 0x46: msdos_int_21h_46h(); break;
9356: case 0x47: msdos_int_21h_47h(0); break;
9357: case 0x48: msdos_int_21h_48h(); break;
9358: case 0x49: msdos_int_21h_49h(); break;
9359: case 0x4a: msdos_int_21h_4ah(); break;
9360: case 0x4b: msdos_int_21h_4bh(); break;
9361: case 0x4c: msdos_int_21h_4ch(); break;
9362: case 0x4d: msdos_int_21h_4dh(); break;
9363: case 0x4e: msdos_int_21h_4eh(); break;
9364: case 0x4f: msdos_int_21h_4fh(); break;
9365: case 0x50: msdos_int_21h_50h(); break;
9366: case 0x51: msdos_int_21h_51h(); break;
9367: case 0x52: msdos_int_21h_52h(); break;
9368: // 0x53: translate bios parameter block to drive param bock
9369: case 0x54: msdos_int_21h_54h(); break;
9370: case 0x55: msdos_int_21h_55h(); break;
9371: case 0x56: msdos_int_21h_56h(0); break;
9372: case 0x57: msdos_int_21h_57h(); break;
9373: case 0x58: msdos_int_21h_58h(); break;
9374: case 0x59: msdos_int_21h_59h(); break;
9375: case 0x5a: msdos_int_21h_5ah(); break;
9376: case 0x5b: msdos_int_21h_5bh(); break;
9377: case 0x5c: msdos_int_21h_5ch(); break;
1.1.1.22! root 9378: case 0x5d: msdos_int_21h_5dh(); break;
1.1 root 9379: // 0x5e: ms-network
9380: // 0x5f: ms-network
9381: case 0x60: msdos_int_21h_60h(0); break;
9382: case 0x61: msdos_int_21h_61h(); break;
9383: case 0x62: msdos_int_21h_62h(); break;
9384: case 0x63: msdos_int_21h_63h(); break;
9385: // 0x64: set device driver lockahead flag
9386: case 0x65: msdos_int_21h_65h(); break;
9387: case 0x66: msdos_int_21h_66h(); break;
9388: case 0x67: msdos_int_21h_67h(); break;
9389: case 0x68: msdos_int_21h_68h(); break;
9390: case 0x69: msdos_int_21h_69h(); break;
9391: case 0x6a: msdos_int_21h_6ah(); break;
9392: case 0x6b: msdos_int_21h_6bh(); break;
9393: case 0x6c: msdos_int_21h_6ch(0); break;
9394: // 0x6d: find first rom program
9395: // 0x6e: find next rom program
9396: // 0x6f: get/set rom scan start address
9397: // 0x70: windows95 get/set internationalization information
9398: case 0x71:
9399: // windows95 long filename functions
9400: switch(REG8(AL)) {
9401: case 0x0d: msdos_int_21h_710dh(); break;
9402: case 0x39: msdos_int_21h_39h(1); break;
9403: case 0x3a: msdos_int_21h_3ah(1); break;
9404: case 0x3b: msdos_int_21h_3bh(1); break;
1.1.1.17 root 9405: case 0x41: msdos_int_21h_7141h(1); break;
1.1 root 9406: case 0x43: msdos_int_21h_43h(1); break;
9407: case 0x47: msdos_int_21h_47h(1); break;
9408: case 0x4e: msdos_int_21h_714eh(); break;
9409: case 0x4f: msdos_int_21h_714fh(); break;
9410: case 0x56: msdos_int_21h_56h(1); break;
9411: case 0x60: msdos_int_21h_60h(1); break;
9412: case 0x6c: msdos_int_21h_6ch(1); break;
9413: case 0xa0: msdos_int_21h_71a0h(); break;
9414: case 0xa1: msdos_int_21h_71a1h(); break;
9415: case 0xa6: msdos_int_21h_71a6h(); break;
9416: case 0xa7: msdos_int_21h_71a7h(); break;
9417: case 0xa8: msdos_int_21h_71a8h(); break;
9418: // 0xa9: server create/open file
1.1.1.22! root 9419: case 0xaa: msdos_int_21h_71aah(); break;
1.1 root 9420: default:
1.1.1.22! root 9421: 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 root 9422: REG16(AX) = 0x7100;
1.1.1.3 root 9423: m_CF = 1;
1.1 root 9424: break;
9425: }
9426: break;
9427: // 0x72: Windows95 beta - LFN FindClose
9428: case 0x73:
9429: // windows95 fat32 functions
9430: switch(REG8(AL)) {
1.1.1.14 root 9431: case 0x00: msdos_int_21h_7300h(); break;
9432: // 0x01: set drive locking ???
9433: case 0x02: msdos_int_21h_7302h(); break;
1.1 root 9434: case 0x03: msdos_int_21h_7303h(); break;
9435: // 0x04: set dpb to use for formatting
9436: default:
1.1.1.22! root 9437: 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 root 9438: REG16(AX) = 0x7300;
1.1.1.3 root 9439: m_CF = 1;
1.1 root 9440: break;
9441: }
9442: break;
9443: default:
1.1.1.22! root 9444: 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 root 9445: REG16(AX) = 0x01;
1.1.1.3 root 9446: m_CF = 1;
1.1 root 9447: break;
9448: }
1.1.1.3 root 9449: if(m_CF) {
1.1 root 9450: error_code = REG16(AX);
9451: }
9452: break;
9453: case 0x22:
9454: fatalerror("int 22h (terminate address)\n");
9455: case 0x23:
9456: msdos_process_terminate(current_psp, (retval & 0xff) | 0x100, 1);
9457: break;
9458: case 0x24:
9459: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
9460: break;
9461: case 0x25:
9462: msdos_int_25h();
9463: break;
9464: case 0x26:
9465: msdos_int_26h();
9466: break;
9467: case 0x27:
9468: msdos_int_27h();
9469: break;
9470: case 0x28:
9471: Sleep(10);
9472: break;
9473: case 0x29:
9474: msdos_int_29h();
9475: break;
9476: case 0x2e:
9477: msdos_int_2eh();
9478: break;
9479: case 0x2f:
9480: // multiplex interrupt
9481: switch(REG8(AH)) {
1.1.1.22! root 9482: case 0x00: break;
! 9483: case 0x01: msdos_int_2fh_01h(); break;
! 9484: case 0x05: msdos_int_2fh_05h(); break;
! 9485: case 0x06: msdos_int_2fh_06h(); break;
! 9486: case 0x08: msdos_int_2fh_08h(); break;
! 9487: case 0x10: msdos_int_2fh_10h(); break;
! 9488: case 0x11: msdos_int_2fh_11h(); break;
1.1.1.21 root 9489: case 0x12: msdos_int_2fh_12h(); break;
1.1.1.22! root 9490: case 0x14: msdos_int_2fh_14h(); break;
! 9491: case 0x15: msdos_int_2fh_15h(); break;
1.1 root 9492: case 0x16: msdos_int_2fh_16h(); break;
1.1.1.22! root 9493: case 0x19: msdos_int_2fh_19h(); break;
1.1 root 9494: case 0x1a: msdos_int_2fh_1ah(); break;
1.1.1.22! root 9495: case 0x1b: msdos_int_2fh_1bh(); break;
1.1 root 9496: case 0x43: msdos_int_2fh_43h(); break;
1.1.1.22! root 9497: case 0x46: msdos_int_2fh_46h(); break;
! 9498: case 0x48: msdos_int_2fh_48h(); break;
1.1 root 9499: case 0x4a: msdos_int_2fh_4ah(); break;
1.1.1.22! root 9500: case 0x4b: msdos_int_2fh_4bh(); break;
! 9501: case 0x4c: break; // unknown
! 9502: case 0x4d: break; // unknown
! 9503: case 0x4e: break; // unknown
1.1 root 9504: case 0x4f: msdos_int_2fh_4fh(); break;
1.1.1.22! root 9505: case 0x55: msdos_int_2fh_55h(); break;
! 9506: case 0x58: break; // unknown
! 9507: case 0x74: break; // unknown
1.1 root 9508: case 0xae: msdos_int_2fh_aeh(); break;
9509: case 0xb7: msdos_int_2fh_b7h(); break;
1.1.1.22! root 9510: case 0xe9: break; // unknown
! 9511: case 0xfe: break; // norton utilities ???
! 9512: default:
! 9513: 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));
! 9514: break;
1.1 root 9515: }
9516: break;
1.1.1.19 root 9517: case 0x68:
9518: // dummy interrupt for EMS (int 67h)
9519: switch(REG8(AH)) {
9520: case 0x40: msdos_int_67h_40h(); break;
9521: case 0x41: msdos_int_67h_41h(); break;
9522: case 0x42: msdos_int_67h_42h(); break;
9523: case 0x43: msdos_int_67h_43h(); break;
9524: case 0x44: msdos_int_67h_44h(); break;
9525: case 0x45: msdos_int_67h_45h(); break;
9526: case 0x46: msdos_int_67h_46h(); break;
9527: case 0x47: msdos_int_67h_47h(); break;
9528: case 0x48: msdos_int_67h_48h(); break;
1.1.1.20 root 9529: // 0x49: LIM EMS - Reserved - Get I/O Port Address (Undocumented in EMS 3.2)
9530: // 0x4a: LIM EMS - Reserved - Get Translation Array (Undocumented in EMS 3.2)
1.1.1.19 root 9531: case 0x4b: msdos_int_67h_4bh(); break;
9532: case 0x4c: msdos_int_67h_4ch(); break;
9533: case 0x4d: msdos_int_67h_4dh(); break;
1.1.1.20 root 9534: case 0x4e: msdos_int_67h_4eh(); break;
1.1.1.21 root 9535: case 0x4f: msdos_int_67h_4fh(); break;
1.1.1.20 root 9536: case 0x50: msdos_int_67h_50h(); break;
1.1.1.19 root 9537: case 0x51: msdos_int_67h_51h(); break;
1.1.1.20 root 9538: case 0x52: msdos_int_67h_52h(); break;
1.1.1.19 root 9539: case 0x53: msdos_int_67h_53h(); break;
9540: case 0x54: msdos_int_67h_54h(); break;
1.1.1.20 root 9541: // 0x55: LIM EMS 4.0 - Alter Page Map And JUMP
9542: // 0x56: LIM EMS 4.0 - Alter Page Map And CALL
9543: case 0x57: msdos_int_67h_57h(); break;
9544: case 0x58: msdos_int_67h_58h(); break;
9545: // 0x59: LIM EMS 4.0 - Get Expanded Memory Hardware Information (for DOS Kernel)
9546: case 0x5a: msdos_int_67h_5ah(); break;
9547: // 0x5b: LIM EMS 4.0 - Alternate Map Register Set (for DOS Kernel)
9548: // 0x5c: LIM EMS 4.0 - Prepate Expanded Memory Hardware For Warm Boot
9549: // 0x5d: LIM EMS 4.0 - Enable/Disable OS Function Set Functions (for DOS Kernel)
1.1.1.19 root 9550: default:
1.1.1.22! root 9551: 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 9552: REG8(AH) = 0x84;
9553: break;
9554: }
9555: break;
9556: #ifdef SUPPORT_XMS
9557: case 0x69:
9558: // dummy interrupt for XMS (call far)
9559: switch(REG8(AH)) {
9560: case 0x00: msdos_call_xms_00h(); break;
9561: case 0x01: msdos_call_xms_01h(); break;
9562: case 0x02: msdos_call_xms_02h(); break;
9563: case 0x03: msdos_call_xms_03h(); break;
9564: case 0x04: msdos_call_xms_04h(); break;
9565: case 0x05: msdos_call_xms_05h(); break;
9566: case 0x06: msdos_call_xms_06h(); break;
9567: case 0x07: msdos_call_xms_07h(); break;
9568: case 0x08: msdos_call_xms_08h(); break;
9569: case 0x09: msdos_call_xms_09h(); break;
9570: case 0x0a: msdos_call_xms_0ah(); break;
9571: case 0x0b: msdos_call_xms_0bh(); break;
9572: case 0x0c: msdos_call_xms_0ch(); break;
9573: case 0x0d: msdos_call_xms_0dh(); break;
9574: case 0x0e: msdos_call_xms_0eh(); break;
9575: case 0x0f: msdos_call_xms_0fh(); break;
9576: case 0x10: msdos_call_xms_10h(); break;
9577: case 0x11: msdos_call_xms_11h(); break;
9578: case 0x12: msdos_call_xms_12h(); break;
9579: // 0x88: XMS 3.0 - Query free extended memory
9580: // 0x89: XMS 3.0 - Allocate any extended memory
9581: // 0x8e: XMS 3.0 - Get extended EMB handle information
9582: // 0x8f: XMS 3.0 - Reallocate any extended memory block
9583: default:
1.1.1.22! root 9584: 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));
1.1.1.19 root 9585: REG16(AX) = 0x0000;
9586: REG8(BL) = 0x80;
9587: break;
9588: }
9589: break;
9590: #endif
9591: case 0x6a:
9592: // dummy interrupt for case map routine pointed in the country info
9593: if(REG8(AL) >= 0x80) {
9594: char tmp[2] = {0};
9595: tmp[0] = REG8(AL);
9596: my_strupr(tmp);
9597: REG8(AL) = tmp[0];
9598: }
9599: break;
1.1.1.8 root 9600: case 0x70:
9601: case 0x71:
9602: case 0x72:
9603: case 0x73:
9604: case 0x74:
9605: case 0x75:
9606: case 0x76:
9607: case 0x77:
9608: // EOI
9609: if((pic[1].isr &= ~(1 << (num - 0x70))) == 0) {
9610: pic[0].isr &= ~(1 << 2); // master
9611: }
9612: pic_update();
9613: break;
1.1 root 9614: default:
1.1.1.22! root 9615: // 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 9616: break;
9617: }
9618:
9619: // update cursor position
9620: if(cursor_moved) {
9621: CONSOLE_SCREEN_BUFFER_INFO csbi;
9622: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.15 root 9623: if(!restore_console_on_exit) {
9624: scr_top = csbi.srWindow.Top;
9625: }
1.1 root 9626: mem[0x450 + mem[0x462] * 2] = csbi.dwCursorPosition.X;
1.1.1.14 root 9627: mem[0x451 + mem[0x462] * 2] = csbi.dwCursorPosition.Y - scr_top;
1.1 root 9628: cursor_moved = false;
9629: }
9630: }
9631:
9632: // init
9633:
9634: int msdos_init(int argc, char *argv[], char *envp[], int standard_env)
9635: {
9636: // init file handler
9637: memset(file_handler, 0, sizeof(file_handler));
9638: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
9639: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
9640: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
1.1.1.21 root 9641: #ifdef MAP_AUX_DEVICE_TO_FILE
1.1 root 9642: if(_open("stdaux.txt", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
1.1.1.21 root 9643: #else
9644: if(_open("NUL", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
9645: #endif
9646: msdos_file_handler_open(3, "STDAUX", 0, 2, 0x80c0, 0);
1.1 root 9647: }
1.1.1.21 root 9648: #ifdef MAP_PRN_DEVICE_TO_FILE
1.1 root 9649: if(_open("stdprn.txt", _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 4) {
1.1.1.21 root 9650: #else
9651: if(_open("NUL", _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 4) {
1.1 root 9652: #endif
1.1.1.21 root 9653: msdos_file_handler_open(4, "STDPRN", 0, 1, 0xa8c0, 0);
9654: }
1.1 root 9655: _dup2(0, DUP_STDIN);
9656: _dup2(1, DUP_STDOUT);
9657: _dup2(2, DUP_STDERR);
1.1.1.21 root 9658: _dup2(3, DUP_STDAUX);
9659: _dup2(4, DUP_STDPRN);
1.1 root 9660:
9661: // init process
9662: memset(process, 0, sizeof(process));
9663:
1.1.1.13 root 9664: // init dtainfo
9665: msdos_dta_info_init();
9666:
1.1 root 9667: // init memory
9668: memset(mem, 0, sizeof(mem));
9669:
9670: // bios data area
9671: CONSOLE_SCREEN_BUFFER_INFO csbi;
9672: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 9673: CONSOLE_FONT_INFO cfi;
9674: GetCurrentConsoleFont(hStdout, FALSE, &cfi);
9675:
9676: int regen = min(scr_width * scr_height * 2, 0x8000);
9677: text_vram_top_address = TEXT_VRAM_TOP;
9678: text_vram_end_address = text_vram_top_address + regen;
9679: shadow_buffer_top_address = SHADOW_BUF_TOP;
9680: shadow_buffer_end_address = shadow_buffer_top_address + regen;
9681:
9682: if(regen > 0x4000) {
9683: regen = 0x8000;
9684: vram_pages = 1;
9685: } else if(regen > 0x2000) {
9686: regen = 0x4000;
9687: vram_pages = 2;
9688: } else if(regen > 0x1000) {
9689: regen = 0x2000;
9690: vram_pages = 4;
9691: } else {
9692: regen = 0x1000;
9693: vram_pages = 8;
9694: }
1.1 root 9695:
1.1.1.14 root 9696: #ifdef SUPPORT_FPU
9697: *(UINT16 *)(mem + 0x410) = 0x22;
9698: #else
1.1 root 9699: *(UINT16 *)(mem + 0x410) = 0x20;
1.1.1.14 root 9700: #endif
1.1 root 9701: *(UINT16 *)(mem + 0x413) = MEMORY_END / 1024;
9702: *(UINT8 *)(mem + 0x449) = 0x03;//0x73;
1.1.1.14 root 9703: *(UINT16 *)(mem + 0x44a) = csbi.dwSize.X;
9704: *(UINT16 *)(mem + 0x44c) = regen;
1.1 root 9705: *(UINT16 *)(mem + 0x44e) = 0;
9706: *(UINT8 *)(mem + 0x450) = csbi.dwCursorPosition.X;
1.1.1.14 root 9707: *(UINT8 *)(mem + 0x451) = csbi.dwCursorPosition.Y - scr_top;
1.1 root 9708: *(UINT8 *)(mem + 0x460) = 7;
9709: *(UINT8 *)(mem + 0x461) = 7;
9710: *(UINT8 *)(mem + 0x462) = 0;
9711: *(UINT16 *)(mem + 0x463) = 0x3d4;
1.1.1.19 root 9712: *(UINT8 *)(mem + 0x465) = 0x09;
9713: *(UINT32 *)(mem + 0x46c) = get_ticks_since_midnight(timeGetTime());
1.1.1.14 root 9714: *(UINT8 *)(mem + 0x484) = csbi.srWindow.Bottom - csbi.srWindow.Top;
9715: *(UINT8 *)(mem + 0x485) = cfi.dwFontSize.Y;
9716: *(UINT8 *)(mem + 0x487) = 0x60;
9717: *(UINT8 *)(mem + 0x496) = 0x10; // enhanced keyboard installed
9718:
9719: // initial screen
9720: SMALL_RECT rect;
9721: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
9722: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
9723: for(int y = 0, ofs1 = TEXT_VRAM_TOP, ofs2 = SHADOW_BUF_TOP; y < scr_height; y++) {
9724: for(int x = 0; x < scr_width; x++) {
9725: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Char.AsciiChar;
9726: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Attributes;
9727: }
9728: }
1.1 root 9729:
9730: // dos info
9731: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
1.1.1.19 root 9732: dos_info->magic_word = 1;
1.1 root 9733: dos_info->first_mcb = MEMORY_TOP >> 4;
9734: dos_info->first_dpb.w.l = 0;
9735: dos_info->first_dpb.w.h = DPB_TOP >> 4;
9736: dos_info->first_sft.w.l = 0;
1.1.1.21 root 9737: dos_info->first_sft.w.h = SFT_TOP >> 4;
1.1.1.19 root 9738: dos_info->max_sector_len = 512;
9739: dos_info->disk_buf_info.w.l = offsetof(dos_info_t, disk_buf_heads);
9740: dos_info->disk_buf_info.w.h = DOS_INFO_TOP >> 4;
1.1 root 9741: dos_info->cds.w.l = 0;
9742: dos_info->cds.w.h = CDS_TOP >> 4;
9743: dos_info->fcb_table.w.l = 0;
9744: dos_info->fcb_table.w.h = FCB_TABLE_TOP >> 4;
9745: dos_info->last_drive = 'Z' - 'A' + 1;
9746: dos_info->buffers_x = 20;
9747: dos_info->buffers_y = 0;
1.1.1.14 root 9748: dos_info->boot_drive = 'C' - 'A' + 1;
1.1.1.19 root 9749: dos_info->nul_device.next_driver = 0xffffffffU;
9750: dos_info->nul_device.attributes = 0x8004U;
9751: dos_info->nul_device.strategy = 0xffffU;
9752: dos_info->nul_device.interrupt = 0xffffU;
9753: memcpy(dos_info->nul_device.dev_name, "NUL ", 8);
9754: dos_info->disk_buf_heads.w.l = 0;
9755: dos_info->disk_buf_heads.w.h = DISK_BUF_TOP >> 4;
1.1.1.20 root 9756: dos_info->first_umb_fcb = UMB_TOP >> 4;
9757: dos_info->first_mcb_2 = MEMORY_TOP >> 4;
1.1.1.17 root 9758:
1.1 root 9759: char *env;
9760: if((env = getenv("LASTDRIVE")) != NULL) {
9761: if(env[0] >= 'A' && env[0] <= 'Z') {
9762: dos_info->last_drive = env[0] - 'A' + 1;
9763: } else if(env[0] >= 'a' && env[0] <= 'z') {
9764: dos_info->last_drive = env[0] - 'a' + 1;
9765: }
9766: }
9767: if((env = getenv("windir")) != NULL) {
9768: if(env[0] >= 'A' && env[0] <= 'Z') {
9769: dos_info->boot_drive = env[0] - 'A' + 1;
9770: } else if(env[0] >= 'a' && env[0] <= 'z') {
9771: dos_info->boot_drive = env[0] - 'a' + 1;
9772: }
9773: }
1.1.1.3 root 9774: #if defined(HAS_I386)
1.1 root 9775: dos_info->i386_or_later = 1;
1.1.1.3 root 9776: #else
9777: dos_info->i386_or_later = 0;
9778: #endif
1.1.1.17 root 9779: dos_info->ext_mem_size = (min(MAX_MEM, 0x4000000) - 0x100000) >> 10;
1.1 root 9780:
1.1.1.19 root 9781: // init mcb
1.1 root 9782: int seg = MEMORY_TOP >> 4;
1.1.1.19 root 9783:
9784: // iret table
9785: // note: int 2eh vector should address the routine in command.com,
9786: // and some softwares invite (int 2eh vector segment) - 1 must address the mcb of command.com.
9787: // so move iret table into allocated memory block
9788: // http://www5c.biglobe.ne.jp/~ecb/assembler2/2_6.html
9789: msdos_mcb_create(seg++, 'M', -1, IRET_SIZE >> 4);
9790: IRET_TOP = seg << 4;
9791: seg += IRET_SIZE >> 4;
9792: memset(mem + IRET_TOP, 0xcf, IRET_SIZE);
9793:
9794: // dummy xms/ems device
9795: msdos_mcb_create(seg++, 'M', -1, XMS_SIZE >> 4);
9796: XMS_TOP = seg << 4;
9797: seg += XMS_SIZE >> 4;
9798:
9799: // environment
1.1 root 9800: msdos_mcb_create(seg++, 'M', -1, ENV_SIZE >> 4);
9801: int env_seg = seg;
9802: int ofs = 0;
1.1.1.15 root 9803: char env_path[8192] = "", *path;
1.1 root 9804:
9805: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1.1.14 root 9806: if(_strnicmp(*p, "MSDOS_PATH=", 11) == 0) {
9807: sprintf(env_path, "%s;", *p + 11);
9808: break;
9809: }
9810: }
9811: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1.1.9 root 9812: if(_strnicmp(*p, "PATH=", 5) == 0) {
1.1.1.14 root 9813: strcat(env_path, *p + 5);
1.1.1.9 root 9814: break;
9815: }
9816: }
1.1.1.18 root 9817: if((path = getenv("MSDOS_COMSPEC")) != NULL ||
9818: (path = msdos_search_command_com(argv[0], env_path)) != NULL) {
1.1.1.15 root 9819: strcpy(comspec_path, path);
9820: }
9821:
1.1.1.9 root 9822: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1 root 9823: // lower to upper
9824: char tmp[ENV_SIZE], name[ENV_SIZE], value[ENV_SIZE];
9825: int value_pos = 0;
9826: strcpy(tmp, *p);
9827: for(int i = 0;; i++) {
9828: if(tmp[i] == '=') {
9829: tmp[i] = '\0';
9830: sprintf(name, ";%s;", tmp);
9831: strcpy(value, tmp + (value_pos = i + 1));
9832: tmp[i] = '=';
9833: break;
9834: } else if(tmp[i] >= 'a' && tmp[i] <= 'z') {
9835: tmp[i] = tmp[i] - 'a' + 'A';
9836: }
9837: }
1.1.1.18 root 9838: if(strncmp(tmp, "MSDOS_COMSPEC=", 14) == 0) {
9839: // ignore MSDOS_COMSPEC
9840: } else if(standard_env && strstr(";COMSPEC;INCLUDE;LIB;PATH;PROMPT;TEMP;TMP;TZ;", name) == NULL) {
9841: // ignore non standard environments
9842: } else {
1.1 root 9843: if(strncmp(tmp, "COMSPEC=", 8) == 0) {
1.1.1.14 root 9844: strcpy(tmp, "COMSPEC=C:\\COMMAND.COM");
1.1 root 9845: } else if(strncmp(tmp, "PATH=", 5) == 0 || strncmp(tmp, "TEMP=", 5) == 0 || strncmp(tmp, "TMP=", 4) == 0) {
9846: tmp[value_pos] = '\0';
9847: char *token = my_strtok(value, ";");
9848: while(token != NULL) {
9849: if(strlen(token) != 0) {
1.1.1.8 root 9850: char *path = msdos_remove_double_quote(token), tmp_path[MAX_PATH];
9851: if(strlen(path) != 0) {
9852: GetShortPathName(path, tmp_path, MAX_PATH);
9853: strcat(tmp, tmp_path);
9854: strcat(tmp, ";");
1.1 root 9855: }
9856: }
9857: token = my_strtok(NULL, ";");
9858: }
9859: tmp[strlen(tmp) - 1] = '\0';
9860: my_strupr(tmp);
9861: }
9862: int len = strlen(tmp);
1.1.1.14 root 9863: if(ofs + len + 1 + (2 + (8 + 1 + 3)) + 2 > ENV_SIZE) {
1.1 root 9864: fatalerror("too many environments\n");
9865: }
9866: memcpy(mem + (seg << 4) + ofs, tmp, len);
9867: ofs += len + 1;
9868: }
9869: }
9870: seg += (ENV_SIZE >> 4);
9871:
9872: // psp
9873: msdos_mcb_create(seg++, 'M', -1, PSP_SIZE >> 4);
9874: current_psp = seg;
1.1.1.14 root 9875: msdos_psp_create(seg, seg + (PSP_SIZE >> 4), -1, env_seg);
1.1 root 9876: seg += (PSP_SIZE >> 4);
9877:
1.1.1.19 root 9878: // first free mcb in conventional memory
9879: msdos_mcb_create(seg, 'Z', 0, (MEMORY_END >> 4) - seg - 2);
1.1.1.8 root 9880: first_mcb = seg;
9881:
1.1.1.19 root 9882: // dummy mcb to link to umb
9883: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', -1, (UMB_TOP >> 4) - (MEMORY_END >> 4));
9884:
9885: // first free mcb in upper memory block
1.1.1.8 root 9886: msdos_mcb_create(UMB_TOP >> 4, 'Z', 0, (UMB_END >> 4) - (UMB_TOP >> 4) - 1);
1.1 root 9887:
1.1.1.19 root 9888: #ifdef SUPPORT_XMS
9889: // first free mcb in extended memory block
9890: msdos_mcb_create(EMB_TOP >> 4, 'Z', 0, (EMB_END >> 4) - (EMB_TOP >> 4) - 1);
9891: #endif
9892:
9893: // interrupt vector
9894: for(int i = 0; i < 0x80; i++) {
9895: *(UINT16 *)(mem + 4 * i + 0) = i;
9896: *(UINT16 *)(mem + 4 * i + 2) = (IRET_TOP >> 4);
9897: }
9898: *(UINT16 *)(mem + 4 * 0x08 + 0) = 0x0005; // irq0
9899: *(UINT16 *)(mem + 4 * 0x08 + 2) = 0xffff;
9900: *(UINT16 *)(mem + 4 * 0x22 + 0) = 0x0000; // boot
9901: *(UINT16 *)(mem + 4 * 0x22 + 2) = 0xffff;
9902: *(UINT16 *)(mem + 4 * 0x67 + 0) = 0x0000; // ems
9903: *(UINT16 *)(mem + 4 * 0x67 + 2) = XMS_TOP >> 4;
9904:
9905: // ems (int 67h) and xms (call far)
9906: mem[XMS_TOP + 0] = 0xcd; // int 68h (dummy)
9907: mem[XMS_TOP + 1] = 0x68;
9908: mem[XMS_TOP + 2] = 0xcf; // iret
9909: #ifdef SUPPORT_XMS
9910: if(support_xms) {
9911: mem[XMS_TOP + 4] = 0xcd; // int 69h (dummy)
9912: mem[XMS_TOP + 5] = 0x69;
9913: mem[XMS_TOP + 6] = 0xcb; // retf
9914: } else
9915: #endif
9916: mem[XMS_TOP + 4] = 0xcb; // retf
9917: memcpy(mem + XMS_TOP + 0x0a, "EMMXXXX0", 8);
9918:
9919: // case map routine (call far)
9920: mem[0xffffc] = 0xcd; // int 6ah (dummy)
9921: mem[0xffffd] = 0x6a;
9922: mem[0xffffe] = 0xcb; // retf
9923:
1.1.1.14 root 9924: // have irq0 call system timer tick
1.1.1.19 root 9925: mem[0xffff5] = 0xcd; // int 1ch
9926: mem[0xffff6] = 0x1c;
9927: mem[0xffff7] = 0xea; // jmp (IRET_TOP >> 4):0008
9928: mem[0xffff8] = 0x08;
9929: mem[0xffff9] = 0x00;
9930: mem[0xffffa] = ((IRET_TOP >> 4) ) & 0xff;
9931: mem[0xffffb] = ((IRET_TOP >> 4) >> 8) & 0xff;
1.1.1.14 root 9932:
1.1 root 9933: // boot
9934: mem[0xffff0] = 0xf4; // halt
9935: mem[0xffff1] = 0xcd; // int 21h
9936: mem[0xffff2] = 0x21;
9937: mem[0xffff3] = 0xcb; // retf
9938:
9939: // param block
9940: // + 0: param block (22bytes)
9941: // +24: fcb1/2 (20bytes)
9942: // +44: command tail (128bytes)
9943: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
9944: param->env_seg = 0;
9945: param->cmd_line.w.l = 44;
9946: param->cmd_line.w.h = (WORK_TOP >> 4);
9947: param->fcb1.w.l = 24;
9948: param->fcb1.w.h = (WORK_TOP >> 4);
9949: param->fcb2.w.l = 24;
9950: param->fcb2.w.h = (WORK_TOP >> 4);
9951:
9952: memset(mem + WORK_TOP + 24, 0x20, 20);
9953:
9954: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
9955: if(argc > 1) {
9956: sprintf(cmd_line->cmd, " %s", argv[1]);
9957: for(int i = 2; i < argc; i++) {
9958: char tmp[128];
9959: sprintf(tmp, "%s %s", cmd_line->cmd, argv[i]);
9960: strcpy(cmd_line->cmd, tmp);
9961: }
9962: cmd_line->len = (UINT8)strlen(cmd_line->cmd);
9963: } else {
9964: cmd_line->len = 0;
9965: }
9966: cmd_line->cmd[cmd_line->len] = 0x0d;
9967:
9968: // system file table
1.1.1.21 root 9969: *(UINT32 *)(mem + SFT_TOP + 0) = 0xffffffff;
9970: *(UINT16 *)(mem + SFT_TOP + 4) = 20;
1.1 root 9971:
1.1.1.19 root 9972: // disk buffer header (from DOSBox)
9973: *(UINT16 *)(mem + DISK_BUF_TOP + 0) = 0xffff; // forward ptr
9974: *(UINT16 *)(mem + DISK_BUF_TOP + 2) = 0xffff; // backward ptr
9975: *(UINT8 *)(mem + DISK_BUF_TOP + 4) = 0xff; // not in use
9976: *(UINT8 *)(mem + DISK_BUF_TOP + 10) = 0x01; // number of FATs
9977: *(UINT32 *)(mem + DISK_BUF_TOP + 13) = 0xffffffff; // pointer to DPB
9978:
1.1 root 9979: // current directory structure
9980: msdos_cds_update(_getdrive() - 1);
9981:
9982: // fcb table
9983: *(UINT32 *)(mem + FCB_TABLE_TOP + 0) = 0xffffffff;
1.1.1.14 root 9984: *(UINT16 *)(mem + FCB_TABLE_TOP + 4) = 0;
1.1 root 9985:
1.1.1.22! root 9986: // error table
! 9987: *(UINT8 *)(mem + ERR_TABLE_TOP + 0) = 0xff;
! 9988: *(UINT8 *)(mem + ERR_TABLE_TOP + 1) = 0x04;
! 9989: *(UINT8 *)(mem + ERR_TABLE_TOP + 2) = 0x00;
! 9990: *(UINT8 *)(mem + ERR_TABLE_TOP + 3) = 0x00;
! 9991:
1.1.1.17 root 9992: // nls stuff
9993: msdos_nls_tables_init();
1.1 root 9994:
9995: // execute command
9996: if(msdos_process_exec(argv[0], param, 0)) {
9997: fatalerror("'%s' not found\n", argv[0]);
9998: }
9999: retval = 0;
10000: return(0);
10001: }
10002:
10003: #define remove_std_file(path) { \
10004: int fd = _open(path, _O_RDONLY | _O_BINARY); \
10005: if(fd != -1) { \
10006: _lseek(fd, 0, SEEK_END); \
10007: int size = _tell(fd); \
10008: _close(fd); \
10009: if(size == 0) { \
10010: remove(path); \
10011: } \
10012: } \
10013: }
10014:
10015: void msdos_finish()
10016: {
10017: for(int i = 0; i < MAX_FILES; i++) {
10018: if(file_handler[i].valid) {
10019: _close(i);
10020: }
10021: }
1.1.1.21 root 10022: #ifdef MAP_AUX_DEVICE_TO_FILE
1.1 root 10023: remove_std_file("stdaux.txt");
1.1.1.21 root 10024: #endif
10025: #ifdef MAP_PRN_DEVICE_TO_FILE
1.1 root 10026: remove_std_file("stdprn.txt");
10027: #endif
10028: msdos_dbcs_table_finish();
10029: }
10030:
10031: /* ----------------------------------------------------------------------------
10032: PC/AT hardware emulation
10033: ---------------------------------------------------------------------------- */
10034:
10035: void hardware_init()
10036: {
1.1.1.3 root 10037: CPU_INIT_CALL(CPU_MODEL);
1.1 root 10038: CPU_RESET_CALL(CPU_MODEL);
1.1.1.14 root 10039: m_IF = 1;
1.1.1.3 root 10040: #if defined(HAS_I386)
1.1 root 10041: cpu_type = (REG32(EDX) >> 8) & 0x0f;
10042: cpu_step = (REG32(EDX) >> 0) & 0x0f;
1.1.1.3 root 10043: #endif
10044: i386_set_a20_line(0);
1.1.1.14 root 10045:
1.1.1.19 root 10046: ems_init();
1.1 root 10047: pic_init();
1.1.1.8 root 10048: #ifdef PIT_ALWAYS_RUNNING
10049: pit_init();
10050: #else
1.1 root 10051: pit_active = 0;
10052: #endif
1.1.1.8 root 10053: cmos_init();
10054: kbd_init();
1.1 root 10055: }
10056:
1.1.1.10 root 10057: void hardware_finish()
10058: {
10059: #if defined(HAS_I386)
10060: vtlb_free(m_vtlb);
10061: #endif
1.1.1.19 root 10062: ems_finish();
1.1.1.10 root 10063: }
10064:
1.1 root 10065: void hardware_run()
10066: {
10067: int ops = 0;
10068:
1.1.1.22! root 10069: #ifdef EXPORT_DEBUG_TO_FILE
! 10070: fdebug = fopen("debug.log", "w");
! 10071: #endif
1.1.1.3 root 10072: while(!m_halted) {
1.1.1.22! root 10073: #ifdef ENABLE_DEBUG_DASM
! 10074: if(dasm > 0) {
1.1 root 10075: char buffer[256];
1.1.1.3 root 10076: #if defined(HAS_I386)
1.1.1.22! root 10077: UINT32 flags = get_flags();
1.1.1.19 root 10078: UINT32 eip = m_eip;
1.1.1.3 root 10079: #else
1.1.1.22! root 10080: UINT32 flags = CompressFlags();
1.1.1.19 root 10081: UINT32 eip = m_pc - SREG_BASE(CS);
1.1.1.3 root 10082: #endif
10083: UINT8 *oprom = mem + SREG_BASE(CS) + eip;
1.1 root 10084:
1.1.1.3 root 10085: #if defined(HAS_I386)
10086: if(m_operand_size) {
1.1 root 10087: CPU_DISASSEMBLE_CALL(x86_32);
1.1.1.3 root 10088: } else
10089: #endif
10090: CPU_DISASSEMBLE_CALL(x86_16);
1.1.1.22! root 10091:
! 10092: fprintf(fdebug, "AX=%04X BX=%04X CX=%04X DX=%04X SP=%04X BP=%04X SI=%04X DI=%04X\nDS=%04X ES=%04X SS=%04X CS=%04X IP=%04X FLAG=[%s %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c]\n",
! 10093: REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SP), REG16(BP), REG16(SI), REG16(DI), SREG(DS), SREG(ES), SREG(SS), SREG(CS), eip,
! 10094: #if defined(HAS_I386)
! 10095: PROTECTED_MODE ? "PE" : "--",
! 10096: #else
! 10097: "--",
! 10098: #endif
! 10099: (flags & 0x40000) ? 'A' : '-',
! 10100: (flags & 0x20000) ? 'V' : '-',
! 10101: (flags & 0x10000) ? 'R' : '-',
! 10102: (flags & 0x04000) ? 'N' : '-',
! 10103: (flags & 0x02000) ? '1' : '0',
! 10104: (flags & 0x01000) ? '1' : '0',
! 10105: (flags & 0x00800) ? 'O' : '-',
! 10106: (flags & 0x00400) ? 'D' : '-',
! 10107: (flags & 0x00200) ? 'I' : '-',
! 10108: (flags & 0x00100) ? 'T' : '-',
! 10109: (flags & 0x00080) ? 'S' : '-',
! 10110: (flags & 0x00040) ? 'Z' : '-',
! 10111: (flags & 0x00010) ? 'A' : '-',
! 10112: (flags & 0x00004) ? 'P' : '-',
! 10113: (flags & 0x00001) ? 'C' : '-');
! 10114: fprintf(fdebug, "%04X:%04X\t%s\n", SREG(CS), (unsigned)eip, buffer);
! 10115: dasm--;
1.1 root 10116: }
10117: #endif
1.1.1.3 root 10118: #if defined(HAS_I386)
10119: m_cycles = 1;
1.1 root 10120: CPU_EXECUTE_CALL(i386);
1.1.1.3 root 10121: #else
10122: CPU_EXECUTE_CALL(CPU_MODEL);
10123: #endif
1.1.1.14 root 10124: #if defined(HAS_I386)
10125: if(m_eip != m_prev_eip) {
10126: #else
10127: if(m_pc != m_prevpc) {
10128: #endif
10129: iops++;
10130: }
1.1.1.8 root 10131: if(++ops == 16384) {
1.1 root 10132: hardware_update();
10133: ops = 0;
10134: }
10135: }
1.1.1.22! root 10136: #ifdef EXPORT_DEBUG_TO_FILE
! 10137: fclose(fdebug);
! 10138: #endif
1.1 root 10139: }
10140:
10141: void hardware_update()
10142: {
1.1.1.8 root 10143: static UINT32 prev_time = 0;
10144: UINT32 cur_time = timeGetTime();
10145:
10146: if(prev_time != cur_time) {
10147: // update pit and raise irq0
10148: #ifndef PIT_ALWAYS_RUNNING
10149: if(pit_active)
10150: #endif
10151: {
10152: if(pit_run(0, cur_time)) {
10153: pic_req(0, 0, 1);
10154: }
10155: pit_run(1, cur_time);
10156: pit_run(2, cur_time);
10157: }
10158: // check key input and raise irq1
1.1.1.14 root 10159: static UINT32 prev_tick = 0;
10160: UINT32 cur_tick = cur_time / 32;
10161: if(prev_tick != cur_tick) {
10162: // update keyboard flags
10163: UINT8 state;
10164: state = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
10165: state |= (GetAsyncKeyState(VK_CAPITAL) & 0x0001) ? 0x40 : 0;
10166: state |= (GetAsyncKeyState(VK_NUMLOCK) & 0x0001) ? 0x20 : 0;
10167: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
10168: state |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
10169: state |= (GetAsyncKeyState(VK_CONTROL) & 0x8000) ? 0x04 : 0;
10170: state |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
10171: state |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
10172: mem[0x417] = state;
10173: state = (GetAsyncKeyState(VK_INSERT ) & 0x8000) ? 0x80 : 0;
10174: state |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
10175: state |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
10176: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
10177: // state |= (GetAsyncKeyState(VK_PAUSE ) & 0x0001) ? 0x08 : 0;
10178: // state |= (GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x04 : 0;
10179: state |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
10180: state |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
10181: mem[0x418] = state;
10182:
10183: // update keyboard input
1.1.1.8 root 10184: if(check_key_input()) {
10185: pic_req(0, 1, 1);
10186: }
1.1.1.14 root 10187: prev_tick = cur_tick;
1.1.1.8 root 10188: }
1.1.1.19 root 10189: // update daily timer counter
10190: pcbios_update_daily_timer_counter(cur_time);
1.1.1.8 root 10191: prev_time = cur_time;
1.1 root 10192: }
10193: }
10194:
1.1.1.19 root 10195: // ems
10196:
10197: void ems_init()
10198: {
10199: memset(ems_handles, 0, sizeof(ems_handles));
10200: memset(ems_pages, 0, sizeof(ems_pages));
10201: free_ems_pages = MAX_EMS_PAGES;
10202: }
10203:
10204: void ems_finish()
10205: {
10206: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
10207: if(ems_handles[i].buffer) {
10208: free(ems_handles[i].buffer);
10209: ems_handles[i].buffer = NULL;
10210: }
10211: }
10212: }
10213:
10214: void ems_allocate_pages(int handle, int pages)
10215: {
10216: if(pages > 0) {
10217: ems_handles[handle].buffer = (UINT8 *)calloc(1, 0x4000 * pages);
10218: } else {
10219: ems_handles[handle].buffer = NULL;
10220: }
10221: ems_handles[handle].pages = pages;
10222: ems_handles[handle].allocated = true;
10223: free_ems_pages -= pages;
10224: }
10225:
10226: void ems_reallocate_pages(int handle, int pages)
10227: {
10228: if(ems_handles[handle].allocated) {
10229: if(ems_handles[handle].pages != pages) {
10230: UINT8 *new_buffer = NULL;
10231:
10232: if(pages > 0) {
10233: new_buffer = (UINT8 *)calloc(1, 0x4000 * pages);
10234: }
10235: if(ems_handles[handle].buffer) {
10236: if(new_buffer) {
10237: if(pages > ems_handles[handle].pages) {
10238: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * ems_handles[handle].pages);
10239: } else {
10240: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * pages);
10241: }
10242: }
10243: free(ems_handles[handle].buffer);
10244: ems_handles[handle].buffer = NULL;
10245: }
10246: free_ems_pages += ems_handles[handle].pages;
10247:
10248: ems_handles[handle].buffer = new_buffer;
10249: ems_handles[handle].pages = pages;
10250: free_ems_pages -= pages;
10251: }
10252: } else {
10253: ems_allocate_pages(handle, pages);
10254: }
10255: }
10256:
10257: void ems_release_pages(int handle)
10258: {
10259: if(ems_handles[handle].allocated) {
10260: if(ems_handles[handle].buffer) {
10261: free(ems_handles[handle].buffer);
10262: ems_handles[handle].buffer = NULL;
10263: }
10264: free_ems_pages += ems_handles[handle].pages;
10265: ems_handles[handle].allocated = false;
10266: }
10267: }
10268:
10269: void ems_map_page(int physical, int handle, int logical)
10270: {
10271: if(ems_pages[physical].mapped) {
10272: if(ems_pages[physical].handle == handle && ems_pages[physical].page == logical) {
10273: return;
10274: }
10275: ems_unmap_page(physical);
10276: }
10277: if(ems_handles[handle].allocated && ems_handles[handle].buffer && logical < ems_handles[handle].pages) {
10278: memcpy(mem + EMS_TOP + 0x4000 * physical, ems_handles[handle].buffer + 0x4000 * logical, 0x4000);
10279: }
10280: ems_pages[physical].handle = handle;
10281: ems_pages[physical].page = logical;
10282: ems_pages[physical].mapped = true;
10283: }
10284:
10285: void ems_unmap_page(int physical)
10286: {
10287: if(ems_pages[physical].mapped) {
10288: int handle = ems_pages[physical].handle;
10289: int logical = ems_pages[physical].page;
10290:
10291: if(ems_handles[handle].allocated && ems_handles[handle].buffer && logical < ems_handles[handle].pages) {
10292: memcpy(ems_handles[handle].buffer + 0x4000 * logical, mem + EMS_TOP + 0x4000 * physical, 0x4000);
10293: }
10294: ems_pages[physical].mapped = false;
10295: }
10296: }
10297:
1.1 root 10298: // pic
10299:
10300: void pic_init()
10301: {
1.1.1.8 root 10302: memset(pic, 0, sizeof(pic));
10303: pic[0].imr = pic[1].imr = 0xff;
1.1 root 10304:
10305: // from bochs bios
10306: pic_write(0, 0, 0x11); // icw1 = 11h
10307: pic_write(0, 1, 0x08); // icw2 = 08h
10308: pic_write(0, 1, 0x04); // icw3 = 04h
10309: pic_write(0, 1, 0x01); // icw4 = 01h
10310: pic_write(0, 1, 0xb8); // ocw1 = b8h
10311: pic_write(1, 0, 0x11); // icw1 = 11h
10312: pic_write(1, 1, 0x70); // icw2 = 70h
10313: pic_write(1, 1, 0x02); // icw3 = 02h
10314: pic_write(1, 1, 0x01); // icw4 = 01h
10315: }
10316:
10317: void pic_write(int c, UINT32 addr, UINT8 data)
10318: {
10319: if(addr & 1) {
10320: if(pic[c].icw2_r) {
10321: // icw2
10322: pic[c].icw2 = data;
10323: pic[c].icw2_r = 0;
10324: } else if(pic[c].icw3_r) {
10325: // icw3
10326: pic[c].icw3 = data;
10327: pic[c].icw3_r = 0;
10328: } else if(pic[c].icw4_r) {
10329: // icw4
10330: pic[c].icw4 = data;
10331: pic[c].icw4_r = 0;
10332: } else {
10333: // ocw1
10334: pic[c].imr = data;
10335: }
10336: } else {
10337: if(data & 0x10) {
10338: // icw1
10339: pic[c].icw1 = data;
10340: pic[c].icw2_r = 1;
10341: pic[c].icw3_r = (data & 2) ? 0 : 1;
10342: pic[c].icw4_r = data & 1;
10343: pic[c].irr = 0;
10344: pic[c].isr = 0;
10345: pic[c].imr = 0;
10346: pic[c].prio = 0;
10347: if(!(pic[c].icw1 & 1)) {
10348: pic[c].icw4 = 0;
10349: }
10350: pic[c].ocw3 = 0;
10351: } else if(data & 8) {
10352: // ocw3
10353: if(!(data & 2)) {
10354: data = (data & ~1) | (pic[c].ocw3 & 1);
10355: }
10356: if(!(data & 0x40)) {
10357: data = (data & ~0x20) | (pic[c].ocw3 & 0x20);
10358: }
10359: pic[c].ocw3 = data;
10360: } else {
10361: // ocw2
10362: int level = 0;
10363: if(data & 0x40) {
10364: level = data & 7;
10365: } else {
10366: if(!pic[c].isr) {
10367: return;
10368: }
10369: level = pic[c].prio;
10370: while(!(pic[c].isr & (1 << level))) {
10371: level = (level + 1) & 7;
10372: }
10373: }
10374: if(data & 0x80) {
10375: pic[c].prio = (level + 1) & 7;
10376: }
10377: if(data & 0x20) {
10378: pic[c].isr &= ~(1 << level);
10379: }
10380: }
10381: }
10382: pic_update();
10383: }
10384:
10385: UINT8 pic_read(int c, UINT32 addr)
10386: {
10387: if(addr & 1) {
10388: return(pic[c].imr);
10389: } else {
10390: // polling mode is not supported...
10391: //if(pic[c].ocw3 & 4) {
10392: // return ???;
10393: //}
10394: if(pic[c].ocw3 & 1) {
10395: return(pic[c].isr);
10396: } else {
10397: return(pic[c].irr);
10398: }
10399: }
10400: }
10401:
10402: void pic_req(int c, int level, int signal)
10403: {
10404: if(signal) {
10405: pic[c].irr |= (1 << level);
10406: } else {
10407: pic[c].irr &= ~(1 << level);
10408: }
10409: pic_update();
10410: }
10411:
10412: int pic_ack()
10413: {
10414: // ack (INTA=L)
10415: pic[pic_req_chip].isr |= pic_req_bit;
10416: pic[pic_req_chip].irr &= ~pic_req_bit;
10417: if(pic_req_chip > 0) {
10418: // update isr and irr of master
10419: UINT8 slave = 1 << (pic[pic_req_chip].icw3 & 7);
10420: pic[pic_req_chip - 1].isr |= slave;
10421: pic[pic_req_chip - 1].irr &= ~slave;
10422: }
10423: //if(pic[pic_req_chip].icw4 & 1) {
10424: // 8086 mode
10425: int vector = (pic[pic_req_chip].icw2 & 0xf8) | pic_req_level;
10426: //} else {
10427: // // 8080 mode
10428: // UINT16 addr = (UINT16)pic[pic_req_chip].icw2 << 8;
10429: // if(pic[pic_req_chip].icw1 & 4) {
10430: // addr |= (pic[pic_req_chip].icw1 & 0xe0) | (pic_req_level << 2);
10431: // } else {
10432: // addr |= (pic[pic_req_chip].icw1 & 0xc0) | (pic_req_level << 3);
10433: // }
10434: // vector = 0xcd | (addr << 8);
10435: //}
10436: if(pic[pic_req_chip].icw4 & 2) {
10437: // auto eoi
10438: pic[pic_req_chip].isr &= ~pic_req_bit;
10439: }
10440: return(vector);
10441: }
10442:
10443: void pic_update()
10444: {
10445: for(int c = 0; c < 2; c++) {
10446: UINT8 irr = pic[c].irr;
10447: if(c + 1 < 2) {
10448: // this is master
10449: if(pic[c + 1].irr & (~pic[c + 1].imr)) {
10450: // request from slave
10451: irr |= 1 << (pic[c + 1].icw3 & 7);
10452: }
10453: }
10454: irr &= (~pic[c].imr);
10455: if(!irr) {
10456: break;
10457: }
10458: if(!(pic[c].ocw3 & 0x20)) {
10459: irr |= pic[c].isr;
10460: }
10461: int level = pic[c].prio;
10462: UINT8 bit = 1 << level;
10463: while(!(irr & bit)) {
10464: level = (level + 1) & 7;
10465: bit = 1 << level;
10466: }
10467: if((c + 1 < 2) && (pic[c].icw3 & bit)) {
10468: // check slave
10469: continue;
10470: }
10471: if(pic[c].isr & bit) {
10472: break;
10473: }
10474: // interrupt request
10475: pic_req_chip = c;
10476: pic_req_level = level;
10477: pic_req_bit = bit;
1.1.1.3 root 10478: i386_set_irq_line(INPUT_LINE_IRQ, HOLD_LINE);
1.1 root 10479: return;
10480: }
1.1.1.3 root 10481: i386_set_irq_line(INPUT_LINE_IRQ, CLEAR_LINE);
1.1.1.2 root 10482: }
1.1 root 10483:
10484: // pit
10485:
1.1.1.22! root 10486: #define PIT_FREQ 1193182ULL
1.1 root 10487: #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)
10488:
10489: void pit_init()
10490: {
1.1.1.8 root 10491: memset(pit, 0, sizeof(pit));
1.1 root 10492: for(int ch = 0; ch < 3; ch++) {
10493: pit[ch].count = 0x10000;
10494: pit[ch].ctrl_reg = 0x34;
10495: pit[ch].mode = 3;
10496: }
10497:
10498: // from bochs bios
10499: pit_write(3, 0x34);
10500: pit_write(0, 0x00);
10501: pit_write(0, 0x00);
10502: }
10503:
10504: void pit_write(int ch, UINT8 val)
10505: {
1.1.1.8 root 10506: #ifndef PIT_ALWAYS_RUNNING
1.1 root 10507: if(!pit_active) {
10508: pit_active = 1;
10509: pit_init();
10510: }
1.1.1.8 root 10511: #endif
1.1 root 10512: switch(ch) {
10513: case 0:
10514: case 1:
10515: case 2:
10516: // write count register
10517: if(!pit[ch].low_write && !pit[ch].high_write) {
10518: if(pit[ch].ctrl_reg & 0x10) {
10519: pit[ch].low_write = 1;
10520: }
10521: if(pit[ch].ctrl_reg & 0x20) {
10522: pit[ch].high_write = 1;
10523: }
10524: }
10525: if(pit[ch].low_write) {
10526: pit[ch].count_reg = val;
10527: pit[ch].low_write = 0;
10528: } else if(pit[ch].high_write) {
10529: if((pit[ch].ctrl_reg & 0x30) == 0x20) {
10530: pit[ch].count_reg = val << 8;
10531: } else {
10532: pit[ch].count_reg |= val << 8;
10533: }
10534: pit[ch].high_write = 0;
10535: }
10536: // start count
1.1.1.8 root 10537: if(!pit[ch].low_write && !pit[ch].high_write) {
10538: if(pit[ch].mode == 0 || pit[ch].mode == 4 || pit[ch].prev_time == 0) {
10539: pit[ch].count = PIT_COUNT_VALUE(ch);
10540: pit[ch].prev_time = timeGetTime();
10541: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 10542: }
10543: }
10544: break;
10545: case 3: // ctrl reg
10546: if((val & 0xc0) == 0xc0) {
10547: // i8254 read-back command
10548: for(ch = 0; ch < 3; ch++) {
10549: if(!(val & 0x10) && !pit[ch].status_latched) {
10550: pit[ch].status = pit[ch].ctrl_reg & 0x3f;
10551: pit[ch].status_latched = 1;
10552: }
10553: if(!(val & 0x20) && !pit[ch].count_latched) {
10554: pit_latch_count(ch);
10555: }
10556: }
10557: break;
10558: }
10559: ch = (val >> 6) & 3;
10560: if(val & 0x30) {
10561: static int modes[8] = {0, 1, 2, 3, 4, 5, 2, 3};
10562: pit[ch].mode = modes[(val >> 1) & 7];
10563: pit[ch].count_latched = 0;
10564: pit[ch].low_read = pit[ch].high_read = 0;
10565: pit[ch].low_write = pit[ch].high_write = 0;
10566: pit[ch].ctrl_reg = val;
10567: // stop count
1.1.1.8 root 10568: pit[ch].prev_time = pit[ch].expired_time = 0;
1.1 root 10569: pit[ch].count_reg = 0;
10570: } else if(!pit[ch].count_latched) {
10571: pit_latch_count(ch);
10572: }
10573: break;
10574: }
10575: }
10576:
10577: UINT8 pit_read(int ch)
10578: {
1.1.1.8 root 10579: #ifndef PIT_ALWAYS_RUNNING
1.1 root 10580: if(!pit_active) {
10581: pit_active = 1;
10582: pit_init();
10583: }
1.1.1.8 root 10584: #endif
1.1 root 10585: switch(ch) {
10586: case 0:
10587: case 1:
10588: case 2:
10589: if(pit[ch].status_latched) {
10590: pit[ch].status_latched = 0;
10591: return(pit[ch].status);
10592: }
10593: // if not latched, through current count
10594: if(!pit[ch].count_latched) {
10595: if(!pit[ch].low_read && !pit[ch].high_read) {
10596: pit_latch_count(ch);
10597: }
10598: }
10599: // return latched count
10600: if(pit[ch].low_read) {
10601: pit[ch].low_read = 0;
10602: if(!pit[ch].high_read) {
10603: pit[ch].count_latched = 0;
10604: }
10605: return(pit[ch].latch & 0xff);
10606: } else if(pit[ch].high_read) {
10607: pit[ch].high_read = 0;
10608: pit[ch].count_latched = 0;
10609: return((pit[ch].latch >> 8) & 0xff);
10610: }
10611: }
10612: return(0xff);
10613: }
10614:
1.1.1.8 root 10615: int pit_run(int ch, UINT32 cur_time)
1.1 root 10616: {
1.1.1.8 root 10617: if(pit[ch].expired_time != 0 && cur_time >= pit[ch].expired_time) {
1.1 root 10618: pit[ch].count = PIT_COUNT_VALUE(ch);
1.1.1.8 root 10619: pit[ch].prev_time = pit[ch].expired_time;
10620: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
10621: if(cur_time >= pit[ch].expired_time) {
10622: pit[ch].prev_time = cur_time;
10623: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 10624: }
1.1.1.8 root 10625: return(1);
1.1 root 10626: }
1.1.1.8 root 10627: return(0);
1.1 root 10628: }
10629:
10630: void pit_latch_count(int ch)
10631: {
1.1.1.8 root 10632: UINT32 cur_time = timeGetTime();
10633:
10634: if(pit[ch].expired_time != 0) {
10635: pit_run(ch, cur_time);
10636: UINT32 tmp = (pit[ch].count * (pit[ch].expired_time - cur_time)) / (pit[ch].expired_time - pit[ch].prev_time);
10637: pit[ch].latch = (tmp != 0) ? (UINT16)tmp : 1;
10638: } else {
10639: pit[ch].latch = (UINT16)pit[ch].count;
1.1 root 10640: }
10641: pit[ch].count_latched = 1;
10642: if((pit[ch].ctrl_reg & 0x30) == 0x10) {
10643: // lower byte
10644: pit[ch].low_read = 1;
10645: pit[ch].high_read = 0;
10646: } else if((pit[ch].ctrl_reg & 0x30) == 0x20) {
10647: // upper byte
10648: pit[ch].low_read = 0;
10649: pit[ch].high_read = 1;
10650: } else {
10651: // lower -> upper
1.1.1.14 root 10652: pit[ch].low_read = pit[ch].high_read = 1;
1.1 root 10653: }
10654: }
10655:
1.1.1.8 root 10656: int pit_get_expired_time(int ch)
1.1 root 10657: {
1.1.1.22! root 10658: pit[ch].accum += 1024ULL * 1000ULL * (UINT64)pit[ch].count / PIT_FREQ;
! 10659: UINT64 val = pit[ch].accum >> 10;
! 10660: pit[ch].accum -= val << 10;
! 10661: return((val != 0) ? val : 1);
1.1.1.8 root 10662: }
10663:
10664: // cmos
10665:
10666: void cmos_init()
10667: {
10668: memset(cmos, 0, sizeof(cmos));
10669: cmos_addr = 0;
1.1 root 10670:
1.1.1.8 root 10671: // from DOSBox
10672: cmos_write(0x0a, 0x26);
10673: cmos_write(0x0b, 0x02);
10674: cmos_write(0x0d, 0x80);
1.1 root 10675: }
10676:
1.1.1.8 root 10677: void cmos_write(int addr, UINT8 val)
1.1 root 10678: {
1.1.1.8 root 10679: cmos[addr & 0x7f] = val;
10680: }
10681:
10682: #define CMOS_GET_TIME() { \
10683: UINT32 cur_sec = timeGetTime() / 1000 ; \
10684: if(prev_sec != cur_sec) { \
10685: GetLocalTime(&time); \
10686: prev_sec = cur_sec; \
10687: } \
1.1 root 10688: }
1.1.1.8 root 10689: #define CMOS_BCD(v) ((cmos[0x0b] & 4) ? (v) : to_bcd(v))
1.1 root 10690:
1.1.1.8 root 10691: UINT8 cmos_read(int addr)
1.1 root 10692: {
1.1.1.8 root 10693: static SYSTEMTIME time;
10694: static UINT32 prev_sec = 0;
1.1 root 10695:
1.1.1.8 root 10696: switch(addr & 0x7f) {
10697: case 0x00: CMOS_GET_TIME(); return(CMOS_BCD(time.wSecond));
10698: case 0x02: CMOS_GET_TIME(); return(CMOS_BCD(time.wMinute));
10699: case 0x04: CMOS_GET_TIME(); return(CMOS_BCD(time.wHour));
10700: case 0x06: CMOS_GET_TIME(); return(time.wDayOfWeek + 1);
10701: case 0x07: CMOS_GET_TIME(); return(CMOS_BCD(time.wDay));
10702: case 0x08: CMOS_GET_TIME(); return(CMOS_BCD(time.wMonth));
10703: case 0x09: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear));
10704: // case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 2 ? 0x80 : 0)); // 2msec
10705: case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 20 ? 0x80 : 0)); // precision of timeGetTime() may not be 1msec
10706: case 0x15: return((MEMORY_END >> 10) & 0xff);
10707: case 0x16: return((MEMORY_END >> 18) & 0xff);
10708: case 0x17: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
10709: case 0x18: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
10710: case 0x30: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
10711: case 0x31: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
10712: case 0x32: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear / 100));
1.1 root 10713: }
1.1.1.8 root 10714: return(cmos[addr & 0x7f]);
1.1 root 10715: }
10716:
1.1.1.7 root 10717: // kbd (a20)
10718:
10719: void kbd_init()
10720: {
1.1.1.8 root 10721: kbd_data = kbd_command = 0;
1.1.1.7 root 10722: kbd_status = 0x18;
10723: }
10724:
10725: UINT8 kbd_read_data()
10726: {
1.1.1.8 root 10727: kbd_status &= ~1;
1.1.1.7 root 10728: return(kbd_data);
10729: }
10730:
10731: void kbd_write_data(UINT8 val)
10732: {
10733: switch(kbd_command) {
10734: case 0xd1:
10735: i386_set_a20_line((val >> 1) & 1);
10736: break;
10737: }
10738: kbd_command = 0;
1.1.1.8 root 10739: kbd_status &= ~8;
1.1.1.7 root 10740: }
10741:
10742: UINT8 kbd_read_status()
10743: {
10744: return(kbd_status);
10745: }
10746:
10747: void kbd_write_command(UINT8 val)
10748: {
10749: switch(val) {
10750: case 0xd0:
10751: kbd_data = ((m_a20_mask >> 19) & 2) | 1;
1.1.1.8 root 10752: kbd_status |= 1;
1.1.1.7 root 10753: break;
10754: case 0xdd:
10755: i386_set_a20_line(0);
10756: break;
10757: case 0xdf:
10758: i386_set_a20_line(1);
10759: break;
10760: case 0xf0:
10761: case 0xf1:
10762: case 0xf2:
10763: case 0xf3:
10764: case 0xf4:
10765: case 0xf5:
10766: case 0xf6:
10767: case 0xf7:
10768: case 0xf8:
10769: case 0xf9:
10770: case 0xfa:
10771: case 0xfb:
10772: case 0xfc:
10773: case 0xfd:
10774: case 0xfe:
10775: case 0xff:
10776: if(!(val & 1)) {
1.1.1.8 root 10777: if((cmos[0x0f] & 0x7f) == 5) {
1.1.1.7 root 10778: // reset pic
10779: pic_init();
10780: pic[0].irr = pic[1].irr = 0x00;
10781: pic[0].imr = pic[1].imr = 0xff;
10782: }
10783: CPU_RESET_CALL(CPU_MODEL);
10784: i386_jmp_far(0x40, 0x67);
10785: }
10786: i386_set_a20_line((val >> 1) & 1);
10787: break;
10788: }
10789: kbd_command = val;
1.1.1.8 root 10790: kbd_status |= 8;
1.1.1.7 root 10791: }
10792:
1.1.1.9 root 10793: // vga
10794:
10795: UINT8 vga_read_status()
10796: {
10797: // 60hz
10798: static const int period[3] = {16, 17, 17};
10799: static int index = 0;
10800: UINT32 time = timeGetTime() % period[index];
10801:
10802: index = (index + 1) % 3;
1.1.1.14 root 10803: return((time < 4 ? 0x08 : 0) | (time == 0 ? 0 : 0x01));
1.1.1.9 root 10804: }
10805:
1.1 root 10806: // i/o bus
10807:
10808: UINT8 read_io_byte(offs_t addr)
10809: {
10810: switch(addr) {
10811: case 0x20:
10812: case 0x21:
10813: return(pic_read(0, addr));
10814: case 0x40:
10815: case 0x41:
10816: case 0x42:
10817: case 0x43:
10818: return(pit_read(addr & 0x03));
1.1.1.7 root 10819: case 0x60:
10820: return(kbd_read_data());
1.1.1.9 root 10821: case 0x61:
10822: return(system_port);
1.1.1.7 root 10823: case 0x64:
10824: return(kbd_read_status());
1.1 root 10825: case 0x71:
1.1.1.8 root 10826: return(cmos_read(cmos_addr));
1.1 root 10827: case 0x92:
1.1.1.3 root 10828: return((m_a20_mask >> 19) & 2);
1.1 root 10829: case 0xa0:
10830: case 0xa1:
10831: return(pic_read(1, addr));
1.1.1.9 root 10832: case 0x3ba:
10833: case 0x3da:
10834: return(vga_read_status());
1.1 root 10835: default:
10836: // error("inb %4x\n", addr);
10837: break;
10838: }
10839: return(0xff);
10840: }
10841:
10842: UINT16 read_io_word(offs_t addr)
10843: {
10844: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8));
10845: }
10846:
10847: UINT32 read_io_dword(offs_t addr)
10848: {
10849: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8) | (read_io_byte(addr + 2) << 16) | (read_io_byte(addr + 3) << 24));
10850: }
10851:
10852: void write_io_byte(offs_t addr, UINT8 val)
10853: {
10854: switch(addr) {
10855: case 0x20:
10856: case 0x21:
10857: pic_write(0, addr, val);
10858: break;
10859: case 0x40:
10860: case 0x41:
10861: case 0x42:
10862: case 0x43:
10863: pit_write(addr & 0x03, val);
10864: break;
1.1.1.7 root 10865: case 0x60:
10866: kbd_write_data(val);
10867: break;
1.1.1.9 root 10868: case 0x61:
10869: if((system_port & 3) != 3 && (val & 3) == 3) {
10870: // beep on
10871: // MessageBeep(-1);
10872: } else if((system_port & 3) == 3 && (val & 3) != 3) {
10873: // beep off
10874: }
10875: system_port = val;
10876: break;
1.1 root 10877: case 0x64:
1.1.1.7 root 10878: kbd_write_command(val);
1.1 root 10879: break;
10880: case 0x70:
10881: cmos_addr = val;
10882: break;
10883: case 0x71:
1.1.1.8 root 10884: cmos_write(cmos_addr, val);
1.1 root 10885: break;
10886: case 0x92:
1.1.1.7 root 10887: i386_set_a20_line((val >> 1) & 1);
1.1 root 10888: break;
10889: case 0xa0:
10890: case 0xa1:
10891: pic_write(1, addr, val);
10892: break;
10893: default:
10894: // error("outb %4x,%2x\n", addr, val);
10895: break;
10896: }
10897: }
10898:
10899: void write_io_word(offs_t addr, UINT16 val)
10900: {
10901: write_io_byte(addr + 0, (val >> 0) & 0xff);
10902: write_io_byte(addr + 1, (val >> 8) & 0xff);
10903: }
10904:
10905: void write_io_dword(offs_t addr, UINT32 val)
10906: {
10907: write_io_byte(addr + 0, (val >> 0) & 0xff);
10908: write_io_byte(addr + 1, (val >> 8) & 0xff);
10909: write_io_byte(addr + 2, (val >> 16) & 0xff);
10910: write_io_byte(addr + 3, (val >> 24) & 0xff);
10911: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.