|
|
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;
1.1.1.23! root 327: WriteConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), scr_char, vram_length_char, vram_coord_char, &num);
1.1.1.14 root 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;
1.1.1.23! root 336: WriteConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE), scr_attr, vram_length_attr, vram_coord_attr, &num);
1.1.1.14 root 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;
1.1.1.23! root 380: WriteConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), scr_char, 1, co, &num);
1.1.1.14 root 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;
1.1.1.23! root 412: WriteConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE), scr_attr, 1, co, &num);
1.1.1.14 root 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;
1.1.1.23! root 488: SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), co);
1.1.1.14 root 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.1.23! root 819: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 820: CONSOLE_SCREEN_BUFFER_INFO csbi;
1.1.1.14 root 821: CONSOLE_CURSOR_INFO ci;
1.1.1.23! root 822:
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) {
1.1.1.23! root 889: hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.12 root 890: if(restore_console_on_exit) {
1.1.1.14 root 891: // window can't be bigger than buffer,
892: // buffer can't be smaller than window,
893: // so make a tiny window,
894: // set the required buffer,
895: // then set the required window
896: SMALL_RECT rect;
897: SET_RECT(rect, 0, csbi.srWindow.Top, 0, csbi.srWindow.Top);
898: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1.1.1.12 root 899: SetConsoleScreenBufferSize(hStdout, csbi.dwSize);
1.1.1.14 root 900: SET_RECT(rect, 0, 0, csbi.srWindow.Right - csbi.srWindow.Left, csbi.srWindow.Bottom - csbi.srWindow.Top);
1.1.1.12 root 901: SetConsoleWindowInfo(hStdout, TRUE, &rect);
902: }
1.1.1.14 root 903: // hStdout (and all handles) will close in msdos_finish()...
904: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
905: SetConsoleCursorInfo(hStdout, &ci);
1.1.1.12 root 906: }
1.1 root 907: msdos_finish();
1.1.1.14 root 908:
1.1.1.8 root 909: timeEndPeriod(caps.wPeriodMin);
1.1.1.14 root 910: SetConsoleCtrlHandler(ctrl_handler, FALSE);
1.1 root 911: }
912:
1.1.1.10 root 913: hardware_finish();
914:
1.1 root 915: delete key_buf_char;
916: delete key_buf_scan;
917:
1.1.1.12 root 918: // SetConsoleTextAttribute(hStdout, csbi.wAttributes);
1.1 root 919:
1.1.1.20 root 920: #ifdef _DEBUG
921: _CrtDumpMemoryLeaks();
922: #endif
1.1 root 923: return(retval);
924: }
925:
1.1.1.20 root 926: /* ----------------------------------------------------------------------------
927: console
928: ---------------------------------------------------------------------------- */
929:
1.1.1.14 root 930: void change_console_size(int width, int height)
1.1.1.12 root 931: {
1.1.1.23! root 932: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.12 root 933: CONSOLE_SCREEN_BUFFER_INFO csbi;
934: SMALL_RECT rect;
935: COORD co;
936:
937: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 938: if(csbi.srWindow.Top != 0 || csbi.dwCursorPosition.Y > height - 1) {
939: if(csbi.srWindow.Right - csbi.srWindow.Left + 1 == width && csbi.srWindow.Bottom - csbi.srWindow.Top + 1 == height) {
940: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &csbi.srWindow);
941: SET_RECT(rect, 0, 0, width - 1, height - 1);
942: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
943: } else if(csbi.dwCursorPosition.Y > height - 1) {
944: SET_RECT(rect, 0, csbi.dwCursorPosition.Y - (height - 1), width - 1, csbi.dwCursorPosition.Y);
945: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
946: SET_RECT(rect, 0, 0, width - 1, height - 1);
947: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1.1.12 root 948: }
949: }
1.1.1.14 root 950: if(csbi.dwCursorPosition.Y > height - 1) {
1.1.1.12 root 951: co.X = csbi.dwCursorPosition.X;
1.1.1.14 root 952: co.Y = min(height - 1, csbi.dwCursorPosition.Y - csbi.srWindow.Top);
1.1.1.12 root 953: SetConsoleCursorPosition(hStdout, co);
954: cursor_moved = true;
955: }
1.1.1.14 root 956:
957: // window can't be bigger than buffer,
958: // buffer can't be smaller than window,
959: // so make a tiny window,
960: // set the required buffer,
961: // then set the required window
962: SET_RECT(rect, 0, csbi.srWindow.Top, 0, csbi.srWindow.Top);
1.1.1.12 root 963: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1.1.1.14 root 964: co.X = width;
965: co.Y = height;
1.1.1.12 root 966: SetConsoleScreenBufferSize(hStdout, co);
1.1.1.14 root 967: SET_RECT(rect, 0, 0, width - 1, height - 1);
968: SetConsoleWindowInfo(hStdout, TRUE, &rect);
969:
970: scr_width = scr_buf_size.X = width;
971: scr_height = scr_buf_size.Y = height;
972: scr_top = 0;
973:
974: clear_scr_buffer(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
975:
976: int regen = min(scr_width * scr_height * 2, 0x8000);
1.1.1.15 root 977: text_vram_end_address = text_vram_top_address + regen;
978: shadow_buffer_end_address = shadow_buffer_top_address + regen;
979:
1.1.1.14 root 980: if(regen > 0x4000) {
981: regen = 0x8000;
982: vram_pages = 1;
983: } else if(regen > 0x2000) {
984: regen = 0x4000;
985: vram_pages = 2;
986: } else if(regen > 0x1000) {
987: regen = 0x2000;
988: vram_pages = 4;
989: } else {
990: regen = 0x1000;
991: vram_pages = 8;
992: }
1.1.1.15 root 993: *(UINT16 *)(mem + 0x44a) = scr_width;
994: *(UINT16 *)(mem + 0x44c) = regen;
995: *(UINT8 *)(mem + 0x484) = scr_height - 1;
996:
997: restore_console_on_exit = true;
1.1.1.14 root 998: }
999:
1000: void clear_scr_buffer(WORD attr)
1001: {
1002: for(int y = 0; y < scr_height; y++) {
1003: for(int x = 0; x < scr_width; x++) {
1004: SCR_BUF(y,x).Char.AsciiChar = ' ';
1005: SCR_BUF(y,x).Attributes = attr;
1006: }
1007: }
1.1.1.12 root 1008: }
1009:
1.1.1.14 root 1010: bool update_key_buffer_tmp()
1.1 root 1011: {
1.1.1.23! root 1012: HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
1.1.1.8 root 1013: DWORD dwNumberOfEvents = 0;
1.1 root 1014: DWORD dwRead;
1015: INPUT_RECORD ir[16];
1016:
1.1.1.8 root 1017: if(GetNumberOfConsoleInputEvents(hStdin, &dwNumberOfEvents) && dwNumberOfEvents != 0) {
1018: if(ReadConsoleInputA(hStdin, ir, 16, &dwRead)) {
1019: for(int i = 0; i < dwRead; i++) {
1020: if((ir[i].EventType & KEY_EVENT) && ir[i].Event.KeyEvent.bKeyDown) {
1.1.1.14 root 1021: UINT8 chr = ir[i].Event.KeyEvent.uChar.AsciiChar;
1022: UINT8 scn = ir[i].Event.KeyEvent.wVirtualScanCode & 0xff;
1023: if(chr == 0) {
1024: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
1025: if(scn >= 0x3b && scn <= 0x44) {
1026: scn += 0x68 - 0x3b; // F1 to F10
1027: } else if(scn == 0x57 || scn == 0x58) {
1028: scn += 0x8b - 0x57; // F11 & F12
1029: } else if(scn >= 0x47 && scn <= 0x53) {
1030: scn += 0x97 - 0x47; // edit/arrow clusters
1031: } else if(scn == 0x35) {
1032: scn = 0xa4; // keypad /
1033: }
1034: } else if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
1035: if(scn == 0x07) {
1036: chr = 0x1e; // Ctrl+^
1037: } else if(scn == 0x0c) {
1038: chr = 0x1f; // Ctrl+_
1039: } else if(scn >= 0x35 && scn <= 0x58) {
1040: static const UINT8 ctrl_map[] = {
1041: 0x95, // keypad /
1042: 0,
1043: 0x96, // keypad *
1044: 0, 0, 0,
1045: 0x5e, // F1
1046: 0x5f, // F2
1047: 0x60, // F3
1048: 0x61, // F4
1049: 0x62, // F5
1050: 0x63, // F6
1051: 0x64, // F7
1052: 0x65, // F8
1053: 0x66, // F9
1054: 0x67, // F10
1055: 0,
1056: 0,
1057: 0x77, // Home
1058: 0x8d, // Up
1059: 0x84, // PgUp
1060: 0x8e, // keypad -
1061: 0x73, // Left
1062: 0x8f, // keypad center
1063: 0x74, // Right
1064: 0x90, // keyapd +
1065: 0x75, // End
1066: 0x91, // Down
1067: 0x76, // PgDn
1068: 0x92, // Insert
1069: 0x93, // Delete
1070: 0, 0, 0,
1071: 0x89, // F11
1072: 0x8a, // F12
1073: };
1074: scn = ctrl_map[scn - 0x35];
1075: }
1076: } else if(ir[i].Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
1077: if(scn >= 0x3b && scn <= 0x44) {
1078: scn += 0x54 - 0x3b; // F1 to F10
1079: } else if(scn == 0x57 || scn == 0x58) {
1080: scn += 0x87 - 0x57; // F11 & F12
1081: }
1082: } else if(scn == 0x57 || scn == 0x58) {
1083: scn += 0x85 - 0x57;
1084: }
1085: // ignore shift, ctrl, alt, win and menu keys
1086: if(scn != 0x1d && scn != 0x2a && scn != 0x36 && scn != 0x38 && (scn < 0x5b || scn > 0x5e)) {
1087: if(chr == 0) {
1088: key_buf_char->write(0x00);
1089: key_buf_scan->write(ir[i].Event.KeyEvent.dwControlKeyState & ENHANCED_KEY ? 0xe0 : 0x00);
1090: }
1091: key_buf_char->write(chr);
1092: key_buf_scan->write(scn);
1.1.1.8 root 1093: }
1094: } else {
1.1.1.14 root 1095: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
1096: chr = 0;
1097: if(scn >= 0x02 && scn <= 0x0e) {
1098: scn += 0x78 - 0x02; // 1 to 0 - =
1099: }
1100: }
1101: key_buf_char->write(chr);
1102: key_buf_scan->write(scn);
1103: }
1104: }
1105: }
1106: for(int i = dwRead; --i >= 0;) {
1107: if((ir[i].EventType & KEY_EVENT)) {
1108: kbd_data = ir[i].Event.KeyEvent.wVirtualScanCode & 0x7f;
1109: if(!ir[i].Event.KeyEvent.bKeyDown) {
1110: kbd_data |= 0x80;
1.1 root 1111: }
1.1.1.14 root 1112: return true;
1.1 root 1113: }
1114: }
1115: }
1116: }
1.1.1.14 root 1117: return false;
1.1.1.8 root 1118: }
1119:
1.1.1.14 root 1120: bool update_key_buffer()
1.1.1.8 root 1121: {
1122: int prev_count = key_buf_char->count();
1.1.1.14 root 1123: bool input = update_key_buffer_tmp();
1.1.1.8 root 1124: key_input += key_buf_char->count() - prev_count;
1.1.1.14 root 1125: return(input || key_buf_char->count() != 0);
1.1 root 1126: }
1127:
1.1.1.8 root 1128: int check_key_input()
1129: {
1130: if(key_input == 0) {
1131: int prev_count = key_buf_char->count();
1.1.1.14 root 1132: bool input = update_key_buffer_tmp();
1.1.1.8 root 1133: key_input = key_buf_char->count() - prev_count;
1.1.1.14 root 1134: if(key_input == 0 && input) {
1135: key_input = 1;
1136: }
1.1.1.8 root 1137: }
1138: int val = key_input;
1139: key_input = 0;
1140: return(val);
1141: }
1142:
1.1.1.20 root 1143: /* ----------------------------------------------------------------------------
1144: MS-DOS virtual machine
1145: ---------------------------------------------------------------------------- */
1146:
1147: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg);
1148: int msdos_psp_get_file_table(int fd, int psp_seg);
1149: void msdos_putch(UINT8 data);
1150:
1.1 root 1151: // process info
1152:
1153: process_t *msdos_process_info_create(UINT16 psp_seg)
1154: {
1155: for(int i = 0; i < MAX_PROCESS; i++) {
1156: if(process[i].psp == 0 || process[i].psp == psp_seg) {
1157: memset(&process[i], 0, sizeof(process_t));
1158: process[i].psp = psp_seg;
1159: return(&process[i]);
1160: }
1161: }
1162: fatalerror("too many processes\n");
1163: return(NULL);
1164: }
1165:
1166: process_t *msdos_process_info_get(UINT16 psp_seg)
1167: {
1168: for(int i = 0; i < MAX_PROCESS; i++) {
1169: if(process[i].psp == psp_seg) {
1170: return(&process[i]);
1171: }
1172: }
1173: fatalerror("invalid psp address\n");
1174: return(NULL);
1175: }
1176:
1.1.1.23! root 1177: void msdos_sda_update(int psp_seg)
! 1178: {
! 1179: sda_t *sda = (sda_t *)(mem + SDA_TOP);
! 1180:
! 1181: for(int i = 0; i < MAX_PROCESS; i++) {
! 1182: if(process[i].psp == psp_seg) {
! 1183: sda->switchar = process[i].switchar;
! 1184: sda->current_dta.w.l = process[i].dta.w.l;
! 1185: sda->current_dta.w.h = process[i].dta.w.h;
! 1186: sda->current_psp = process[i].psp;
! 1187: break;
! 1188: }
! 1189: }
! 1190: sda->malloc_strategy = malloc_strategy;
! 1191: sda->return_code = retval;
! 1192: sda->current_drive = _getdrive();
! 1193: }
! 1194:
1.1.1.13 root 1195: // dta info
1196:
1197: void msdos_dta_info_init()
1198: {
1.1.1.14 root 1199: for(int i = 0; i < MAX_DTAINFO; i++) {
1.1.1.13 root 1200: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
1201: }
1202: }
1203:
1204: dtainfo_t *msdos_dta_info_get(UINT16 psp_seg, UINT32 dta_laddr)
1205: {
1206: dtainfo_t *free_dta = NULL;
1.1.1.14 root 1207: for(int i = 0; i < MAX_DTAINFO; i++) {
1208: if(dtalist[i].find_handle == INVALID_HANDLE_VALUE) {
1209: if(free_dta == NULL) {
1.1.1.13 root 1210: free_dta = &dtalist[i];
1211: }
1.1.1.14 root 1212: } else if(dta_laddr < LFN_DTA_LADDR && dtalist[i].dta == dta_laddr) {
1.1.1.13 root 1213: return(&dtalist[i]);
1214: }
1215: }
1.1.1.14 root 1216: if(free_dta) {
1.1.1.13 root 1217: free_dta->psp = psp_seg;
1218: free_dta->dta = dta_laddr;
1219: return(free_dta);
1220: }
1221: fatalerror("too many dta\n");
1222: return(NULL);
1223: }
1224:
1225: void msdos_dta_info_free(UINT16 psp_seg)
1226: {
1.1.1.14 root 1227: for(int i = 0; i < MAX_DTAINFO; i++) {
1228: if(dtalist[i].psp == psp_seg && dtalist[i].find_handle != INVALID_HANDLE_VALUE) {
1.1.1.13 root 1229: FindClose(dtalist[i].find_handle);
1230: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
1231: }
1232: }
1233: }
1234:
1.1 root 1235: void msdos_cds_update(int drv)
1236: {
1237: cds_t *cds = (cds_t *)(mem + CDS_TOP);
1238:
1239: memset(mem + CDS_TOP, 0, CDS_SIZE);
1240: sprintf(cds->path_name, "%c:\\", 'A' + drv);
1241: cds->drive_attrib = 0x4000; // physical drive
1242: cds->physical_drive_number = drv;
1243: }
1244:
1.1.1.17 root 1245: // nls information tables
1246:
1247: // uppercase table (func 6502h)
1248: void msdos_upper_table_update()
1249: {
1250: *(UINT16 *)(mem + UPPERTABLE_TOP) = 0x80;
1.1.1.22 root 1251: for(unsigned i = 0; i < 0x80; ++i) {
1.1.1.17 root 1252: UINT8 c[4];
1253: *(UINT32 *)c = 0; // reset internal conversion state
1254: CharUpperBuffA((LPSTR)c, 4); // (workaround for MBCS codepage)
1255: c[0] = 0x80 + i;
1256: DWORD rc = CharUpperBuffA((LPSTR)c, 1);
1257: mem[UPPERTABLE_TOP + 2 + i] = (rc == 1 && c[0]) ? c[0] : 0x80 + i;
1258: }
1259: }
1260:
1.1.1.23! root 1261: // lowercase table (func 6503h)
! 1262: void msdos_lower_table_update()
! 1263: {
! 1264: *(UINT16 *)(mem + LOWERTABLE_TOP) = 0x80;
! 1265: for(unsigned i = 0; i < 0x80; ++i) {
! 1266: UINT8 c[4];
! 1267: *(UINT32 *)c = 0; // reset internal conversion state
! 1268: CharLowerBuffA((LPSTR)c, 4); // (workaround for MBCS codepage)
! 1269: c[0] = 0x80 + i;
! 1270: DWORD rc = CharLowerBuffA((LPSTR)c, 1);
! 1271: mem[LOWERTABLE_TOP + 2 + i] = (rc == 1 && c[0]) ? c[0] : 0x80 + i;
! 1272: }
! 1273: }
! 1274:
1.1.1.17 root 1275: // filename uppercase table (func 6504h)
1276: void msdos_filename_upper_table_init()
1277: {
1278: // depended on (file)system, not on active codepage
1279: // temporary solution: just filling data
1280: *(UINT16 *)(mem + FILENAME_UPPERTABLE_TOP) = 0x80;
1.1.1.22 root 1281: for(unsigned i = 0; i < 0x80; ++i) {
1.1.1.17 root 1282: mem[FILENAME_UPPERTABLE_TOP + 2 + i] = 0x80 + i;
1283: }
1284: }
1285:
1286: // filaname terminator table (func 6505h)
1287: void msdos_filename_terminator_table_init()
1288: {
1289: const char illegal_chars[] = ".\"/\\[]:|<>+=;,"; // for standard MS-DOS fs.
1290: UINT8 *data = mem + FILENAME_TERMINATOR_TOP;
1291:
1292: data[2] = 1; // marker? (permissible character value)
1293: data[3] = 0x00; // 00h...FFh
1294: data[4] = 0xff;
1295: data[5] = 0; // marker? (excluded character)
1296: data[6] = 0x00; // 00h...20h
1297: data[7] = 0x20;
1298: data[8] = 2; // marker? (illegal characters for filename)
1299: data[9] = (UINT8)strlen(illegal_chars);
1300: memcpy(data + 10, illegal_chars, data[9]);
1301:
1302: // total length
1303: *(UINT16 *)data = (10 - 2) + data[9];
1304: }
1305:
1306: // collating table (func 6506h)
1307: void msdos_collating_table_update()
1308: {
1309: // temporary solution: just filling data
1310: *(UINT16 *)(mem + COLLATING_TABLE_TOP) = 0x100;
1.1.1.22 root 1311: for(unsigned i = 0; i < 256; ++i) {
1.1.1.17 root 1312: mem[COLLATING_TABLE_TOP + 2 + i] = i;
1313: }
1314: }
1315:
1.1 root 1316: // dbcs
1317:
1318: void msdos_dbcs_table_update()
1319: {
1320: UINT8 dbcs_data[DBCS_SIZE];
1321: memset(dbcs_data, 0, sizeof(dbcs_data));
1322:
1323: CPINFO info;
1324: GetCPInfo(active_code_page, &info);
1325:
1326: if(info.MaxCharSize != 1) {
1327: for(int i = 0;; i += 2) {
1328: UINT8 lo = info.LeadByte[i + 0];
1329: UINT8 hi = info.LeadByte[i + 1];
1330: dbcs_data[2 + i + 0] = lo;
1331: dbcs_data[2 + i + 1] = hi;
1332: if(lo == 0 && hi == 0) {
1333: dbcs_data[0] = i + 2;
1334: break;
1335: }
1336: }
1337: } else {
1338: dbcs_data[0] = 2; // ???
1339: }
1340: memcpy(mem + DBCS_TOP, dbcs_data, sizeof(dbcs_data));
1341: }
1342:
1.1.1.17 root 1343: void msdos_dbcs_table_finish()
1344: {
1345: if(active_code_page != system_code_page) {
1346: _setmbcp(system_code_page);
1347: }
1348: }
1349:
1350: void msdos_nls_tables_init()
1.1 root 1351: {
1352: system_code_page = active_code_page = _getmbcp();
1.1.1.17 root 1353: msdos_upper_table_update();
1.1.1.23! root 1354: msdos_lower_table_update();
1.1.1.17 root 1355: msdos_filename_terminator_table_init();
1356: msdos_filename_upper_table_init();
1357: msdos_collating_table_update();
1.1 root 1358: msdos_dbcs_table_update();
1359: }
1360:
1.1.1.17 root 1361: void msdos_nls_tables_update()
1.1 root 1362: {
1.1.1.17 root 1363: msdos_dbcs_table_update();
1364: msdos_upper_table_update();
1.1.1.23! root 1365: msdos_lower_table_update();
! 1366: // msdos_collating_table_update();
1.1 root 1367: }
1368:
1369: int msdos_lead_byte_check(UINT8 code)
1370: {
1371: UINT8 *dbcs_table = mem + DBCS_TABLE;
1372:
1373: for(int i = 0;; i += 2) {
1374: UINT8 lo = dbcs_table[i + 0];
1375: UINT8 hi = dbcs_table[i + 1];
1376: if(lo == 0 && hi == 0) {
1377: break;
1378: }
1379: if(lo <= code && code <= hi) {
1380: return(1);
1381: }
1382: }
1383: return(0);
1384: }
1385:
1.1.1.20 root 1386: int msdos_ctrl_code_check(UINT8 code)
1387: {
1.1.1.22 root 1388: return (code >= 0x01 && code <= 0x1a && code != 0x07 && code != 0x08 && code != 0x09 && code != 0x0a && code != 0x0d);
1.1.1.20 root 1389: }
1390:
1.1 root 1391: // file control
1392:
1.1.1.14 root 1393: char *msdos_remove_double_quote(char *path)
1394: {
1395: static char tmp[MAX_PATH];
1396:
1397: memset(tmp, 0, sizeof(tmp));
1398: if(strlen(path) >= 2 && path[0] == '"' && path[strlen(path) - 1] == '"') {
1399: memcpy(tmp, path + 1, strlen(path) - 2);
1400: } else {
1401: strcpy(tmp, path);
1402: }
1403: return(tmp);
1404: }
1405:
1406: char *msdos_combine_path(char *dir, const char *file)
1407: {
1408: static char tmp[MAX_PATH];
1409: char *tmp_dir = msdos_remove_double_quote(dir);
1410:
1411: if(strlen(tmp_dir) == 0) {
1412: strcpy(tmp, file);
1413: } else if(tmp_dir[strlen(tmp_dir) - 1] == '\\') {
1414: sprintf(tmp, "%s%s", tmp_dir, file);
1415: } else {
1416: sprintf(tmp, "%s\\%s", tmp_dir, file);
1417: }
1418: return(tmp);
1419: }
1420:
1.1 root 1421: char *msdos_trimmed_path(char *path, int lfn)
1422: {
1423: static char tmp[MAX_PATH];
1424:
1425: if(lfn) {
1426: strcpy(tmp, path);
1427: } else {
1428: // remove space in the path
1429: char *src = path, *dst = tmp;
1430:
1431: while(*src != '\0') {
1432: if(msdos_lead_byte_check(*src)) {
1433: *dst++ = *src++;
1434: *dst++ = *src++;
1435: } else if(*src != ' ') {
1436: *dst++ = *src++;
1437: } else {
1438: src++; // skip space
1439: }
1440: }
1441: *dst = '\0';
1442: }
1.1.1.14 root 1443: if(_stricmp(tmp, "C:\\COMMAND.COM") == 0) {
1444: // redirect C:\COMMAND.COM to comspec_path
1445: strcpy(tmp, comspec_path);
1446: } else if(is_vista_or_later && _access(tmp, 0) != 0) {
1447: // redirect new files (without wildcards) in C:\ to %TEMP%, since C:\ is not usually writable
1448: static int root_drive_protected = -1;
1449: char temp[MAX_PATH], name[MAX_PATH], *name_temp = NULL;
1450: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
1451:
1452: if(GetFullPathName(tmp, MAX_PATH, temp, &name_temp) != 0 &&
1453: name_temp != NULL && strstr(name_temp, "?") == NULL && strstr(name_temp, "*") == NULL) {
1454: strcpy(name, name_temp);
1455: name_temp[0] = '\0';
1456:
1457: if((temp[0] == 'A' + dos_info->boot_drive - 1 || temp[0] == 'a' + dos_info->boot_drive - 1) &&
1458: (temp[1] == ':') && (temp[2] == '\\' || temp[2] == '/') && (temp[3] == '\0')) {
1459: if(root_drive_protected == -1) {
1460: FILE *fp = NULL;
1461:
1462: sprintf(temp, "%c:\\MS-DOS_Player.$$$", 'A' + dos_info->boot_drive - 1);
1463: root_drive_protected = 1;
1464: try {
1465: if((fp = fopen(temp, "w")) != NULL) {
1466: if(fprintf(fp, "TEST") == 4) {
1467: root_drive_protected = 0;
1468: }
1469: }
1470: } catch(...) {
1471: }
1472: if(fp != NULL) {
1473: fclose(fp);
1474: }
1475: if(_access(temp, 0) == 0) {
1476: remove(temp);
1477: }
1478: }
1479: if(root_drive_protected == 1) {
1480: if(GetEnvironmentVariable("TEMP", temp, MAX_PATH) != 0 ||
1481: GetEnvironmentVariable("TMP", temp, MAX_PATH) != 0) {
1482: strcpy(tmp, msdos_combine_path(temp, name));
1483: }
1484: }
1485: }
1486: }
1487: }
1.1 root 1488: return(tmp);
1489: }
1490:
1491: bool match(char *text, char *pattern)
1492: {
1493: //http://www.prefield.com/algorithm/string/wildcard.html
1.1.1.14 root 1494: switch(*pattern) {
1.1 root 1495: case '\0':
1496: return !*text;
1497: case '*':
1.1.1.14 root 1498: return match(text, pattern + 1) || (*text && match(text + 1, pattern));
1.1 root 1499: case '?':
1500: return *text && match(text + 1, pattern + 1);
1501: default:
1502: return (*text == *pattern) && match(text + 1, pattern + 1);
1503: }
1504: }
1505:
1506: bool msdos_match_volume_label(char *path, char *volume)
1507: {
1508: char *p;
1509:
1.1.1.14 root 1510: if(!*volume) {
1511: return false;
1512: } else if((p = my_strchr(path, ':')) != NULL) {
1.1 root 1513: return msdos_match_volume_label(p + 1, volume);
1514: } else if((p = my_strchr(path, '\\')) != NULL) {
1515: return msdos_match_volume_label(p + 1, volume);
1516: } else if((p = my_strchr(path, '.')) != NULL) {
1.1.1.14 root 1517: char tmp[MAX_PATH];
1518: sprintf(tmp, "%.*s%s", (int)(p - path), path, p + 1);
1519: return match(volume, tmp);
1.1 root 1520: } else {
1521: return match(volume, path);
1522: }
1523: }
1524:
1525: char *msdos_fcb_path(fcb_t *fcb)
1526: {
1527: static char tmp[MAX_PATH];
1528: char name[9], ext[4];
1529:
1530: memset(name, 0, sizeof(name));
1531: memcpy(name, fcb->file_name, 8);
1532: strcpy(name, msdos_trimmed_path(name, 0));
1533:
1534: memset(ext, 0, sizeof(ext));
1535: memcpy(ext, fcb->file_name + 8, 3);
1536: strcpy(ext, msdos_trimmed_path(ext, 0));
1537:
1538: if(name[0] == '\0' || strcmp(name, "????????") == 0) {
1539: strcpy(name, "*");
1540: }
1541: if(ext[0] == '\0') {
1542: strcpy(tmp, name);
1543: } else {
1544: if(strcmp(ext, "???") == 0) {
1545: strcpy(ext, "*");
1546: }
1547: sprintf(tmp, "%s.%s", name, ext);
1548: }
1549: return(tmp);
1550: }
1551:
1552: void msdos_set_fcb_path(fcb_t *fcb, char *path)
1553: {
1554: char *ext = my_strchr(path, '.');
1555:
1556: memset(fcb->file_name, 0x20, 8 + 3);
1557: if(ext != NULL && path[0] != '.') {
1558: *ext = '\0';
1559: memcpy(fcb->file_name + 8, ext + 1, strlen(ext + 1));
1560: }
1561: memcpy(fcb->file_name, path, strlen(path));
1562: }
1563:
1564: char *msdos_short_path(char *path)
1565: {
1566: static char tmp[MAX_PATH];
1567:
1568: GetShortPathName(path, tmp, MAX_PATH);
1569: my_strupr(tmp);
1570: return(tmp);
1571: }
1572:
1.1.1.13 root 1573: char *msdos_short_name(WIN32_FIND_DATA *fd)
1574: {
1575: static char tmp[MAX_PATH];
1576:
1.1.1.14 root 1577: if(fd->cAlternateFileName[0]) {
1.1.1.13 root 1578: strcpy(tmp, fd->cAlternateFileName);
1579: } else {
1580: strcpy(tmp, fd->cFileName);
1581: }
1582: my_strupr(tmp);
1583: return(tmp);
1584: }
1585:
1.1 root 1586: char *msdos_short_full_path(char *path)
1587: {
1588: static char tmp[MAX_PATH];
1589: char full[MAX_PATH], *name;
1590:
1.1.1.14 root 1591: // Full works with non-existent files, but Short does not
1.1 root 1592: GetFullPathName(path, MAX_PATH, full, &name);
1.1.1.14 root 1593: *tmp = '\0';
1594: if(GetShortPathName(full, tmp, MAX_PATH) == 0 && name > path) {
1595: name[-1] = '\0';
1596: DWORD len = GetShortPathName(full, tmp, MAX_PATH);
1597: if(len == 0) {
1598: strcpy(tmp, full);
1599: } else {
1600: tmp[len++] = '\\';
1601: strcpy(tmp + len, name);
1602: }
1603: }
1.1 root 1604: my_strupr(tmp);
1605: return(tmp);
1606: }
1607:
1608: char *msdos_short_full_dir(char *path)
1609: {
1610: static char tmp[MAX_PATH];
1611: char full[MAX_PATH], *name;
1612:
1613: GetFullPathName(path, MAX_PATH, full, &name);
1614: name[-1] = '\0';
1615: GetShortPathName(full, tmp, MAX_PATH);
1616: my_strupr(tmp);
1617: return(tmp);
1618: }
1619:
1620: char *msdos_local_file_path(char *path, int lfn)
1621: {
1622: char *trimmed = msdos_trimmed_path(path, lfn);
1.1.1.14 root 1623: #if 0
1624: // I have forgotten the reason of this routine... :-(
1.1 root 1625: if(_access(trimmed, 0) != 0) {
1626: process_t *process = msdos_process_info_get(current_psp);
1627: static char tmp[MAX_PATH];
1628:
1629: sprintf(tmp, "%s\\%s", process->module_dir, trimmed);
1630: if(_access(tmp, 0) == 0) {
1631: return(tmp);
1632: }
1633: }
1.1.1.14 root 1634: #endif
1.1 root 1635: return(trimmed);
1636: }
1637:
1.1.1.11 root 1638: bool msdos_is_con_path(char *path)
1639: {
1640: char full[MAX_PATH], *name;
1641:
1642: GetFullPathName(path, MAX_PATH, full, &name);
1643: return(_stricmp(full, "\\\\.\\CON") == 0);
1644: }
1645:
1.1.1.14 root 1646: bool msdos_is_nul_path(char *path)
1.1.1.8 root 1647: {
1.1.1.14 root 1648: char full[MAX_PATH], *name;
1.1.1.8 root 1649:
1.1.1.14 root 1650: GetFullPathName(path, MAX_PATH, full, &name);
1651: return(_stricmp(full, "\\\\.\\NUL") == 0);
1.1.1.8 root 1652: }
1653:
1.1.1.9 root 1654: char *msdos_search_command_com(char *command_path, char *env_path)
1655: {
1656: static char tmp[MAX_PATH];
1657: char path[MAX_PATH], *file_name;
1658:
1659: if(GetFullPathName(command_path, MAX_PATH, tmp, &file_name) != 0) {
1660: sprintf(file_name, "COMMAND.COM");
1661: if(_access(tmp, 0) == 0) {
1662: return(tmp);
1663: }
1664: }
1665: if(GetModuleFileName(NULL, path, MAX_PATH) != 0 && GetFullPathName(path, MAX_PATH, tmp, &file_name) != 0) {
1666: sprintf(file_name, "COMMAND.COM");
1667: if(_access(tmp, 0) == 0) {
1668: return(tmp);
1669: }
1670: }
1671: if(GetFullPathName("COMMAND.COM", MAX_PATH, tmp, &file_name) != 0) {
1672: if(_access(tmp, 0) == 0) {
1673: return(tmp);
1674: }
1675: }
1676: char *token = my_strtok(env_path, ";");
1677: while(token != NULL) {
1.1.1.14 root 1678: if(strlen(token) != 0 && token[0] != '%') {
1.1.1.9 root 1679: strcpy(tmp, msdos_combine_path(token, "COMMAND.COM"));
1680: if(_access(tmp, 0) == 0) {
1681: return(tmp);
1682: }
1683: }
1684: token = my_strtok(NULL, ";");
1685: }
1686: return(NULL);
1687: }
1688:
1.1.1.14 root 1689: int msdos_drive_number(const char *path)
1.1 root 1690: {
1691: char tmp[MAX_PATH], *name;
1692:
1693: GetFullPathName(path, MAX_PATH, tmp, &name);
1694: if(tmp[0] >= 'a' && tmp[0] <= 'z') {
1695: return(tmp[0] - 'a');
1696: } else {
1697: return(tmp[0] - 'A');
1698: }
1699: }
1700:
1701: char *msdos_volume_label(char *path)
1702: {
1703: static char tmp[MAX_PATH];
1704: char volume[] = "A:\\";
1705:
1706: if(path[1] == ':') {
1707: volume[0] = path[0];
1708: } else {
1709: volume[0] = 'A' + _getdrive() - 1;
1710: }
1711: if(!GetVolumeInformation(volume, tmp, MAX_PATH, NULL, NULL, NULL, NULL, 0)) {
1712: memset(tmp, 0, sizeof(tmp));
1713: }
1714: return(tmp);
1715: }
1716:
1717: char *msdos_short_volume_label(char *label)
1718: {
1719: static char tmp[(8 + 1 + 3) + 1];
1720: char *src = label;
1721: int remain = strlen(label);
1722: char *dst_n = tmp;
1723: char *dst_e = tmp + 9;
1724:
1725: strcpy(tmp, " . ");
1726: for(int i = 0; i < 8 && remain > 0; i++) {
1727: if(msdos_lead_byte_check(*src)) {
1728: if(++i == 8) {
1729: break;
1730: }
1731: *dst_n++ = *src++;
1732: remain--;
1733: }
1734: *dst_n++ = *src++;
1735: remain--;
1736: }
1737: if(remain > 0) {
1738: for(int i = 0; i < 3 && remain > 0; i++) {
1739: if(msdos_lead_byte_check(*src)) {
1740: if(++i == 3) {
1741: break;
1742: }
1743: *dst_e++ = *src++;
1744: remain--;
1745: }
1746: *dst_e++ = *src++;
1747: remain--;
1748: }
1749: *dst_e = '\0';
1750: } else {
1751: *dst_n = '\0';
1752: }
1753: my_strupr(tmp);
1754: return(tmp);
1755: }
1756:
1.1.1.13 root 1757: errno_t msdos_maperr(unsigned long oserrno)
1758: {
1759: _doserrno = oserrno;
1.1.1.14 root 1760: switch(oserrno) {
1.1.1.13 root 1761: case ERROR_FILE_NOT_FOUND: // 2
1762: case ERROR_PATH_NOT_FOUND: // 3
1763: case ERROR_INVALID_DRIVE: // 15
1764: case ERROR_NO_MORE_FILES: // 18
1765: case ERROR_BAD_NETPATH: // 53
1766: case ERROR_BAD_NET_NAME: // 67
1767: case ERROR_BAD_PATHNAME: // 161
1768: case ERROR_FILENAME_EXCED_RANGE: // 206
1769: return ENOENT;
1770: case ERROR_TOO_MANY_OPEN_FILES: // 4
1771: return EMFILE;
1772: case ERROR_ACCESS_DENIED: // 5
1773: case ERROR_CURRENT_DIRECTORY: // 16
1774: case ERROR_NETWORK_ACCESS_DENIED: // 65
1775: case ERROR_CANNOT_MAKE: // 82
1776: case ERROR_FAIL_I24: // 83
1777: case ERROR_DRIVE_LOCKED: // 108
1778: case ERROR_SEEK_ON_DEVICE: // 132
1779: case ERROR_NOT_LOCKED: // 158
1780: case ERROR_LOCK_FAILED: // 167
1781: return EACCES;
1782: case ERROR_INVALID_HANDLE: // 6
1783: case ERROR_INVALID_TARGET_HANDLE: // 114
1784: case ERROR_DIRECT_ACCESS_HANDLE: // 130
1785: return EBADF;
1786: case ERROR_ARENA_TRASHED: // 7
1787: case ERROR_NOT_ENOUGH_MEMORY: // 8
1788: case ERROR_INVALID_BLOCK: // 9
1789: case ERROR_NOT_ENOUGH_QUOTA: // 1816
1790: return ENOMEM;
1791: case ERROR_BAD_ENVIRONMENT: // 10
1792: return E2BIG;
1793: case ERROR_BAD_FORMAT: // 11
1794: return ENOEXEC;
1795: case ERROR_NOT_SAME_DEVICE: // 17
1796: return EXDEV;
1797: case ERROR_FILE_EXISTS: // 80
1798: case ERROR_ALREADY_EXISTS: // 183
1799: return EEXIST;
1800: case ERROR_NO_PROC_SLOTS: // 89
1801: case ERROR_MAX_THRDS_REACHED: // 164
1802: case ERROR_NESTING_NOT_ALLOWED: // 215
1803: return EAGAIN;
1804: case ERROR_BROKEN_PIPE: // 109
1805: return EPIPE;
1806: case ERROR_DISK_FULL: // 112
1807: return ENOSPC;
1808: case ERROR_WAIT_NO_CHILDREN: // 128
1809: case ERROR_CHILD_NOT_COMPLETE: // 129
1810: return ECHILD;
1811: case ERROR_DIR_NOT_EMPTY: // 145
1812: return ENOTEMPTY;
1813: }
1.1.1.14 root 1814: if(oserrno >= ERROR_WRITE_PROTECT /* 19 */ &&
1.1.1.13 root 1815: oserrno <= ERROR_SHARING_BUFFER_EXCEEDED /* 36 */) {
1816: return EACCES;
1817: }
1.1.1.14 root 1818: if(oserrno >= ERROR_INVALID_STARTING_CODESEG /* 188 */ &&
1.1.1.13 root 1819: oserrno <= ERROR_INFLOOP_IN_RELOC_CHAIN /* 202 */) {
1820: return ENOEXEC;
1821: }
1822: return EINVAL;
1823: }
1824:
1825: int msdos_open(const char *filename, int oflag)
1826: {
1.1.1.14 root 1827: if((oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) != _O_RDONLY) {
1.1.1.13 root 1828: return _open(filename, oflag);
1829: }
1.1.1.14 root 1830:
1831: SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, !(oflag & _O_NOINHERIT) };
1.1.1.13 root 1832: DWORD disposition;
1.1.1.14 root 1833: switch(oflag & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
1834: default:
1.1.1.13 root 1835: case _O_EXCL:
1836: disposition = OPEN_EXISTING;
1837: break;
1838: case _O_CREAT:
1839: disposition = OPEN_ALWAYS;
1840: break;
1841: case _O_CREAT | _O_EXCL:
1842: case _O_CREAT | _O_TRUNC | _O_EXCL:
1843: disposition = CREATE_NEW;
1844: break;
1845: case _O_TRUNC:
1846: case _O_TRUNC | _O_EXCL:
1847: disposition = TRUNCATE_EXISTING;
1848: break;
1849: case _O_CREAT | _O_TRUNC:
1850: disposition = CREATE_ALWAYS;
1851: break;
1852: }
1.1.1.14 root 1853:
1.1.1.13 root 1854: HANDLE h = CreateFile(filename, GENERIC_READ | FILE_WRITE_ATTRIBUTES,
1855: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
1856: FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.14 root 1857: if(h == INVALID_HANDLE_VALUE) {
1.1.1.13 root 1858: // FILE_WRITE_ATTRIBUTES may not be granted for standard users.
1859: // Retry without FILE_WRITE_ATTRIBUTES.
1860: h = CreateFile(filename, GENERIC_READ,
1861: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
1862: FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.14 root 1863: if(h == INVALID_HANDLE_VALUE) {
1.1.1.13 root 1864: errno = msdos_maperr(GetLastError());
1865: return -1;
1866: }
1867: }
1.1.1.14 root 1868:
1.1.1.13 root 1869: int fd = _open_osfhandle((intptr_t) h, oflag);
1.1.1.14 root 1870: if(fd == -1) {
1.1.1.13 root 1871: CloseHandle(h);
1872: }
1873: return fd;
1874: }
1875:
1.1.1.14 root 1876: void msdos_file_handler_open(int fd, const char *path, int atty, int mode, UINT16 info, UINT16 psp_seg)
1.1 root 1877: {
1878: static int id = 0;
1879: char full[MAX_PATH], *name;
1880:
1881: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1882: strcpy(file_handler[fd].path, full);
1883: } else {
1884: strcpy(file_handler[fd].path, path);
1885: }
1.1.1.14 root 1886: // isatty makes no distinction between CON & NUL
1887: // GetFileSize fails on CON, succeeds on NUL
1888: if(atty && (info != 0x80d3 || GetFileSize((HANDLE)_get_osfhandle(fd), NULL) == 0)) {
1889: info = 0x8084;
1890: atty = 0;
1891: } else if(!atty && info == 0x80d3) {
1892: info = msdos_drive_number(".");
1893: }
1.1 root 1894: file_handler[fd].valid = 1;
1895: file_handler[fd].id = id++; // dummy id for int 21h ax=71a6h
1896: file_handler[fd].atty = atty;
1897: file_handler[fd].mode = mode;
1898: file_handler[fd].info = info;
1899: file_handler[fd].psp = psp_seg;
1.1.1.21 root 1900:
1901: // init system file table
1902: if(fd < 20) {
1903: UINT8 *sft = mem + SFT_TOP + 6 + 0x3b * fd;
1904:
1905: memset(sft, 0, 0x3b);
1906:
1907: *(UINT16 *)(sft + 0x00) = 1;
1908: *(UINT16 *)(sft + 0x02) = file_handler[fd].mode;
1909: *(UINT8 *)(sft + 0x04) = GetFileAttributes(file_handler[fd].path) & 0xff;
1910: *(UINT16 *)(sft + 0x05) = file_handler[fd].info & 0xff;
1911:
1912: if(!(file_handler[fd].info & 0x80)) {
1913: *(UINT16 *)(sft + 0x07) = sizeof(dpb_t) * (file_handler[fd].info & 0x1f);
1914: *(UINT16 *)(sft + 0x09) = DPB_TOP >> 4;
1915:
1916: FILETIME time, local;
1917: HANDLE hHandle;
1918: WORD dos_date = 0, dos_time = 0;
1919: DWORD file_size = 0;
1920: if((hHandle = (HANDLE)_get_osfhandle(fd)) != INVALID_HANDLE_VALUE) {
1921: if(GetFileTime(hHandle, NULL, NULL, &time)) {
1922: FileTimeToLocalFileTime(&time, &local);
1923: FileTimeToDosDateTime(&local, &dos_date, &dos_time);
1924: }
1925: file_size = GetFileSize(hHandle, NULL);
1926: }
1927: *(UINT16 *)(sft + 0x0d) = dos_time;
1928: *(UINT16 *)(sft + 0x0f) = dos_date;
1929: *(UINT32 *)(sft + 0x11) = file_size;
1930: }
1931:
1932: char fname[MAX_PATH] = {0}, ext[MAX_PATH] = {0};
1933: _splitpath(file_handler[fd].path, NULL, NULL, fname, ext);
1934: my_strupr(fname);
1935: my_strupr(ext);
1936: memset(sft + 0x20, 0x20, 11);
1937: memcpy(sft + 0x20, fname, min(strlen(fname), 8));
1938: memcpy(sft + 0x28, ext + 1, min(strlen(ext + 1), 3));
1939:
1940: *(UINT16 *)(sft + 0x31) = psp_seg;
1941: }
1.1 root 1942: }
1943:
1944: void msdos_file_handler_dup(int dst, int src, UINT16 psp_seg)
1945: {
1946: strcpy(file_handler[dst].path, file_handler[src].path);
1947: file_handler[dst].valid = 1;
1948: file_handler[dst].id = file_handler[src].id;
1949: file_handler[dst].atty = file_handler[src].atty;
1950: file_handler[dst].mode = file_handler[src].mode;
1951: file_handler[dst].info = file_handler[src].info;
1952: file_handler[dst].psp = psp_seg;
1953: }
1954:
1.1.1.20 root 1955: void msdos_file_handler_close(int fd)
1.1 root 1956: {
1957: file_handler[fd].valid = 0;
1.1.1.21 root 1958:
1959: if(fd < 20) {
1960: memset(mem + SFT_TOP + 6 + 0x3b * fd, 0, 0x3b);
1961: }
1.1 root 1962: }
1963:
1.1.1.14 root 1964: inline int msdos_file_attribute_create(UINT16 new_attr)
1.1 root 1965: {
1.1.1.14 root 1966: return(new_attr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
1967: FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE |
1968: FILE_ATTRIBUTE_DIRECTORY));
1.1 root 1969: }
1970:
1971: // find file
1972:
1973: int msdos_find_file_check_attribute(int attribute, int allowed_mask, int required_mask)
1974: {
1975: if((allowed_mask & 0x08) && !(attribute & FILE_ATTRIBUTE_DIRECTORY)) {
1976: return(0); // search directory only !!!
1977: } else if(!(allowed_mask & 0x02) && (attribute & FILE_ATTRIBUTE_HIDDEN)) {
1978: return(0);
1979: } else if(!(allowed_mask & 0x04) && (attribute & FILE_ATTRIBUTE_SYSTEM)) {
1980: return(0);
1981: } else if(!(allowed_mask & 0x10) && (attribute & FILE_ATTRIBUTE_DIRECTORY)) {
1982: return(0);
1983: } else if((attribute & required_mask) != required_mask) {
1984: return(0);
1985: } else {
1986: return(1);
1987: }
1988: }
1989:
1.1.1.13 root 1990: int msdos_find_file_has_8dot3name(WIN32_FIND_DATA *fd)
1991: {
1.1.1.14 root 1992: if(fd->cAlternateFileName[0]) {
1.1.1.13 root 1993: return 1;
1994: }
1995: size_t len = strlen(fd->cFileName);
1.1.1.14 root 1996: if(len > 12) {
1.1.1.13 root 1997: return 0;
1998: }
1999: const char *ext = strrchr(fd->cFileName, '.');
1.1.1.14 root 2000: if((ext ? ext - fd->cFileName : len) > 8) {
1.1.1.13 root 2001: return 0;
2002: }
2003: return 1;
2004: }
2005:
1.1 root 2006: void msdos_find_file_conv_local_time(WIN32_FIND_DATA *fd)
2007: {
2008: FILETIME local;
2009:
2010: FileTimeToLocalFileTime(&fd->ftCreationTime, &local);
2011: fd->ftCreationTime.dwLowDateTime = local.dwLowDateTime;
2012: fd->ftCreationTime.dwHighDateTime = local.dwHighDateTime;
2013:
2014: FileTimeToLocalFileTime(&fd->ftLastAccessTime, &local);
2015: fd->ftLastAccessTime.dwLowDateTime = local.dwLowDateTime;
2016: fd->ftLastAccessTime.dwHighDateTime = local.dwHighDateTime;
2017:
2018: FileTimeToLocalFileTime(&fd->ftLastWriteTime, &local);
2019: fd->ftLastWriteTime.dwLowDateTime = local.dwLowDateTime;
2020: fd->ftLastWriteTime.dwHighDateTime = local.dwHighDateTime;
2021: }
2022:
2023: // i/o
2024:
2025: void msdos_stdio_reopen()
2026: {
2027: if(!file_handler[0].valid) {
2028: _dup2(DUP_STDIN, 0);
2029: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
2030: }
2031: if(!file_handler[1].valid) {
2032: _dup2(DUP_STDOUT, 1);
2033: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
2034: }
2035: if(!file_handler[2].valid) {
2036: _dup2(DUP_STDERR, 2);
2037: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
2038: }
1.1.1.21 root 2039: if(!file_handler[3].valid) {
2040: _dup2(DUP_STDAUX, 3);
2041: msdos_file_handler_open(3, "STDAUX", 0, 2, 0x80c0, 0);
2042: }
2043: if(!file_handler[4].valid) {
2044: _dup2(DUP_STDPRN, 4);
2045: msdos_file_handler_open(4, "STDPRN", 0, 1, 0xa8c0, 0);
2046: }
2047: for(int i = 0; i < 5; i++) {
2048: if(msdos_psp_get_file_table(i, current_psp) == 0xff) {
2049: msdos_psp_set_file_table(i, i, current_psp);
2050: }
2051: }
1.1 root 2052: }
2053:
2054: int msdos_kbhit()
2055: {
2056: msdos_stdio_reopen();
2057:
1.1.1.20 root 2058: process_t *process = msdos_process_info_get(current_psp);
2059: int fd = msdos_psp_get_file_table(0, current_psp);
2060:
2061: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 2062: // stdin is redirected to file
1.1.1.20 root 2063: return(eof(fd) == 0);
1.1 root 2064: }
2065:
2066: // check keyboard status
1.1.1.5 root 2067: if(key_buf_char->count() != 0 || key_code != 0) {
1.1 root 2068: return(1);
2069: } else {
2070: return(_kbhit());
2071: }
2072: }
2073:
2074: int msdos_getch_ex(int echo)
2075: {
2076: static char prev = 0;
2077:
2078: msdos_stdio_reopen();
2079:
1.1.1.20 root 2080: process_t *process = msdos_process_info_get(current_psp);
2081: int fd = msdos_psp_get_file_table(0, current_psp);
2082:
2083: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 2084: // stdin is redirected to file
2085: retry:
2086: char data;
1.1.1.20 root 2087: if(_read(fd, &data, 1) == 1) {
1.1 root 2088: char tmp = data;
2089: if(data == 0x0a) {
2090: if(prev == 0x0d) {
2091: goto retry; // CRLF -> skip LF
2092: } else {
2093: data = 0x0d; // LF only -> CR
2094: }
2095: }
2096: prev = tmp;
2097: return(data);
2098: }
2099: return(EOF);
2100: }
2101:
2102: // input from console
1.1.1.5 root 2103: int key_char, key_scan;
2104: if(key_code != 0) {
2105: key_char = (key_code >> 0) & 0xff;
2106: key_scan = (key_code >> 8) & 0xff;
2107: key_code >>= 16;
2108: } else {
1.1.1.14 root 2109: while(key_buf_char->count() == 0 && !m_halted) {
1.1.1.23! root 2110: if(!(fd < process->max_files && file_handler[fd].valid && file_handler[fd].atty && file_mode[file_handler[fd].mode].in)) {
! 2111: // NOTE: stdin is redirected to stderr when we do "type (file) | more" on freedos's command.com
! 2112: if(_kbhit()) {
! 2113: key_buf_char->write(_getch());
! 2114: key_buf_scan->write(0);
! 2115: } else {
! 2116: Sleep(10);
! 2117: }
! 2118: } else {
! 2119: if(!update_key_buffer()) {
! 2120: Sleep(10);
! 2121: }
1.1.1.14 root 2122: }
2123: }
2124: if(m_halted) {
2125: // ctrl-c pressed - insert CR to terminate input loops
2126: key_char = 0x0d;
2127: key_scan = 0;
2128: } else {
2129: key_char = key_buf_char->read();
2130: key_scan = key_buf_scan->read();
1.1.1.5 root 2131: }
1.1 root 2132: }
2133: if(echo && key_char) {
2134: msdos_putch(key_char);
2135: }
2136: return key_char ? key_char : (key_scan != 0xe0) ? key_scan : 0;
2137: }
2138:
2139: inline int msdos_getch()
2140: {
2141: return(msdos_getch_ex(0));
2142: }
2143:
2144: inline int msdos_getche()
2145: {
2146: return(msdos_getch_ex(1));
2147: }
2148:
2149: int msdos_write(int fd, const void *buffer, unsigned int count)
2150: {
2151: static int is_cr = 0;
2152:
2153: if(fd == 1 && !file_handler[1].atty) {
2154: // CR+LF -> LF
2155: UINT8 *buf = (UINT8 *)buffer;
2156: for(unsigned int i = 0; i < count; i++) {
2157: UINT8 data = buf[i];
2158: if(is_cr) {
2159: if(data != 0x0a) {
2160: UINT8 tmp = 0x0d;
2161: _write(1, &tmp, 1);
2162: }
2163: _write(1, &data, 1);
2164: is_cr = 0;
2165: } else if(data == 0x0d) {
2166: is_cr = 1;
2167: } else {
2168: _write(1, &data, 1);
2169: }
2170: }
2171: return(count);
2172: }
1.1.1.14 root 2173: vram_flush();
1.1 root 2174: return(_write(fd, buffer, count));
2175: }
2176:
2177: void msdos_putch(UINT8 data)
2178: {
2179: static int p = 0;
2180: static int is_kanji = 0;
2181: static int is_esc = 0;
2182: static int stored_x;
2183: static int stored_y;
2184: static WORD stored_a;
1.1.1.20 root 2185: static char tmp[64], out[64];
1.1 root 2186:
2187: msdos_stdio_reopen();
2188:
1.1.1.20 root 2189: process_t *process = msdos_process_info_get(current_psp);
2190: int fd = msdos_psp_get_file_table(1, current_psp);
2191:
2192: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 2193: // stdout is redirected to file
1.1.1.20 root 2194: msdos_write(fd, &data, 1);
1.1 root 2195: return;
2196: }
1.1.1.23! root 2197: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 2198:
2199: // output to console
2200: tmp[p++] = data;
2201:
1.1.1.14 root 2202: vram_flush();
2203:
1.1 root 2204: if(is_kanji) {
2205: // kanji character
2206: is_kanji = 0;
2207: } else if(is_esc) {
2208: // escape sequense
2209: if((tmp[1] == ')' || tmp[1] == '(') && p == 3) {
2210: p = is_esc = 0;
2211: } else if(tmp[1] == '=' && p == 4) {
2212: COORD co;
2213: co.X = tmp[3] - 0x20;
1.1.1.14 root 2214: co.Y = tmp[2] - 0x20 + scr_top;
1.1 root 2215: SetConsoleCursorPosition(hStdout, co);
2216: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14 root 2217: mem[0x451 + mem[0x462] * 2] = co.Y - scr_top;
1.1 root 2218: cursor_moved = false;
2219: p = is_esc = 0;
2220: } else if((data >= 'a' && data <= 'z') || (data >= 'A' && data <= 'Z') || data == '*') {
2221: CONSOLE_SCREEN_BUFFER_INFO csbi;
2222: COORD co;
2223: GetConsoleScreenBufferInfo(hStdout, &csbi);
2224: co.X = csbi.dwCursorPosition.X;
2225: co.Y = csbi.dwCursorPosition.Y;
2226: WORD wAttributes = csbi.wAttributes;
2227:
2228: if(tmp[1] == 'D') {
2229: co.Y++;
2230: } else if(tmp[1] == 'E') {
2231: co.X = 0;
2232: co.Y++;
2233: } else if(tmp[1] == 'M') {
2234: co.Y--;
2235: } else if(tmp[1] == '*') {
2236: SMALL_RECT rect;
1.1.1.14 root 2237: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2238: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2239: co.X = 0;
2240: co.Y = csbi.srWindow.Top;
1.1 root 2241: } else if(tmp[1] == '[') {
2242: int param[256], params = 0;
2243: memset(param, 0, sizeof(param));
2244: for(int i = 2; i < p; i++) {
2245: if(tmp[i] >= '0' && tmp[i] <= '9') {
2246: param[params] *= 10;
2247: param[params] += tmp[i] - '0';
2248: } else {
2249: params++;
2250: }
2251: }
2252: if(data == 'A') {
1.1.1.14 root 2253: co.Y -= (params == 0) ? 1 : param[0];
1.1 root 2254: } else if(data == 'B') {
1.1.1.14 root 2255: co.Y += (params == 0) ? 1 : param[0];
1.1 root 2256: } else if(data == 'C') {
1.1.1.14 root 2257: co.X += (params == 0) ? 1 : param[0];
1.1 root 2258: } else if(data == 'D') {
1.1.1.14 root 2259: co.X -= (params == 0) ? 1 : param[0];
1.1 root 2260: } else if(data == 'H' || data == 'f') {
1.1.1.14 root 2261: co.X = (param[1] == 0 ? 1 : param[1]) - 1;
2262: co.Y = (param[0] == 0 ? 1 : param[0]) - 1 + csbi.srWindow.Top;
1.1 root 2263: } else if(data == 'J') {
2264: SMALL_RECT rect;
1.1.1.14 root 2265: clear_scr_buffer(csbi.wAttributes);
1.1 root 2266: if(param[0] == 0) {
2267: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 2268: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2269: if(co.Y < csbi.srWindow.Bottom) {
2270: SET_RECT(rect, 0, co.Y + 1, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2271: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2272: }
2273: } else if(param[0] == 1) {
1.1.1.14 root 2274: if(co.Y > csbi.srWindow.Top) {
2275: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, co.Y - 1);
2276: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2277: }
2278: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14 root 2279: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2280: } else if(param[0] == 2) {
1.1.1.14 root 2281: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2282: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2283: co.X = co.Y = 0;
2284: }
2285: } else if(data == 'K') {
2286: SMALL_RECT rect;
1.1.1.14 root 2287: clear_scr_buffer(csbi.wAttributes);
1.1 root 2288: if(param[0] == 0) {
2289: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 2290: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2291: } else if(param[0] == 1) {
2292: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14 root 2293: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2294: } else if(param[0] == 2) {
2295: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 2296: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2297: }
2298: } else if(data == 'L') {
2299: SMALL_RECT rect;
1.1.1.14 root 2300: if(params == 0) {
2301: param[0] = 1;
1.1 root 2302: }
1.1.1.14 root 2303: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2304: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2305: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2306: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2307: clear_scr_buffer(csbi.wAttributes);
1.1 root 2308: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y + param[0] - 1);
1.1.1.14 root 2309: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2310: co.X = 0;
2311: } else if(data == 'M') {
2312: SMALL_RECT rect;
1.1.1.14 root 2313: if(params == 0) {
2314: param[0] = 1;
2315: }
2316: if(co.Y + param[0] > csbi.srWindow.Bottom) {
2317: clear_scr_buffer(csbi.wAttributes);
2318: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2319: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2320: } else {
1.1.1.14 root 2321: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2322: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2323: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2324: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2325: clear_scr_buffer(csbi.wAttributes);
1.1 root 2326: }
2327: co.X = 0;
2328: } else if(data == 'h') {
2329: if(tmp[2] == '>' && tmp[3] == '5') {
2330: CONSOLE_CURSOR_INFO cur;
2331: GetConsoleCursorInfo(hStdout, &cur);
2332: if(cur.bVisible) {
2333: cur.bVisible = FALSE;
1.1.1.14 root 2334: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 2335: }
2336: }
2337: } else if(data == 'l') {
2338: if(tmp[2] == '>' && tmp[3] == '5') {
2339: CONSOLE_CURSOR_INFO cur;
2340: GetConsoleCursorInfo(hStdout, &cur);
2341: if(!cur.bVisible) {
2342: cur.bVisible = TRUE;
1.1.1.14 root 2343: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 2344: }
2345: }
2346: } else if(data == 'm') {
2347: wAttributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
2348: int reverse = 0, hidden = 0;
2349: for(int i = 0; i < params; i++) {
2350: if(param[i] == 1) {
2351: wAttributes |= FOREGROUND_INTENSITY;
2352: } else if(param[i] == 4) {
2353: wAttributes |= COMMON_LVB_UNDERSCORE;
2354: } else if(param[i] == 7) {
2355: reverse = 1;
2356: } else if(param[i] == 8 || param[i] == 16) {
2357: hidden = 1;
2358: } else if((param[i] >= 17 && param[i] <= 23) || (param[i] >= 30 && param[i] <= 37)) {
2359: wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
2360: if(param[i] >= 17 && param[i] <= 23) {
2361: param[i] -= 16;
2362: } else {
2363: param[i] -= 30;
2364: }
2365: if(param[i] & 1) {
2366: wAttributes |= FOREGROUND_RED;
2367: }
2368: if(param[i] & 2) {
2369: wAttributes |= FOREGROUND_GREEN;
2370: }
2371: if(param[i] & 4) {
2372: wAttributes |= FOREGROUND_BLUE;
2373: }
2374: } else if(param[i] >= 40 && param[i] <= 47) {
2375: wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
2376: if((param[i] - 40) & 1) {
2377: wAttributes |= BACKGROUND_RED;
2378: }
2379: if((param[i] - 40) & 2) {
2380: wAttributes |= BACKGROUND_GREEN;
2381: }
2382: if((param[i] - 40) & 4) {
2383: wAttributes |= BACKGROUND_BLUE;
2384: }
2385: }
2386: }
2387: if(reverse) {
2388: wAttributes &= ~0xff;
2389: wAttributes |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
2390: }
2391: if(hidden) {
2392: wAttributes &= ~0x0f;
2393: wAttributes |= (wAttributes >> 4) & 0x0f;
2394: }
2395: } else if(data == 'n') {
2396: if(param[0] == 6) {
2397: char tmp[16];
2398: sprintf(tmp, "\x1b[%d;%dR", co.Y + 1, co.X + 1);
2399: int len = strlen(tmp);
2400: for(int i = 0; i < len; i++) {
2401: key_buf_char->write(tmp[i]);
2402: key_buf_scan->write(0x00);
2403: }
2404: }
2405: } else if(data == 's') {
2406: stored_x = co.X;
2407: stored_y = co.Y;
2408: stored_a = wAttributes;
2409: } else if(data == 'u') {
2410: co.X = stored_x;
2411: co.Y = stored_y;
2412: wAttributes = stored_a;
2413: }
2414: }
2415: if(co.X < 0) {
2416: co.X = 0;
2417: } else if(co.X >= csbi.dwSize.X) {
2418: co.X = csbi.dwSize.X - 1;
2419: }
1.1.1.14 root 2420: if(co.Y < csbi.srWindow.Top) {
2421: co.Y = csbi.srWindow.Top;
2422: } else if(co.Y > csbi.srWindow.Bottom) {
2423: co.Y = csbi.srWindow.Bottom;
1.1 root 2424: }
2425: if(co.X != csbi.dwCursorPosition.X || co.Y != csbi.dwCursorPosition.Y) {
2426: SetConsoleCursorPosition(hStdout, co);
2427: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14 root 2428: mem[0x451 + mem[0x462] * 2] = co.Y - csbi.srWindow.Top;
1.1 root 2429: cursor_moved = false;
2430: }
2431: if(wAttributes != csbi.wAttributes) {
2432: SetConsoleTextAttribute(hStdout, wAttributes);
2433: }
2434: p = is_esc = 0;
2435: }
2436: return;
2437: } else {
2438: if(msdos_lead_byte_check(data)) {
2439: is_kanji = 1;
2440: return;
2441: } else if(data == 0x1b) {
2442: is_esc = 1;
2443: return;
2444: }
2445: }
1.1.1.20 root 2446:
2447: DWORD q = 0, num;
2448: is_kanji = 0;
2449: for(int i = 0; i < p; i++) {
2450: UINT8 c = tmp[i];
2451: if(is_kanji) {
2452: is_kanji = 0;
2453: } else if(msdos_lead_byte_check(data)) {
2454: is_kanji = 1;
2455: } else if(msdos_ctrl_code_check(data)) {
2456: out[q++] = '^';
2457: c += 'A' - 1;
2458: }
2459: out[q++] = c;
2460: }
2461: WriteConsole(hStdout, out, q, &num, NULL);
1.1 root 2462: p = 0;
1.1.1.14 root 2463:
1.1.1.15 root 2464: if(!restore_console_on_exit) {
2465: CONSOLE_SCREEN_BUFFER_INFO csbi;
2466: GetConsoleScreenBufferInfo(hStdout, &csbi);
2467: scr_top = csbi.srWindow.Top;
2468: }
1.1 root 2469: cursor_moved = true;
2470: }
2471:
2472: int msdos_aux_in()
2473: {
1.1.1.21 root 2474: msdos_stdio_reopen();
2475:
1.1.1.20 root 2476: process_t *process = msdos_process_info_get(current_psp);
2477: int fd = msdos_psp_get_file_table(3, current_psp);
2478:
2479: if(fd < process->max_files && file_handler[fd].valid && !eof(fd)) {
1.1 root 2480: char data = 0;
1.1.1.20 root 2481: _read(fd, &data, 1);
1.1 root 2482: return(data);
2483: } else {
2484: return(EOF);
2485: }
2486: }
2487:
2488: void msdos_aux_out(char data)
2489: {
1.1.1.21 root 2490: msdos_stdio_reopen();
2491:
1.1.1.20 root 2492: process_t *process = msdos_process_info_get(current_psp);
2493: int fd = msdos_psp_get_file_table(3, current_psp);
2494:
2495: if(fd < process->max_files && file_handler[fd].valid) {
2496: msdos_write(fd, &data, 1);
1.1 root 2497: }
2498: }
2499:
2500: void msdos_prn_out(char data)
2501: {
1.1.1.21 root 2502: msdos_stdio_reopen();
2503:
1.1.1.20 root 2504: process_t *process = msdos_process_info_get(current_psp);
2505: int fd = msdos_psp_get_file_table(4, current_psp);
2506:
2507: if(fd < process->max_files && file_handler[fd].valid) {
2508: msdos_write(fd, &data, 1);
1.1 root 2509: }
2510: }
2511:
2512: // memory control
2513:
1.1.1.19 root 2514: mcb_t *msdos_mcb_create(int mcb_seg, UINT8 mz, UINT16 psp, int paragraphs)
1.1 root 2515: {
2516: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2517:
2518: mcb->mz = mz;
2519: mcb->psp = psp;
1.1.1.19 root 2520: mcb->paragraphs32 = paragraphs;
1.1 root 2521: return(mcb);
2522: }
2523:
2524: void msdos_mcb_check(mcb_t *mcb)
2525: {
2526: if(!(mcb->mz == 'M' || mcb->mz == 'Z')) {
2527: fatalerror("broken mcb\n");
2528: }
2529: }
2530:
2531: int msdos_mem_split(int seg, int paragraphs)
2532: {
2533: int mcb_seg = seg - 1;
2534: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2535: msdos_mcb_check(mcb);
2536:
1.1.1.19 root 2537: if(mcb->paragraphs() > paragraphs) {
1.1 root 2538: int new_seg = mcb_seg + 1 + paragraphs;
1.1.1.19 root 2539: int new_paragraphs = mcb->paragraphs() - paragraphs - 1;
1.1 root 2540:
2541: msdos_mcb_create(new_seg, mcb->mz, 0, new_paragraphs);
2542: mcb->mz = 'M';
1.1.1.19 root 2543: mcb->paragraphs32 = paragraphs;
1.1 root 2544: return(0);
2545: }
2546: return(-1);
2547: }
2548:
2549: void msdos_mem_merge(int seg)
2550: {
2551: int mcb_seg = seg - 1;
2552: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2553: msdos_mcb_check(mcb);
2554:
2555: while(1) {
2556: if(mcb->mz == 'Z') {
2557: break;
2558: }
1.1.1.19 root 2559: int next_seg = mcb_seg + 1 + mcb->paragraphs();
1.1 root 2560: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
2561: msdos_mcb_check(next_mcb);
2562:
2563: if(next_mcb->psp != 0) {
2564: break;
2565: }
2566: mcb->mz = next_mcb->mz;
1.1.1.19 root 2567: mcb->paragraphs32 = mcb->paragraphs() + 1 + next_mcb->paragraphs();
1.1 root 2568: }
2569: }
2570:
1.1.1.8 root 2571: int msdos_mem_alloc(int mcb_seg, int paragraphs, int new_process)
1.1 root 2572: {
2573: while(1) {
2574: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2575:
1.1.1.14 root 2576: if(mcb->psp == 0) {
2577: msdos_mem_merge(mcb_seg + 1);
2578: } else {
2579: msdos_mcb_check(mcb);
2580: }
1.1.1.8 root 2581: if(!(new_process && mcb->mz != 'Z')) {
1.1.1.19 root 2582: if(mcb->psp == 0 && mcb->paragraphs() >= paragraphs) {
1.1 root 2583: msdos_mem_split(mcb_seg + 1, paragraphs);
2584: mcb->psp = current_psp;
2585: return(mcb_seg + 1);
2586: }
2587: }
2588: if(mcb->mz == 'Z') {
2589: break;
2590: }
1.1.1.19 root 2591: mcb_seg += 1 + mcb->paragraphs();
1.1 root 2592: }
2593: return(-1);
2594: }
2595:
2596: int msdos_mem_realloc(int seg, int paragraphs, int *max_paragraphs)
2597: {
2598: int mcb_seg = seg - 1;
2599: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2600: msdos_mcb_check(mcb);
1.1.1.19 root 2601: int current_paragraphs = mcb->paragraphs();
1.1 root 2602:
2603: msdos_mem_merge(seg);
1.1.1.19 root 2604: if(paragraphs > mcb->paragraphs()) {
1.1.1.14 root 2605: if(max_paragraphs) {
1.1.1.19 root 2606: *max_paragraphs = mcb->paragraphs();
1.1.1.14 root 2607: }
1.1 root 2608: msdos_mem_split(seg, current_paragraphs);
2609: return(-1);
2610: }
2611: msdos_mem_split(seg, paragraphs);
2612: return(0);
2613: }
2614:
2615: void msdos_mem_free(int seg)
2616: {
2617: int mcb_seg = seg - 1;
2618: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2619: msdos_mcb_check(mcb);
2620:
2621: mcb->psp = 0;
2622: msdos_mem_merge(seg);
2623: }
2624:
1.1.1.8 root 2625: int msdos_mem_get_free(int mcb_seg, int new_process)
1.1 root 2626: {
2627: int max_paragraphs = 0;
2628:
2629: while(1) {
2630: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2631: msdos_mcb_check(mcb);
2632:
1.1.1.8 root 2633: if(!(new_process && mcb->mz != 'Z')) {
1.1.1.19 root 2634: if(mcb->psp == 0 && mcb->paragraphs() > max_paragraphs) {
2635: max_paragraphs = mcb->paragraphs();
1.1 root 2636: }
2637: }
2638: if(mcb->mz == 'Z') {
2639: break;
2640: }
1.1.1.19 root 2641: mcb_seg += 1 + mcb->paragraphs();
1.1 root 2642: }
1.1.1.14 root 2643: return(max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs);
1.1 root 2644: }
2645:
1.1.1.8 root 2646: int msdos_mem_get_last_mcb(int mcb_seg, UINT16 psp)
2647: {
2648: int last_seg = -1;
2649:
2650: while(1) {
2651: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2652: msdos_mcb_check(mcb);
2653:
1.1.1.14 root 2654: if(mcb->psp == psp) {
1.1.1.8 root 2655: last_seg = mcb_seg;
2656: }
1.1.1.14 root 2657: if(mcb->mz == 'Z') {
2658: break;
2659: }
1.1.1.19 root 2660: mcb_seg += 1 + mcb->paragraphs();
1.1.1.8 root 2661: }
2662: return(last_seg);
2663: }
2664:
1.1.1.19 root 2665: int msdos_mem_get_umb_linked()
2666: {
2667: int mcb_seg = first_mcb;
2668:
2669: while(1) {
2670: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2671: msdos_mcb_check(mcb);
2672:
2673: if(mcb->mz == 'Z') {
2674: if(mcb_seg >= (UMB_TOP >> 4)) {
2675: return(-1);
2676: }
2677: break;
2678: }
2679: mcb_seg += 1 + mcb->paragraphs();
2680: }
2681: return(0);
2682: }
2683:
2684: int msdos_mem_link_umb()
2685: {
2686: int mcb_seg = first_mcb;
2687:
2688: while(1) {
2689: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2690: msdos_mcb_check(mcb);
2691: mcb_seg += 1 + mcb->paragraphs();
2692:
2693: if(mcb->mz == 'Z') {
2694: if(mcb_seg == (MEMORY_END >> 4) - 1) {
2695: mcb->mz = 'M';
1.1.1.20 root 2696: ((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked |= 0x01;
1.1.1.19 root 2697: return(-1);
2698: }
2699: break;
2700: }
2701: }
2702: return(0);
2703: }
2704:
2705: int msdos_mem_unlink_umb()
2706: {
2707: int mcb_seg = first_mcb;
2708:
2709: while(1) {
2710: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2711: msdos_mcb_check(mcb);
2712: mcb_seg += 1 + mcb->paragraphs();
2713:
2714: if(mcb->mz == 'Z') {
2715: break;
2716: } else {
2717: if(mcb_seg == (MEMORY_END >> 4) - 1) {
2718: mcb->mz = 'Z';
1.1.1.20 root 2719: ((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked &= ~0x01;
1.1.1.19 root 2720: return(-1);
2721: }
2722: }
2723: }
2724: return(0);
2725: }
2726:
1.1 root 2727: // environment
2728:
2729: void msdos_env_set_argv(int env_seg, char *argv)
2730: {
2731: char *dst = (char *)(mem + (env_seg << 4));
2732:
2733: while(1) {
2734: if(dst[0] == 0) {
2735: break;
2736: }
2737: dst += strlen(dst) + 1;
2738: }
2739: *dst++ = 0; // end of environment
2740: *dst++ = 1; // top of argv[0]
2741: *dst++ = 0;
2742: memcpy(dst, argv, strlen(argv));
2743: dst += strlen(argv);
2744: *dst++ = 0;
2745: *dst++ = 0;
2746: }
2747:
2748: char *msdos_env_get_argv(int env_seg)
2749: {
2750: static char env[ENV_SIZE];
2751: char *src = env;
2752:
2753: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
2754: while(1) {
2755: if(src[0] == 0) {
2756: if(src[1] == 1) {
2757: return(src + 3);
2758: }
2759: break;
2760: }
2761: src += strlen(src) + 1;
2762: }
2763: return(NULL);
2764: }
2765:
2766: char *msdos_env_get(int env_seg, const char *name)
2767: {
2768: static char env[ENV_SIZE];
2769: char *src = env;
2770:
2771: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
2772: while(1) {
2773: if(src[0] == 0) {
2774: break;
2775: }
2776: int len = strlen(src);
2777: char *n = my_strtok(src, "=");
2778: char *v = src + strlen(n) + 1;
2779:
2780: if(_stricmp(name, n) == 0) {
2781: return(v);
2782: }
2783: src += len + 1;
2784: }
2785: return(NULL);
2786: }
2787:
2788: void msdos_env_set(int env_seg, char *name, char *value)
2789: {
2790: char env[ENV_SIZE];
2791: char *src = env;
2792: char *dst = (char *)(mem + (env_seg << 4));
2793: char *argv = msdos_env_get_argv(env_seg);
2794: int done = 0;
2795:
2796: memcpy(src, dst, ENV_SIZE);
2797: memset(dst, 0, ENV_SIZE);
2798: while(1) {
2799: if(src[0] == 0) {
2800: break;
2801: }
2802: int len = strlen(src);
2803: char *n = my_strtok(src, "=");
2804: char *v = src + strlen(n) + 1;
2805: char tmp[1024];
2806:
2807: if(_stricmp(name, n) == 0) {
2808: sprintf(tmp, "%s=%s", n, value);
2809: done = 1;
2810: } else {
2811: sprintf(tmp, "%s=%s", n, v);
2812: }
2813: memcpy(dst, tmp, strlen(tmp));
2814: dst += strlen(tmp) + 1;
2815: src += len + 1;
2816: }
2817: if(!done) {
2818: char tmp[1024];
2819:
2820: sprintf(tmp, "%s=%s", name, value);
2821: memcpy(dst, tmp, strlen(tmp));
2822: dst += strlen(tmp) + 1;
2823: }
2824: if(argv) {
2825: *dst++ = 0; // end of environment
2826: *dst++ = 1; // top of argv[0]
2827: *dst++ = 0;
2828: memcpy(dst, argv, strlen(argv));
2829: dst += strlen(argv);
2830: *dst++ = 0;
2831: *dst++ = 0;
2832: }
2833: }
2834:
2835: // process
2836:
1.1.1.8 root 2837: psp_t *msdos_psp_create(int psp_seg, UINT16 mcb_seg, UINT16 parent_psp, UINT16 env_seg)
1.1 root 2838: {
2839: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
2840:
2841: memset(psp, 0, PSP_SIZE);
2842: psp->exit[0] = 0xcd;
2843: psp->exit[1] = 0x20;
1.1.1.8 root 2844: psp->first_mcb = mcb_seg;
1.1 root 2845: psp->far_call = 0xea;
2846: psp->cpm_entry.w.l = 0xfff1; // int 21h, retf
2847: psp->cpm_entry.w.h = 0xf000;
2848: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
2849: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
2850: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
2851: psp->parent_psp = parent_psp;
1.1.1.20 root 2852: if(parent_psp == (UINT16)-1) {
2853: for(int i = 0; i < 20; i++) {
2854: if(file_handler[i].valid) {
2855: psp->file_table[i] = i;
2856: } else {
2857: psp->file_table[i] = 0xff;
2858: }
1.1 root 2859: }
1.1.1.20 root 2860: } else {
2861: memcpy(psp->file_table, ((psp_t *)(mem + (parent_psp << 4)))->file_table, 20);
1.1 root 2862: }
2863: psp->env_seg = env_seg;
2864: psp->stack.w.l = REG16(SP);
1.1.1.3 root 2865: psp->stack.w.h = SREG(SS);
1.1.1.14 root 2866: psp->file_table_size = 20;
2867: psp->file_table_ptr.w.l = 0x18;
2868: psp->file_table_ptr.w.h = psp_seg;
1.1 root 2869: psp->service[0] = 0xcd;
2870: psp->service[1] = 0x21;
2871: psp->service[2] = 0xcb;
2872: return(psp);
2873: }
2874:
1.1.1.20 root 2875: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg)
2876: {
2877: if(psp_seg && fd < 20) {
2878: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
2879: psp->file_table[fd] = value;
2880: }
2881: }
2882:
2883: int msdos_psp_get_file_table(int fd, int psp_seg)
2884: {
2885: if(psp_seg && fd < 20) {
2886: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
2887: fd = psp->file_table[fd];
2888: }
2889: return fd;
2890: }
2891:
1.1 root 2892: int msdos_process_exec(char *cmd, param_block_t *param, UINT8 al)
2893: {
2894: // load command file
2895: int fd = -1;
2896: int dos_command = 0;
1.1.1.4 root 2897: char command[MAX_PATH], path[MAX_PATH], opt[MAX_PATH], *name, name_tmp[MAX_PATH];
1.1 root 2898:
2899: int opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
2900: int opt_len = mem[opt_ofs];
2901: memset(opt, 0, sizeof(opt));
2902: memcpy(opt, mem + opt_ofs + 1, opt_len);
2903:
1.1.1.14 root 2904: if(strlen(cmd) >= 5 && _stricmp(&cmd[strlen(cmd) - 4], ".BAT") == 0) {
2905: // this is a batch file, run command.com
2906: char tmp[MAX_PATH];
2907: if(opt_len != 0) {
2908: sprintf(tmp, "/C %s %s", cmd, opt);
2909: } else {
2910: sprintf(tmp, "/C %s", cmd);
2911: }
2912: strcpy(opt, tmp);
2913: opt_len = strlen(opt);
2914: mem[opt_ofs] = opt_len;
2915: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
2916: strcpy(command, comspec_path);
2917: strcpy(name_tmp, "COMMAND.COM");
2918: } else {
2919: if(_stricmp(cmd, "C:\\COMMAND.COM") == 0) {
2920: // redirect C:\COMMAND.COM to comspec_path
2921: strcpy(command, comspec_path);
2922: } else {
2923: strcpy(command, cmd);
2924: }
2925: GetFullPathName(command, MAX_PATH, path, &name);
2926: memset(name_tmp, 0, sizeof(name_tmp));
2927: strcpy(name_tmp, name);
2928:
2929: // check command.com
2930: if(_stricmp(name, "COMMAND.COM") == 0 || _stricmp(name, "COMMAND") == 0) {
2931: if(opt_len == 0) {
2932: // process_t *current_process = msdos_process_info_get(current_psp);
2933: process_t *current_process = NULL;
2934: for(int i = 0; i < MAX_PROCESS; i++) {
2935: if(process[i].psp == current_psp) {
2936: current_process = &process[i];
2937: break;
2938: }
2939: }
2940: if(current_process != NULL) {
2941: param->cmd_line.dw = current_process->dta.dw;
2942: opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
2943: opt_len = mem[opt_ofs];
2944: memset(opt, 0, sizeof(opt));
2945: memcpy(opt, mem + opt_ofs + 1, opt_len);
2946: }
2947: }
2948: for(int i = 0; i < opt_len; i++) {
2949: if(opt[i] == ' ') {
2950: continue;
2951: }
2952: if(opt[i] == '/' && (opt[i + 1] == 'c' || opt[i + 1] == 'C') && opt[i + 2] == ' ') {
2953: for(int j = i + 3; j < opt_len; j++) {
2954: if(opt[j] == ' ') {
2955: continue;
2956: }
2957: char *token = my_strtok(opt + j, " ");
2958:
2959: if(strlen(token) >= 5 && _stricmp(&token[strlen(token) - 4], ".BAT") == 0) {
2960: // this is a batch file, okay to run command.com
2961: } else {
2962: // run program directly without command.com
2963: strcpy(command, token);
2964: char tmp[MAX_PATH];
2965: strcpy(tmp, token + strlen(token) + 1);
2966: strcpy(opt, tmp);
2967: opt_len = strlen(opt);
2968: mem[opt_ofs] = opt_len;
2969: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
2970: dos_command = 1;
2971: }
2972: break;
1.1 root 2973: }
2974: }
1.1.1.14 root 2975: break;
1.1 root 2976: }
2977: }
2978: }
2979:
2980: // load command file
2981: strcpy(path, command);
2982: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
2983: sprintf(path, "%s.COM", command);
2984: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
2985: sprintf(path, "%s.EXE", command);
2986: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
1.1.1.14 root 2987: sprintf(path, "%s.BAT", command);
2988: if(_access(path, 0) == 0) {
2989: // this is a batch file, run command.com
2990: char tmp[MAX_PATH];
2991: if(opt_len != 0) {
2992: sprintf(tmp, "/C %s %s", path, opt);
2993: } else {
2994: sprintf(tmp, "/C %s", path);
2995: }
2996: strcpy(opt, tmp);
2997: opt_len = strlen(opt);
2998: mem[opt_ofs] = opt_len;
2999: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
3000: strcpy(path, comspec_path);
3001: strcpy(name_tmp, "COMMAND.COM");
3002: fd = _open(path, _O_RDONLY | _O_BINARY);
3003: } else {
3004: // search path in parent environments
3005: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
3006: char *env = msdos_env_get(parent_psp->env_seg, "PATH");
3007: if(env != NULL) {
3008: char env_path[4096];
3009: strcpy(env_path, env);
3010: char *token = my_strtok(env_path, ";");
3011:
3012: while(token != NULL) {
3013: if(strlen(token) != 0) {
3014: sprintf(path, "%s", msdos_combine_path(token, command));
3015: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
3016: break;
3017: }
3018: sprintf(path, "%s.COM", msdos_combine_path(token, command));
3019: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
3020: break;
3021: }
3022: sprintf(path, "%s.EXE", msdos_combine_path(token, command));
3023: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
3024: break;
3025: }
3026: sprintf(path, "%s.BAT", msdos_combine_path(token, command));
3027: if(_access(path, 0) == 0) {
3028: // this is a batch file, run command.com
3029: char tmp[MAX_PATH];
3030: if(opt_len != 0) {
3031: sprintf(tmp, "/C %s %s", path, opt);
3032: } else {
3033: sprintf(tmp, "/C %s", path);
3034: }
3035: strcpy(opt, tmp);
3036: opt_len = strlen(opt);
3037: mem[opt_ofs] = opt_len;
3038: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
3039: strcpy(path, comspec_path);
3040: strcpy(name_tmp, "COMMAND.COM");
3041: fd = _open(path, _O_RDONLY | _O_BINARY);
3042: break;
3043: }
1.1.1.8 root 3044: }
1.1.1.14 root 3045: token = my_strtok(NULL, ";");
1.1 root 3046: }
3047: }
3048: }
3049: }
3050: }
3051: }
3052: if(fd == -1) {
3053: if(dos_command) {
3054: // may be dos command
3055: char tmp[MAX_PATH];
3056: sprintf(tmp, "%s %s", command, opt);
3057: system(tmp);
3058: return(0);
3059: } else {
3060: return(-1);
3061: }
3062: }
3063: _read(fd, file_buffer, sizeof(file_buffer));
3064: _close(fd);
3065:
3066: // copy environment
3067: int env_seg, psp_seg;
3068:
1.1.1.8 root 3069: if((env_seg = msdos_mem_alloc(first_mcb, ENV_SIZE >> 4, 1)) == -1) {
1.1 root 3070: return(-1);
3071: }
3072: if(param->env_seg == 0) {
3073: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
3074: memcpy(mem + (env_seg << 4), mem + (parent_psp->env_seg << 4), ENV_SIZE);
3075: } else {
3076: memcpy(mem + (env_seg << 4), mem + (param->env_seg << 4), ENV_SIZE);
3077: }
3078: msdos_env_set_argv(env_seg, msdos_short_full_path(path));
3079:
3080: // check exe header
3081: exe_header_t *header = (exe_header_t *)file_buffer;
1.1.1.8 root 3082: int paragraphs, free_paragraphs = msdos_mem_get_free(first_mcb, 1);
1.1 root 3083: UINT16 cs, ss, ip, sp;
3084:
3085: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
3086: // memory allocation
3087: int header_size = header->header_size * 16;
3088: int load_size = header->pages * 512 - header_size;
3089: if(header_size + load_size < 512) {
3090: load_size = 512 - header_size;
3091: }
3092: paragraphs = (PSP_SIZE + load_size) >> 4;
3093: if(paragraphs + header->min_alloc > free_paragraphs) {
3094: msdos_mem_free(env_seg);
3095: return(-1);
3096: }
3097: paragraphs += header->max_alloc ? header->max_alloc : header->min_alloc;
3098: if(paragraphs > free_paragraphs) {
3099: paragraphs = free_paragraphs;
3100: }
1.1.1.8 root 3101: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1 root 3102: msdos_mem_free(env_seg);
3103: return(-1);
3104: }
3105: // relocation
3106: int start_seg = psp_seg + (PSP_SIZE >> 4);
3107: for(int i = 0; i < header->relocations; i++) {
3108: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
3109: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
3110: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
3111: }
3112: memcpy(mem + (start_seg << 4), file_buffer + header_size, load_size);
3113: // segments
3114: cs = header->init_cs + start_seg;
3115: ss = header->init_ss + start_seg;
3116: ip = header->init_ip;
3117: sp = header->init_sp - 2; // for symdeb
3118: } else {
3119: // memory allocation
3120: paragraphs = free_paragraphs;
1.1.1.8 root 3121: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1 root 3122: msdos_mem_free(env_seg);
3123: return(-1);
3124: }
3125: int start_seg = psp_seg + (PSP_SIZE >> 4);
3126: memcpy(mem + (start_seg << 4), file_buffer, 0x10000 - PSP_SIZE);
3127: // segments
3128: cs = ss = psp_seg;
3129: ip = 0x100;
3130: sp = 0xfffe;
3131: }
3132:
3133: // create psp
1.1.1.3 root 3134: #if defined(HAS_I386)
3135: *(UINT16 *)(mem + 4 * 0x22 + 0) = m_eip;
3136: #else
3137: *(UINT16 *)(mem + 4 * 0x22 + 0) = m_pc - SREG_BASE(CS);
3138: #endif
3139: *(UINT16 *)(mem + 4 * 0x22 + 2) = SREG(CS);
1.1 root 3140: psp_t *psp = msdos_psp_create(psp_seg, psp_seg + paragraphs, current_psp, env_seg);
3141: memcpy(psp->fcb1, mem + (param->fcb1.w.h << 4) + param->fcb1.w.l, sizeof(psp->fcb1));
3142: memcpy(psp->fcb2, mem + (param->fcb2.w.h << 4) + param->fcb2.w.l, sizeof(psp->fcb2));
3143: memcpy(psp->buffer, mem + (param->cmd_line.w.h << 4) + param->cmd_line.w.l, sizeof(psp->buffer));
3144:
3145: mcb_t *mcb_env = (mcb_t *)(mem + ((env_seg - 1) << 4));
3146: mcb_t *mcb_psp = (mcb_t *)(mem + ((psp_seg - 1) << 4));
3147: mcb_psp->psp = mcb_env->psp = psp_seg;
3148:
1.1.1.4 root 3149: for(int i = 0; i < 8; i++) {
3150: if(name_tmp[i] == '.') {
3151: mcb_psp->prog_name[i] = '\0';
3152: break;
3153: } else if(i < 7 && msdos_lead_byte_check(name_tmp[i])) {
3154: mcb_psp->prog_name[i] = name_tmp[i];
3155: i++;
3156: mcb_psp->prog_name[i] = name_tmp[i];
3157: } else if(name_tmp[i] >= 'a' && name_tmp[i] <= 'z') {
3158: mcb_psp->prog_name[i] = name_tmp[i] - 'a' + 'A';
3159: } else {
3160: mcb_psp->prog_name[i] = name_tmp[i];
3161: }
3162: }
3163:
1.1 root 3164: // process info
3165: process_t *process = msdos_process_info_create(psp_seg);
3166: strcpy(process->module_dir, msdos_short_full_dir(path));
3167: process->dta.w.l = 0x80;
3168: process->dta.w.h = psp_seg;
3169: process->switchar = '/';
3170: process->max_files = 20;
3171: process->parent_int_10h_feh_called = int_10h_feh_called;
3172: process->parent_int_10h_ffh_called = int_10h_ffh_called;
1.1.1.14 root 3173: process->parent_ds = SREG(DS);
1.1 root 3174:
3175: current_psp = psp_seg;
1.1.1.23! root 3176: msdos_sda_update(current_psp);
1.1 root 3177:
3178: if(al == 0x00) {
3179: int_10h_feh_called = int_10h_ffh_called = false;
3180:
3181: // registers and segments
3182: REG16(AX) = REG16(BX) = 0x00;
3183: REG16(CX) = 0xff;
3184: REG16(DX) = psp_seg;
3185: REG16(SI) = ip;
3186: REG16(DI) = sp;
3187: REG16(SP) = sp;
1.1.1.3 root 3188: SREG(DS) = SREG(ES) = psp_seg;
3189: SREG(SS) = ss;
3190: i386_load_segment_descriptor(DS);
3191: i386_load_segment_descriptor(ES);
3192: i386_load_segment_descriptor(SS);
1.1 root 3193:
3194: *(UINT16 *)(mem + (ss << 4) + sp) = 0;
3195: i386_jmp_far(cs, ip);
3196: } else if(al == 0x01) {
3197: // copy ss:sp and cs:ip to param block
3198: param->sp = sp;
3199: param->ss = ss;
3200: param->ip = ip;
3201: param->cs = cs;
3202: }
3203: return(0);
3204: }
3205:
3206: void msdos_process_terminate(int psp_seg, int ret, int mem_free)
3207: {
3208: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
3209:
3210: *(UINT32 *)(mem + 4 * 0x22) = psp->int_22h.dw;
3211: *(UINT32 *)(mem + 4 * 0x23) = psp->int_23h.dw;
3212: *(UINT32 *)(mem + 4 * 0x24) = psp->int_24h.dw;
3213:
1.1.1.3 root 3214: SREG(SS) = psp->stack.w.h;
3215: i386_load_segment_descriptor(SS);
1.1 root 3216: REG16(SP) = psp->stack.w.l;
3217: i386_jmp_far(psp->int_22h.w.h, psp->int_22h.w.l);
3218:
3219: process_t *process = msdos_process_info_get(psp_seg);
3220: int_10h_feh_called = process->parent_int_10h_feh_called;
3221: int_10h_ffh_called = process->parent_int_10h_ffh_called;
1.1.1.14 root 3222: SREG(DS) = process->parent_ds;
3223: i386_load_segment_descriptor(DS);
1.1 root 3224:
3225: if(mem_free) {
1.1.1.8 root 3226: int mcb_seg;
3227: while((mcb_seg = msdos_mem_get_last_mcb(first_mcb, psp_seg)) != -1) {
3228: msdos_mem_free(mcb_seg + 1);
3229: }
3230: while((mcb_seg = msdos_mem_get_last_mcb(UMB_TOP >> 4, psp_seg)) != -1) {
3231: msdos_mem_free(mcb_seg + 1);
3232: }
1.1 root 3233:
3234: for(int i = 0; i < MAX_FILES; i++) {
3235: if(file_handler[i].valid && file_handler[i].psp == psp_seg) {
3236: _close(i);
1.1.1.20 root 3237: msdos_file_handler_close(i);
3238: msdos_psp_set_file_table(i, 0x0ff, psp_seg); // FIXME: consider duplicated file handles
1.1 root 3239: }
3240: }
1.1.1.13 root 3241: msdos_dta_info_free(psp_seg);
1.1 root 3242: }
1.1.1.14 root 3243: msdos_stdio_reopen();
1.1 root 3244:
3245: memset(process, 0, sizeof(process_t));
3246:
3247: current_psp = psp->parent_psp;
3248: retval = ret;
1.1.1.23! root 3249: msdos_sda_update(current_psp);
1.1 root 3250: }
3251:
3252: // drive
3253:
3254: int msdos_drive_param_block_update(int drive_num, UINT16 *seg, UINT16 *ofs, int force_update)
3255: {
3256: *seg = DPB_TOP >> 4;
3257: *ofs = sizeof(dpb_t) * drive_num;
3258: dpb_t *dpb = (dpb_t *)(mem + (*seg << 4) + *ofs);
3259:
3260: if(!force_update && dpb->free_clusters != 0) {
3261: return(dpb->bytes_per_sector ? 1 : 0);
3262: }
3263: memset(dpb, 0, sizeof(dpb_t));
3264:
3265: int res = 0;
3266: char dev[64];
3267: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num);
3268:
1.1.1.17 root 3269: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1.1 root 3270: if(hFile != INVALID_HANDLE_VALUE) {
3271: DISK_GEOMETRY geo;
3272: DWORD dwSize;
3273: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
3274: dpb->bytes_per_sector = (UINT16)geo.BytesPerSector;
3275: dpb->highest_sector_num = (UINT8)(geo.SectorsPerTrack - 1);
3276: dpb->highest_cluster_num = (UINT16)(geo.TracksPerCylinder * geo.Cylinders.QuadPart + 1);
1.1.1.14 root 3277: dpb->maximum_cluster_num = (UINT32)(geo.TracksPerCylinder * geo.Cylinders.QuadPart + 1);
1.1 root 3278: switch(geo.MediaType) {
3279: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K)
3280: dpb->media_type = 0xff;
3281: break;
3282: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K)
3283: dpb->media_type = 0xfe;
3284: break;
3285: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K)
3286: dpb->media_type = 0xfd;
3287: break;
3288: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K)
3289: dpb->media_type = 0xfc;
3290: break;
3291: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M)
3292: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5")
3293: dpb->media_type = 0xf9;
3294: break;
3295: case FixedMedia: // hard disk
3296: case RemovableMedia:
1.1.1.19 root 3297: case Unknown:
1.1 root 3298: dpb->media_type = 0xf8;
3299: break;
3300: default:
3301: dpb->media_type = 0xf0;
3302: break;
3303: }
3304: res = 1;
3305: }
3306: dpb->drive_num = drive_num;
3307: dpb->unit_num = drive_num;
3308: dpb->next_dpb_ofs = *ofs + sizeof(dpb_t);
3309: dpb->next_dpb_seg = *seg;
1.1.1.14 root 3310: dpb->info_sector = 0xffff;
3311: dpb->backup_boot_sector = 0xffff;
1.1 root 3312: dpb->free_clusters = 0xffff;
1.1.1.14 root 3313: dpb->free_search_cluster = 0xffffffff;
1.1 root 3314: CloseHandle(hFile);
3315: }
3316: return(res);
3317: }
3318:
3319: // pc bios
3320:
1.1.1.19 root 3321: UINT32 get_ticks_since_midnight(UINT32 cur_msec)
3322: {
3323: static unsigned __int64 start_msec_since_midnight = 0;
3324: static unsigned __int64 start_msec_since_hostboot = 0;
3325:
3326: if(start_msec_since_midnight == 0) {
3327: SYSTEMTIME time;
3328: GetLocalTime(&time);
3329: start_msec_since_midnight = ((time.wHour * 60 + time.wMinute) * 60 + time.wSecond) * 1000 + time.wMilliseconds;
3330: start_msec_since_hostboot = cur_msec;
3331: }
3332: unsigned __int64 msec = (start_msec_since_midnight + cur_msec - start_msec_since_hostboot) % (24 * 60 * 60 * 1000);
3333: unsigned __int64 tick = msec * 0x1800b0 / (24 * 60 * 60 * 1000);
3334: return (UINT32)tick;
3335: }
3336:
3337: void pcbios_update_daily_timer_counter(UINT32 cur_msec)
3338: {
3339: UINT32 prev_tick = *(UINT32 *)(mem + 0x46c);
3340: UINT32 next_tick = get_ticks_since_midnight(cur_msec);
3341:
3342: if(prev_tick > next_tick) {
3343: mem[0x470] = 1;
3344: }
3345: *(UINT32 *)(mem + 0x46c) = next_tick;
3346: }
3347:
1.1.1.14 root 3348: inline void pcbios_irq0()
3349: {
3350: //++*(UINT32 *)(mem + 0x46c);
1.1.1.19 root 3351: pcbios_update_daily_timer_counter(timeGetTime());
1.1.1.14 root 3352: }
3353:
1.1.1.16 root 3354: int pcbios_get_text_vram_address(int page)
1.1 root 3355: {
3356: if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 3357: return TEXT_VRAM_TOP;
1.1 root 3358: } else {
1.1.1.14 root 3359: return TEXT_VRAM_TOP + VIDEO_REGEN * (page % vram_pages);
1.1 root 3360: }
3361: }
3362:
1.1.1.16 root 3363: int pcbios_get_shadow_buffer_address(int page)
1.1 root 3364: {
1.1.1.14 root 3365: if(!int_10h_feh_called) {
1.1.1.16 root 3366: return pcbios_get_text_vram_address(page);
1.1.1.14 root 3367: } else if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 3368: return SHADOW_BUF_TOP;
3369: } else {
1.1.1.14 root 3370: return SHADOW_BUF_TOP + VIDEO_REGEN * (page % vram_pages);
1.1.1.8 root 3371: }
3372: }
3373:
1.1.1.16 root 3374: int pcbios_get_shadow_buffer_address(int page, int x, int y)
1.1.1.8 root 3375: {
1.1.1.16 root 3376: return pcbios_get_shadow_buffer_address(page) + (x + y * scr_width) * 2;
1.1 root 3377: }
3378:
1.1.1.16 root 3379: void pcbios_set_console_size(int width, int height, bool clr_screen)
1.1 root 3380: {
1.1.1.14 root 3381: // clear the existing screen, not just the new one
3382: int clr_height = max(height, scr_height);
3383:
1.1.1.16 root 3384: if(scr_width != width || scr_height != height) {
3385: change_console_size(width, height);
1.1.1.14 root 3386: }
3387: mem[0x462] = 0;
3388: *(UINT16 *)(mem + 0x44e) = 0;
3389:
1.1.1.16 root 3390: text_vram_top_address = pcbios_get_text_vram_address(0);
3391: text_vram_end_address = text_vram_top_address + width * height * 2;
3392: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(0);
3393: shadow_buffer_end_address = shadow_buffer_top_address + width * height * 2;
1.1 root 3394:
1.1.1.23! root 3395: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.16 root 3396: if(clr_screen) {
1.1.1.14 root 3397: for(int ofs = shadow_buffer_top_address; ofs < shadow_buffer_end_address;) {
3398: mem[ofs++] = 0x20;
3399: mem[ofs++] = 0x07;
3400: }
3401:
3402: EnterCriticalSection(&vram_crit_sect);
3403: for(int y = 0; y < clr_height; y++) {
3404: for(int x = 0; x < scr_width; x++) {
3405: SCR_BUF(y,x).Char.AsciiChar = ' ';
3406: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
1.1 root 3407: }
3408: }
3409: SMALL_RECT rect;
1.1.1.14 root 3410: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + clr_height - 1);
3411: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
3412: vram_length_char = vram_last_length_char = 0;
3413: vram_length_attr = vram_last_length_attr = 0;
3414: LeaveCriticalSection(&vram_crit_sect);
1.1 root 3415: }
1.1.1.14 root 3416: COORD co;
3417: co.X = 0;
3418: co.Y = scr_top;
3419: SetConsoleCursorPosition(hStdout, co);
3420: cursor_moved = true;
3421: SetConsoleTextAttribute(hStdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
1.1 root 3422: }
3423:
1.1.1.16 root 3424: inline void pcbios_int_10h_00h()
3425: {
3426: switch(REG8(AL) & 0x7f) {
3427: case 0x70: // v-text mode
3428: case 0x71: // extended cga v-text mode
3429: pcbios_set_console_size(scr_width, scr_height, !(REG8(AL) & 0x80));
3430: break;
3431: default:
3432: pcbios_set_console_size(80, 25, !(REG8(AL) & 0x80));
3433: break;
3434: }
3435: if(REG8(AL) & 0x80) {
3436: mem[0x487] |= 0x80;
3437: } else {
3438: mem[0x487] &= ~0x80;
3439: }
3440: mem[0x449] = REG8(AL) & 0x7f;
3441: }
3442:
1.1 root 3443: inline void pcbios_int_10h_01h()
3444: {
1.1.1.13 root 3445: mem[0x460] = REG8(CL);
3446: mem[0x461] = REG8(CH);
1.1.1.14 root 3447:
1.1.1.23! root 3448: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 3449: CONSOLE_CURSOR_INFO ci;
3450: GetConsoleCursorInfo(hStdout, &ci);
3451: // ci.bVisible = !(REG8(CH) & 0x60) && REG8(CH) <= REG8(CL);
3452: // if(ci.bVisible) {
3453: int lines = max(8, REG8(CL) + 1);
3454: ci.dwSize = (REG8(CL) - REG8(CH) + 1) * 100 / lines;
3455: // }
3456: SetConsoleCursorInfo(hStdout, &ci);
1.1 root 3457: }
3458:
3459: inline void pcbios_int_10h_02h()
3460: {
1.1.1.14 root 3461: // continuously setting the cursor effectively stops it blinking
3462: if(mem[0x462] == REG8(BH) && (REG8(DL) != mem[0x450 + REG8(BH) * 2] || REG8(DH) != mem[0x451 + REG8(BH) * 2])) {
1.1 root 3463: COORD co;
3464: co.X = REG8(DL);
1.1.1.14 root 3465: co.Y = REG8(DH) + scr_top;
3466:
3467: // some programs hide the cursor by moving it off screen
3468: static bool hidden = false;
1.1.1.23! root 3469: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 3470: CONSOLE_CURSOR_INFO ci;
3471: GetConsoleCursorInfo(hStdout, &ci);
3472:
3473: if(REG8(DH) >= scr_height || !SetConsoleCursorPosition(hStdout, co)) {
3474: if(ci.bVisible) {
3475: ci.bVisible = FALSE;
3476: // SetConsoleCursorInfo(hStdout, &ci);
3477: hidden = true;
3478: }
3479: } else if(hidden) {
3480: if(!ci.bVisible) {
3481: ci.bVisible = TRUE;
3482: // SetConsoleCursorInfo(hStdout, &ci);
3483: }
3484: hidden = false;
3485: }
1.1 root 3486: }
1.1.1.14 root 3487: mem[0x450 + (REG8(BH) % vram_pages) * 2] = REG8(DL);
3488: mem[0x451 + (REG8(BH) % vram_pages) * 2] = REG8(DH);
1.1 root 3489: }
3490:
3491: inline void pcbios_int_10h_03h()
3492: {
1.1.1.14 root 3493: REG8(DL) = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3494: REG8(DH) = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 3495: REG8(CL) = mem[0x460];
3496: REG8(CH) = mem[0x461];
3497: }
3498:
3499: inline void pcbios_int_10h_05h()
3500: {
1.1.1.14 root 3501: if(REG8(AL) >= vram_pages) {
3502: return;
3503: }
3504: if(mem[0x462] != REG8(AL)) {
3505: vram_flush();
3506:
1.1.1.23! root 3507: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 3508: SMALL_RECT rect;
1.1.1.14 root 3509: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
3510: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3511:
1.1.1.16 root 3512: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(mem[0x462]); y < scr_height; y++) {
1.1.1.14 root 3513: for(int x = 0; x < scr_width; x++) {
3514: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
3515: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 3516: }
3517: }
1.1.1.16 root 3518: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(REG8(AL)); y < scr_height; y++) {
1.1.1.14 root 3519: for(int x = 0; x < scr_width; x++) {
3520: SCR_BUF(y,x).Char.AsciiChar = mem[ofs++];
3521: SCR_BUF(y,x).Attributes = mem[ofs++];
1.1 root 3522: }
3523: }
1.1.1.14 root 3524: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3525:
3526: COORD co;
1.1.1.14 root 3527: co.X = mem[0x450 + REG8(AL) * 2];
3528: co.Y = mem[0x451 + REG8(AL) * 2] + scr_top;
3529: if(co.Y < scr_top + scr_height) {
3530: SetConsoleCursorPosition(hStdout, co);
3531: }
1.1 root 3532: }
1.1.1.14 root 3533: mem[0x462] = REG8(AL);
3534: *(UINT16 *)(mem + 0x44e) = REG8(AL) * VIDEO_REGEN;
3535: int regen = min(scr_width * scr_height * 2, 0x8000);
1.1.1.16 root 3536: text_vram_top_address = pcbios_get_text_vram_address(mem[0x462]);
1.1.1.14 root 3537: text_vram_end_address = text_vram_top_address + regen;
1.1.1.16 root 3538: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(mem[0x462]);
1.1.1.14 root 3539: shadow_buffer_end_address = shadow_buffer_top_address + regen;
1.1 root 3540: }
3541:
3542: inline void pcbios_int_10h_06h()
3543: {
1.1.1.14 root 3544: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
3545: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
3546: return;
3547: }
3548: vram_flush();
3549:
1.1.1.23! root 3550: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 3551: SMALL_RECT rect;
1.1.1.14 root 3552: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
3553: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
3554:
3555: int right = min(REG8(DL), scr_width - 1);
3556: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 3557:
3558: if(REG8(AL) == 0) {
1.1.1.14 root 3559: for(int y = REG8(CH); y <= bottom; y++) {
1.1.1.16 root 3560: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 3561: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
3562: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3563: }
3564: }
3565: } else {
1.1.1.14 root 3566: for(int y = REG8(CH), y2 = min(REG8(CH) + REG8(AL), bottom + 1); y <= bottom; y++, y2++) {
1.1.1.16 root 3567: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 3568: if(y2 <= bottom) {
3569: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 3570: } else {
1.1.1.14 root 3571: SCR_BUF(y,x).Char.AsciiChar = ' ';
3572: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3573: }
1.1.1.14 root 3574: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
3575: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 3576: }
3577: }
3578: }
1.1.1.14 root 3579: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3580: }
3581:
3582: inline void pcbios_int_10h_07h()
3583: {
1.1.1.14 root 3584: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
3585: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
3586: return;
3587: }
3588: vram_flush();
3589:
1.1.1.23! root 3590: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 3591: SMALL_RECT rect;
1.1.1.14 root 3592: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
3593: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
3594:
3595: int right = min(REG8(DL), scr_width - 1);
3596: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 3597:
3598: if(REG8(AL) == 0) {
1.1.1.14 root 3599: for(int y = REG8(CH); y <= bottom; y++) {
1.1.1.16 root 3600: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 3601: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
3602: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3603: }
3604: }
3605: } else {
1.1.1.14 root 3606: for(int y = bottom, y2 = max(REG8(CH) - 1, bottom - REG8(AL)); y >= REG8(CH); y--, y2--) {
1.1.1.16 root 3607: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 3608: if(y2 >= REG8(CH)) {
3609: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 3610: } else {
1.1.1.14 root 3611: SCR_BUF(y,x).Char.AsciiChar = ' ';
3612: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3613: }
1.1.1.14 root 3614: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
3615: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 3616: }
3617: }
3618: }
1.1.1.14 root 3619: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3620: }
3621:
3622: inline void pcbios_int_10h_08h()
3623: {
3624: COORD co;
3625: DWORD num;
3626:
1.1.1.14 root 3627: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3628: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 3629:
3630: if(mem[0x462] == REG8(BH)) {
1.1.1.23! root 3631: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 3632: co.Y += scr_top;
3633: vram_flush();
1.1 root 3634: ReadConsoleOutputCharacter(hStdout, scr_char, 1, co, &num);
3635: ReadConsoleOutputAttribute(hStdout, scr_attr, 1, co, &num);
3636: REG8(AL) = scr_char[0];
3637: REG8(AH) = scr_attr[0];
3638: } else {
1.1.1.16 root 3639: REG16(AX) = *(UINT16 *)(mem + pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y));
1.1 root 3640: }
3641: }
3642:
3643: inline void pcbios_int_10h_09h()
3644: {
3645: COORD co;
3646:
1.1.1.14 root 3647: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3648: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
3649:
1.1.1.16 root 3650: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
3651: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 3652:
3653: if(mem[0x462] == REG8(BH)) {
1.1.1.14 root 3654: EnterCriticalSection(&vram_crit_sect);
1.1.1.16 root 3655: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 3656: while(dest < end) {
3657: write_text_vram_char(dest - vram, REG8(AL));
3658: mem[dest++] = REG8(AL);
3659: write_text_vram_attr(dest - vram, REG8(BL));
3660: mem[dest++] = REG8(BL);
1.1 root 3661: }
1.1.1.14 root 3662: LeaveCriticalSection(&vram_crit_sect);
1.1 root 3663: } else {
1.1.1.14 root 3664: while(dest < end) {
1.1 root 3665: mem[dest++] = REG8(AL);
3666: mem[dest++] = REG8(BL);
3667: }
3668: }
3669: }
3670:
3671: inline void pcbios_int_10h_0ah()
3672: {
3673: COORD co;
3674:
1.1.1.14 root 3675: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3676: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
3677:
1.1.1.16 root 3678: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
3679: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 3680:
3681: if(mem[0x462] == REG8(BH)) {
1.1.1.14 root 3682: EnterCriticalSection(&vram_crit_sect);
1.1.1.16 root 3683: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 3684: while(dest < end) {
3685: write_text_vram_char(dest - vram, REG8(AL));
3686: mem[dest++] = REG8(AL);
3687: dest++;
1.1 root 3688: }
1.1.1.14 root 3689: LeaveCriticalSection(&vram_crit_sect);
1.1 root 3690: } else {
1.1.1.14 root 3691: while(dest < end) {
1.1 root 3692: mem[dest++] = REG8(AL);
3693: dest++;
3694: }
3695: }
3696: }
3697:
3698: inline void pcbios_int_10h_0eh()
3699: {
1.1.1.14 root 3700: DWORD num;
3701: COORD co;
3702:
3703: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3704: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
3705:
3706: if(REG8(AL) == 7) {
3707: //MessageBeep(-1);
3708: } else if(REG8(AL) == 8 || REG8(AL) == 10 || REG8(AL) == 13) {
3709: if(REG8(AL) == 10) {
3710: vram_flush();
3711: }
1.1.1.23! root 3712: WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ®8(AL), 1, &num, NULL);
1.1.1.14 root 3713: cursor_moved = true;
3714: } else {
1.1.1.16 root 3715: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
1.1.1.14 root 3716: if(mem[0x462] == REG8(BH)) {
3717: EnterCriticalSection(&vram_crit_sect);
1.1.1.16 root 3718: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 3719: write_text_vram_char(dest - vram, REG8(AL));
3720: LeaveCriticalSection(&vram_crit_sect);
3721:
1.1.1.23! root 3722: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 3723: if(++co.X == scr_width) {
3724: co.X = 0;
3725: if(++co.Y == scr_height) {
3726: vram_flush();
3727: WriteConsole(hStdout, "\n", 1, &num, NULL);
3728: cursor_moved = true;
3729: }
3730: }
3731: if(!cursor_moved) {
3732: co.Y += scr_top;
3733: SetConsoleCursorPosition(hStdout, co);
3734: cursor_moved = true;
3735: }
3736: }
3737: mem[dest] = REG8(AL);
3738: }
1.1 root 3739: }
3740:
3741: inline void pcbios_int_10h_0fh()
3742: {
3743: REG8(AL) = mem[0x449];
3744: REG8(AH) = mem[0x44a];
3745: REG8(BH) = mem[0x462];
3746: }
3747:
1.1.1.14 root 3748: inline void pcbios_int_10h_11h()
3749: {
3750: switch(REG8(AL)) {
1.1.1.16 root 3751: case 0x01:
1.1.1.14 root 3752: case 0x11:
1.1.1.16 root 3753: pcbios_set_console_size(80, 28, true);
1.1.1.14 root 3754: break;
1.1.1.16 root 3755: case 0x02:
1.1.1.14 root 3756: case 0x12:
1.1.1.16 root 3757: pcbios_set_console_size(80, 50, true);
1.1.1.14 root 3758: break;
1.1.1.16 root 3759: case 0x04:
1.1.1.14 root 3760: case 0x14:
1.1.1.16 root 3761: pcbios_set_console_size(80, 25, true);
3762: break;
3763: case 0x18:
3764: pcbios_set_console_size(80, 50, true);
1.1.1.14 root 3765: break;
3766: case 0x30:
3767: SREG(ES) = 0;
3768: i386_load_segment_descriptor(ES);
3769: REG16(BP) = 0;
3770: REG16(CX) = mem[0x485];
3771: REG8(DL) = mem[0x484];
3772: break;
3773: }
3774: }
3775:
3776: inline void pcbios_int_10h_12h()
3777: {
1.1.1.16 root 3778: switch(REG8(BL)) {
3779: case 0x10:
1.1.1.14 root 3780: REG16(BX) = 0x0003;
3781: REG16(CX) = 0x0009;
1.1.1.16 root 3782: break;
1.1.1.14 root 3783: }
3784: }
3785:
1.1 root 3786: inline void pcbios_int_10h_13h()
3787: {
1.1.1.3 root 3788: int ofs = SREG_BASE(ES) + REG16(BP);
1.1 root 3789: COORD co;
3790: DWORD num;
3791:
3792: co.X = REG8(DL);
1.1.1.14 root 3793: co.Y = REG8(DH) + scr_top;
3794:
3795: vram_flush();
1.1 root 3796:
3797: switch(REG8(AL)) {
3798: case 0x00:
3799: case 0x01:
3800: if(mem[0x462] == REG8(BH)) {
1.1.1.23! root 3801: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 3802: CONSOLE_SCREEN_BUFFER_INFO csbi;
3803: GetConsoleScreenBufferInfo(hStdout, &csbi);
3804: SetConsoleCursorPosition(hStdout, co);
3805:
3806: if(csbi.wAttributes != REG8(BL)) {
3807: SetConsoleTextAttribute(hStdout, REG8(BL));
3808: }
1.1.1.14 root 3809: WriteConsole(hStdout, &mem[ofs], REG16(CX), &num, NULL);
3810:
1.1 root 3811: if(csbi.wAttributes != REG8(BL)) {
3812: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
3813: }
3814: if(REG8(AL) == 0x00) {
1.1.1.15 root 3815: if(!restore_console_on_exit) {
3816: GetConsoleScreenBufferInfo(hStdout, &csbi);
3817: scr_top = csbi.srWindow.Top;
3818: }
1.1.1.14 root 3819: co.X = mem[0x450 + REG8(BH) * 2];
3820: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 3821: SetConsoleCursorPosition(hStdout, co);
3822: } else {
3823: cursor_moved = true;
3824: }
3825: } else {
1.1.1.3 root 3826: m_CF = 1;
1.1 root 3827: }
3828: break;
3829: case 0x02:
3830: case 0x03:
3831: if(mem[0x462] == REG8(BH)) {
1.1.1.23! root 3832: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 3833: CONSOLE_SCREEN_BUFFER_INFO csbi;
3834: GetConsoleScreenBufferInfo(hStdout, &csbi);
3835: SetConsoleCursorPosition(hStdout, co);
3836:
3837: WORD wAttributes = csbi.wAttributes;
3838: for(int i = 0; i < REG16(CX); i++, ofs += 2) {
3839: if(wAttributes != mem[ofs + 1]) {
3840: SetConsoleTextAttribute(hStdout, mem[ofs + 1]);
3841: wAttributes = mem[ofs + 1];
3842: }
1.1.1.14 root 3843: WriteConsole(hStdout, &mem[ofs], 1, &num, NULL);
1.1 root 3844: }
3845: if(csbi.wAttributes != wAttributes) {
3846: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
3847: }
3848: if(REG8(AL) == 0x02) {
1.1.1.14 root 3849: co.X = mem[0x450 + REG8(BH) * 2];
3850: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 3851: SetConsoleCursorPosition(hStdout, co);
3852: } else {
3853: cursor_moved = true;
3854: }
3855: } else {
1.1.1.3 root 3856: m_CF = 1;
1.1 root 3857: }
3858: break;
3859: case 0x10:
3860: case 0x11:
3861: if(mem[0x462] == REG8(BH)) {
1.1.1.23! root 3862: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 3863: ReadConsoleOutputCharacter(hStdout, scr_char, REG16(CX), co, &num);
3864: ReadConsoleOutputAttribute(hStdout, scr_attr, REG16(CX), co, &num);
3865: for(int i = 0; i < num; i++) {
3866: mem[ofs++] = scr_char[i];
3867: mem[ofs++] = scr_attr[i];
3868: if(REG8(AL) == 0x11) {
3869: mem[ofs++] = 0;
3870: mem[ofs++] = 0;
3871: }
3872: }
3873: } else {
1.1.1.16 root 3874: 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 3875: mem[ofs++] = mem[src++];
3876: mem[ofs++] = mem[src++];
3877: if(REG8(AL) == 0x11) {
3878: mem[ofs++] = 0;
3879: mem[ofs++] = 0;
3880: }
1.1.1.14 root 3881: if(++co.X == scr_width) {
3882: if(++co.Y == scr_height) {
1.1 root 3883: break;
3884: }
3885: co.X = 0;
3886: }
3887: }
3888: }
3889: break;
3890: case 0x20:
3891: case 0x21:
3892: if(mem[0x462] == REG8(BH)) {
1.1.1.23! root 3893: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 3894: int len = min(REG16(CX), scr_width * scr_height);
3895: for(int i = 0; i < len; i++) {
1.1 root 3896: scr_char[i] = mem[ofs++];
3897: scr_attr[i] = mem[ofs++];
3898: if(REG8(AL) == 0x21) {
3899: ofs += 2;
3900: }
3901: }
1.1.1.14 root 3902: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
3903: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 3904: } else {
1.1.1.16 root 3905: 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 3906: mem[dest++] = mem[ofs++];
3907: mem[dest++] = mem[ofs++];
3908: if(REG8(AL) == 0x21) {
3909: ofs += 2;
3910: }
1.1.1.14 root 3911: if(++co.X == scr_width) {
3912: if(++co.Y == scr_height) {
1.1 root 3913: break;
3914: }
3915: co.X = 0;
3916: }
3917: }
3918: }
3919: break;
3920: default:
1.1.1.22 root 3921: 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 3922: m_CF = 1;
1.1 root 3923: break;
3924: }
3925: }
3926:
1.1.1.14 root 3927: inline void pcbios_int_10h_1ah()
3928: {
3929: switch(REG8(AL)) {
3930: case 0x00:
3931: REG8(AL) = 0x1a;
3932: REG8(BL) = 0x08;
3933: REG8(BH) = 0x00;
3934: break;
3935: default:
1.1.1.22 root 3936: 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 3937: m_CF = 1;
3938: break;
3939: }
3940: }
3941:
1.1 root 3942: inline void pcbios_int_10h_1dh()
3943: {
3944: switch(REG8(AL)) {
3945: case 0x01:
3946: break;
3947: case 0x02:
3948: REG16(BX) = 0;
3949: break;
3950: default:
1.1.1.22 root 3951: 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));
3952: m_CF = 1;
3953: break;
3954: }
3955: }
3956:
3957: inline void pcbios_int_10h_4fh()
3958: {
3959: switch(REG8(AL)) {
3960: case 0x00:
3961: REG8(AH) = 0x02; // not supported
3962: break;
3963: case 0x01:
3964: case 0x02:
3965: case 0x03:
3966: case 0x04:
3967: case 0x05:
3968: case 0x06:
3969: case 0x07:
3970: case 0x08:
3971: case 0x09:
3972: case 0x0a:
3973: case 0x0b:
3974: case 0x0c:
3975: REG8(AH) = 0x01; // failed
3976: break;
3977: default:
3978: 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 3979: m_CF = 1;
1.1 root 3980: break;
3981: }
3982: }
3983:
3984: inline void pcbios_int_10h_82h()
3985: {
3986: static UINT8 mode = 0;
3987:
3988: switch(REG8(AL)) {
1.1.1.22 root 3989: case 0x00:
1.1 root 3990: if(REG8(BL) != 0xff) {
3991: mode = REG8(BL);
3992: }
3993: REG8(AL) = mode;
3994: break;
3995: default:
1.1.1.22 root 3996: 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 3997: m_CF = 1;
1.1 root 3998: break;
3999: }
4000: }
4001:
1.1.1.22 root 4002: inline void pcbios_int_10h_83h()
4003: {
4004: static UINT8 mode = 0;
4005:
4006: switch(REG8(AL)) {
4007: case 0x00:
4008: REG16(AX) = 0; // offset???
4009: SREG(ES) = (SHADOW_BUF_TOP >> 4);
4010: i386_load_segment_descriptor(ES);
4011: REG16(BX) = (SHADOW_BUF_TOP & 0x0f);
4012: break;
4013: default:
4014: 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));
4015: m_CF = 1;
4016: break;
4017: }
4018: }
4019:
4020: inline void pcbios_int_10h_90h()
4021: {
4022: REG8(AL) = mem[0x449];
4023: }
4024:
4025: inline void pcbios_int_10h_91h()
4026: {
4027: REG8(AL) = 0x04; // VGA
4028: }
4029:
4030: inline void pcbios_int_10h_efh()
4031: {
4032: REG16(DX) = 0xffff;
4033: }
4034:
1.1 root 4035: inline void pcbios_int_10h_feh()
4036: {
4037: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 4038: SREG(ES) = (SHADOW_BUF_TOP >> 4);
1.1.1.3 root 4039: i386_load_segment_descriptor(ES);
1.1.1.8 root 4040: REG16(DI) = (SHADOW_BUF_TOP & 0x0f);
1.1 root 4041: }
4042: int_10h_feh_called = true;
4043: }
4044:
4045: inline void pcbios_int_10h_ffh()
4046: {
4047: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.23! root 4048: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 4049: COORD co;
4050: DWORD num;
4051:
1.1.1.14 root 4052: vram_flush();
4053:
4054: co.X = (REG16(DI) >> 1) % scr_width;
4055: co.Y = (REG16(DI) >> 1) / scr_width;
1.1.1.16 root 4056: int ofs = pcbios_get_shadow_buffer_address(0, co.X, co.Y);
4057: int end = min(ofs + REG16(CX) * 2, pcbios_get_shadow_buffer_address(0, 0, scr_height));
1.1.1.14 root 4058: int len;
4059: for(len = 0; ofs < end; len++) {
4060: scr_char[len] = mem[ofs++];
4061: scr_attr[len] = mem[ofs++];
4062: }
4063: co.Y += scr_top;
4064: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
4065: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 4066: }
4067: int_10h_ffh_called = true;
4068: }
4069:
1.1.1.14 root 4070: inline void pcbios_int_15h_10h()
4071: {
1.1.1.22 root 4072: switch(REG8(AL)) {
4073: case 0x00:
1.1.1.14 root 4074: Sleep(10);
4075: hardware_update();
1.1.1.22 root 4076: break;
4077: default:
4078: 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 4079: REG8(AH) = 0x86;
4080: m_CF = 1;
4081: }
4082: }
4083:
1.1 root 4084: inline void pcbios_int_15h_23h()
4085: {
4086: switch(REG8(AL)) {
1.1.1.22 root 4087: case 0x00:
1.1.1.8 root 4088: REG8(CL) = cmos_read(0x2d);
4089: REG8(CH) = cmos_read(0x2e);
1.1 root 4090: break;
1.1.1.22 root 4091: case 0x01:
1.1.1.8 root 4092: cmos_write(0x2d, REG8(CL));
4093: cmos_write(0x2e, REG8(CH));
1.1 root 4094: break;
4095: default:
1.1.1.22 root 4096: 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 4097: REG8(AH) = 0x86;
1.1.1.3 root 4098: m_CF = 1;
1.1 root 4099: break;
4100: }
4101: }
4102:
4103: inline void pcbios_int_15h_24h()
4104: {
4105: switch(REG8(AL)) {
1.1.1.22 root 4106: case 0x00:
1.1.1.3 root 4107: i386_set_a20_line(0);
1.1 root 4108: REG8(AH) = 0;
4109: break;
1.1.1.22 root 4110: case 0x01:
1.1.1.3 root 4111: i386_set_a20_line(1);
1.1 root 4112: REG8(AH) = 0;
4113: break;
1.1.1.22 root 4114: case 0x02:
1.1 root 4115: REG8(AH) = 0;
1.1.1.3 root 4116: REG8(AL) = (m_a20_mask >> 20) & 1;
1.1 root 4117: REG16(CX) = 0;
4118: break;
1.1.1.22 root 4119: case 0x03:
1.1 root 4120: REG16(AX) = 0;
4121: REG16(BX) = 0;
4122: break;
1.1.1.22 root 4123: default:
4124: 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));
4125: REG8(AH) = 0x86;
4126: m_CF = 1;
4127: break;
1.1 root 4128: }
4129: }
4130:
4131: inline void pcbios_int_15h_49h()
4132: {
1.1.1.14 root 4133: REG8(AH) = 0;
4134: REG8(BL) = 0; // DOS/V
1.1 root 4135: }
4136:
1.1.1.22 root 4137: inline void pcbios_int_15h_50h()
4138: {
4139: switch(REG8(AL)) {
4140: case 0x00:
4141: case 0x01:
4142: if(REG8(BH) != 0x00 && REG8(BH) != 0x01) {
4143: REG8(AH) = 0x01; // invalid font type in bh
4144: m_CF = 1;
4145: } else if(REG8(BL) != 0) {
4146: REG8(AH) = 0x02; // bl not zero
4147: m_CF = 1;
4148: } else if(REG16(BP) != 0 && REG16(BP) != 437 && REG16(BP) != 932 && REG16(BP) != 934 && REG16(BP) != 936 && REG16(BP) != 938) {
4149: REG8(AH) = 0x04; // invalid code page
4150: m_CF = 1;
4151: } else {
4152: REG8(AH) = 0x86; // finally, this function is not supported
4153: m_CF = 1;
4154: }
4155: break;
4156: default:
4157: 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));
4158: REG8(AH) = 0x86;
4159: m_CF = 1;
4160: break;
4161: }
4162: }
4163:
1.1 root 4164: inline void pcbios_int_15h_86h()
4165: {
4166: UINT32 usec = (REG16(CX) << 16) | REG16(DX);
1.1.1.14 root 4167: UINT32 msec = usec / 1000;
4168:
4169: while(msec) {
4170: UINT32 tmp = min(msec, 100);
4171: if(msec - tmp < 10) {
4172: tmp = msec;
4173: }
4174: Sleep(tmp);
4175:
4176: if(m_halted) {
4177: return;
4178: }
4179: msec -= tmp;
4180: }
1.1 root 4181: }
4182:
4183: inline void pcbios_int_15h_87h()
4184: {
4185: // copy extended memory (from DOSBox)
4186: int len = REG16(CX) * 2;
1.1.1.3 root 4187: int ofs = SREG_BASE(ES) + REG16(SI);
1.1 root 4188: int src = (*(UINT32 *)(mem + ofs + 0x12) & 0xffffff); // + (mem[ofs + 0x16] << 24);
4189: int dst = (*(UINT32 *)(mem + ofs + 0x1a) & 0xffffff); // + (mem[ofs + 0x1e] << 24);
4190: memcpy(mem + dst, mem + src, len);
4191: REG16(AX) = 0x00;
4192: }
4193:
4194: inline void pcbios_int_15h_88h()
4195: {
1.1.1.17 root 4196: REG16(AX) = ((min(MAX_MEM, 0x4000000) - 0x100000) >> 10);
1.1 root 4197: }
4198:
4199: inline void pcbios_int_15h_89h()
4200: {
1.1.1.21 root 4201: #if defined(HAS_I286) || defined(HAS_I386)
1.1 root 4202: // switch to protected mode (from DOSBox)
4203: write_io_byte(0x20, 0x10);
4204: write_io_byte(0x21, REG8(BH));
4205: write_io_byte(0x21, 0x00);
4206: write_io_byte(0xa0, 0x10);
4207: write_io_byte(0xa1, REG8(BL));
4208: write_io_byte(0xa1, 0x00);
1.1.1.3 root 4209: i386_set_a20_line(1);
4210: int ofs = SREG_BASE(ES) + REG16(SI);
4211: m_gdtr.limit = *(UINT16 *)(mem + ofs + 0x08);
4212: m_gdtr.base = *(UINT32 *)(mem + ofs + 0x08 + 0x02) & 0xffffff;
4213: m_idtr.limit = *(UINT16 *)(mem + ofs + 0x10);
4214: m_idtr.base = *(UINT32 *)(mem + ofs + 0x10 + 0x02) & 0xffffff;
4215: #if defined(HAS_I386)
4216: m_cr[0] |= 1;
4217: #else
4218: m_msw |= 1;
4219: #endif
4220: SREG(DS) = 0x18;
4221: SREG(ES) = 0x20;
4222: SREG(SS) = 0x28;
4223: i386_load_segment_descriptor(DS);
4224: i386_load_segment_descriptor(ES);
4225: i386_load_segment_descriptor(SS);
1.1.1.21 root 4226: UINT16 offset = *(UINT16 *)(mem + SREG_BASE(SS) + REG16(SP));
1.1 root 4227: REG16(SP) += 6;
1.1.1.3 root 4228: #if defined(HAS_I386)
1.1.1.21 root 4229: UINT32 flags = get_flags();
4230: flags &= (0x20000 | 0x40000 | 0x80000 | 0x100000 | 0x200000);
4231: set_flags(flags);
1.1.1.3 root 4232: #else
1.1.1.21 root 4233: UINT32 flags = CompressFlags();
4234: flags &= (0x20000 | 0x40000 | 0x80000 | 0x100000 | 0x200000);
4235: ExpandFlags(flags);
1.1.1.3 root 4236: #endif
1.1 root 4237: REG16(AX) = 0x00;
1.1.1.21 root 4238: i386_jmp_far(0x30, /*REG16(CX)*/offset);
1.1 root 4239: #else
1.1.1.21 root 4240: // i86/i186/v30: protected mode is not supported
1.1 root 4241: REG8(AH) = 0x86;
1.1.1.3 root 4242: m_CF = 1;
1.1 root 4243: #endif
4244: }
4245:
1.1.1.21 root 4246: inline void pcbios_int_15h_8ah()
4247: {
4248: UINT32 size = MAX_MEM - 0x100000;
4249: REG16(AX) = size & 0xffff;
4250: REG16(DX) = size >> 16;
4251: }
4252:
1.1.1.3 root 4253: #if defined(HAS_I386)
1.1 root 4254: inline void pcbios_int_15h_c9h()
4255: {
4256: REG8(AH) = 0x00;
4257: REG8(CH) = cpu_type;
4258: REG8(CL) = cpu_step;
4259: }
1.1.1.3 root 4260: #endif
1.1 root 4261:
4262: inline void pcbios_int_15h_cah()
4263: {
4264: switch(REG8(AL)) {
1.1.1.22 root 4265: case 0x00:
1.1 root 4266: if(REG8(BL) > 0x3f) {
4267: REG8(AH) = 0x03;
1.1.1.3 root 4268: m_CF = 1;
1.1 root 4269: } else if(REG8(BL) < 0x0e) {
4270: REG8(AH) = 0x04;
1.1.1.3 root 4271: m_CF = 1;
1.1 root 4272: } else {
1.1.1.8 root 4273: REG8(CL) = cmos_read(REG8(BL));
1.1 root 4274: }
4275: break;
1.1.1.22 root 4276: case 0x01:
1.1 root 4277: if(REG8(BL) > 0x3f) {
4278: REG8(AH) = 0x03;
1.1.1.3 root 4279: m_CF = 1;
1.1 root 4280: } else if(REG8(BL) < 0x0e) {
4281: REG8(AH) = 0x04;
1.1.1.3 root 4282: m_CF = 1;
1.1 root 4283: } else {
1.1.1.8 root 4284: cmos_write(REG8(BL), REG8(CL));
1.1 root 4285: }
4286: break;
4287: default:
1.1.1.22 root 4288: 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 4289: REG8(AH) = 0x86;
1.1.1.3 root 4290: m_CF = 1;
1.1 root 4291: break;
4292: }
4293: }
4294:
1.1.1.22 root 4295: inline void pcbios_int_15h_e8h()
1.1.1.17 root 4296: {
1.1.1.22 root 4297: switch(REG8(AL)) {
4298: #if defined(HAS_I386)
4299: case 0x01:
4300: REG16(AX) = REG16(CX) = ((min(MAX_MEM, 0x1000000) - 0x100000) >> 10);
4301: REG16(BX) = REG16(DX) = ((max(MAX_MEM, 0x1000000) - 0x1000000) >> 16);
4302: break;
1.1.1.17 root 4303: #endif
1.1.1.22 root 4304: default:
4305: 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));
4306: REG8(AH) = 0x86;
4307: m_CF = 1;
4308: break;
4309: }
4310: }
1.1.1.17 root 4311:
1.1.1.16 root 4312: UINT32 pcbios_get_key_code(bool clear_buffer)
1.1 root 4313: {
4314: UINT32 code = 0;
4315:
4316: if(key_buf_char->count() == 0) {
1.1.1.14 root 4317: if(!update_key_buffer()) {
4318: if(clear_buffer) {
4319: Sleep(10);
4320: } else {
4321: maybe_idle();
4322: }
4323: }
1.1 root 4324: }
4325: if(!clear_buffer) {
4326: key_buf_char->store_buffer();
4327: key_buf_scan->store_buffer();
4328: }
4329: if(key_buf_char->count() != 0) {
4330: code = key_buf_char->read() | (key_buf_scan->read() << 8);
4331: }
4332: if(key_buf_char->count() != 0) {
4333: code |= (key_buf_char->read() << 16) | (key_buf_scan->read() << 24);
4334: }
4335: if(!clear_buffer) {
4336: key_buf_char->restore_buffer();
4337: key_buf_scan->restore_buffer();
4338: }
4339: return code;
4340: }
4341:
4342: inline void pcbios_int_16h_00h()
4343: {
1.1.1.14 root 4344: while(key_code == 0 && !m_halted) {
1.1.1.16 root 4345: key_code = pcbios_get_key_code(true);
1.1 root 4346: }
4347: if((key_code & 0xffff) == 0x0000 || (key_code & 0xffff) == 0xe000) {
4348: if(REG8(AH) == 0x10) {
4349: key_code = ((key_code >> 8) & 0xff) | ((key_code >> 16) & 0xff00);
4350: } else {
4351: key_code = ((key_code >> 16) & 0xff00);
4352: }
4353: }
4354: REG16(AX) = key_code & 0xffff;
4355: key_code >>= 16;
4356: }
4357:
4358: inline void pcbios_int_16h_01h()
4359: {
1.1.1.5 root 4360: UINT32 key_code_tmp = key_code;
1.1 root 4361:
1.1.1.5 root 4362: if(key_code_tmp == 0) {
1.1.1.16 root 4363: key_code_tmp = pcbios_get_key_code(false);
1.1.1.5 root 4364: }
1.1.1.14 root 4365: if((key_code_tmp & 0xffff) == 0x0000 || (key_code_tmp & 0xffff) == 0xe000) {
4366: if(REG8(AH) == 0x11) {
4367: key_code_tmp = ((key_code_tmp >> 8) & 0xff) | ((key_code_tmp >> 16) & 0xff00);
4368: } else {
4369: key_code_tmp = ((key_code_tmp >> 16) & 0xff00);
1.1 root 4370: }
4371: }
1.1.1.5 root 4372: if(key_code_tmp != 0) {
4373: REG16(AX) = key_code_tmp & 0xffff;
1.1 root 4374: }
1.1.1.3 root 4375: #if defined(HAS_I386)
1.1.1.5 root 4376: m_ZF = (key_code_tmp == 0);
1.1.1.3 root 4377: #else
1.1.1.5 root 4378: m_ZeroVal = (key_code_tmp != 0);
1.1.1.3 root 4379: #endif
1.1 root 4380: }
4381:
4382: inline void pcbios_int_16h_02h()
4383: {
4384: REG8(AL) = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
4385: REG8(AL) |= (GetAsyncKeyState(VK_CAPITAL) & 0x0001) ? 0x40 : 0;
4386: REG8(AL) |= (GetAsyncKeyState(VK_NUMLOCK) & 0x0001) ? 0x20 : 0;
4387: REG8(AL) |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
4388: REG8(AL) |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
4389: REG8(AL) |= (GetAsyncKeyState(VK_CONTROL) & 0x8000) ? 0x04 : 0;
4390: REG8(AL) |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
4391: REG8(AL) |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
4392: }
4393:
4394: inline void pcbios_int_16h_03h()
4395: {
4396: static UINT16 status = 0;
4397:
4398: switch(REG8(AL)) {
4399: case 0x05:
4400: status = REG16(BX);
4401: break;
4402: case 0x06:
4403: REG16(BX) = status;
4404: break;
4405: default:
1.1.1.3 root 4406: m_CF = 1;
1.1 root 4407: break;
4408: }
4409: }
4410:
4411: inline void pcbios_int_16h_05h()
4412: {
1.1.1.14 root 4413: key_buf_char->write(REG8(CL));
4414: key_buf_scan->write(REG8(CH));
1.1 root 4415: REG8(AL) = 0x00;
4416: }
4417:
4418: inline void pcbios_int_16h_12h()
4419: {
4420: pcbios_int_16h_02h();
4421:
4422: REG8(AH) = 0;//(GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x80 : 0;
4423: REG8(AH) |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
4424: REG8(AH) |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
4425: REG8(AH) |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
4426: REG8(AH) |= (GetAsyncKeyState(VK_RMENU ) & 0x8000) ? 0x08 : 0;
4427: REG8(AH) |= (GetAsyncKeyState(VK_RCONTROL) & 0x8000) ? 0x04 : 0;
4428: REG8(AH) |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
4429: REG8(AH) |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
4430: }
4431:
4432: inline void pcbios_int_16h_13h()
4433: {
4434: static UINT16 status = 0;
4435:
4436: switch(REG8(AL)) {
4437: case 0x00:
4438: status = REG16(DX);
4439: break;
4440: case 0x01:
4441: REG16(DX) = status;
4442: break;
4443: default:
1.1.1.22 root 4444: 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 4445: m_CF = 1;
1.1 root 4446: break;
4447: }
4448: }
4449:
4450: inline void pcbios_int_16h_14h()
4451: {
4452: static UINT8 status = 0;
4453:
4454: switch(REG8(AL)) {
4455: case 0x00:
4456: case 0x01:
4457: status = REG8(AL);
4458: break;
4459: case 0x02:
4460: REG8(AL) = status;
4461: break;
4462: default:
1.1.1.22 root 4463: 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 4464: m_CF = 1;
1.1 root 4465: break;
4466: }
4467: }
4468:
4469: inline void pcbios_int_1ah_00h()
4470: {
1.1.1.19 root 4471: pcbios_update_daily_timer_counter(timeGetTime());
4472: REG16(CX) = *(UINT16 *)(mem + 0x46e);
4473: REG16(DX) = *(UINT16 *)(mem + 0x46c);
4474: REG8(AL) = mem[0x470];
4475: mem[0x470] = 0;
1.1 root 4476: }
4477:
4478: inline int to_bcd(int t)
4479: {
4480: int u = (t % 100) / 10;
4481: return (u << 4) | (t % 10);
4482: }
4483:
4484: inline void pcbios_int_1ah_02h()
4485: {
4486: SYSTEMTIME time;
4487:
4488: GetLocalTime(&time);
4489: REG8(CH) = to_bcd(time.wHour);
4490: REG8(CL) = to_bcd(time.wMinute);
4491: REG8(DH) = to_bcd(time.wSecond);
4492: REG8(DL) = 0x00;
4493: }
4494:
4495: inline void pcbios_int_1ah_04h()
4496: {
4497: SYSTEMTIME time;
4498:
4499: GetLocalTime(&time);
4500: REG8(CH) = to_bcd(time.wYear / 100);
4501: REG8(CL) = to_bcd(time.wYear);
4502: REG8(DH) = to_bcd(time.wMonth);
4503: REG8(DL) = to_bcd(time.wDay);
4504: }
4505:
4506: inline void pcbios_int_1ah_0ah()
4507: {
4508: SYSTEMTIME time;
4509: FILETIME file_time;
4510: WORD dos_date, dos_time;
4511:
4512: GetLocalTime(&time);
4513: SystemTimeToFileTime(&time, &file_time);
4514: FileTimeToDosDateTime(&file_time, &dos_date, &dos_time);
4515: REG16(CX) = dos_date;
4516: }
4517:
4518: // msdos system call
4519:
4520: inline void msdos_int_21h_00h()
4521: {
1.1.1.3 root 4522: msdos_process_terminate(SREG(CS), retval, 1);
1.1 root 4523: }
4524:
4525: inline void msdos_int_21h_01h()
4526: {
4527: REG8(AL) = msdos_getche();
1.1.1.8 root 4528: // some seconds may be passed in console
1.1 root 4529: hardware_update();
4530: }
4531:
4532: inline void msdos_int_21h_02h()
4533: {
4534: msdos_putch(REG8(DL));
4535: }
4536:
4537: inline void msdos_int_21h_03h()
4538: {
4539: REG8(AL) = msdos_aux_in();
4540: }
4541:
4542: inline void msdos_int_21h_04h()
4543: {
4544: msdos_aux_out(REG8(DL));
4545: }
4546:
4547: inline void msdos_int_21h_05h()
4548: {
4549: msdos_prn_out(REG8(DL));
4550: }
4551:
4552: inline void msdos_int_21h_06h()
4553: {
4554: if(REG8(DL) == 0xff) {
4555: if(msdos_kbhit()) {
4556: REG8(AL) = msdos_getch();
1.1.1.3 root 4557: #if defined(HAS_I386)
4558: m_ZF = 0;
4559: #else
4560: m_ZeroVal = 1;
4561: #endif
1.1 root 4562: } else {
4563: REG8(AL) = 0;
1.1.1.3 root 4564: #if defined(HAS_I386)
4565: m_ZF = 1;
4566: #else
4567: m_ZeroVal = 0;
4568: #endif
1.1.1.14 root 4569: maybe_idle();
1.1 root 4570: }
4571: } else {
4572: msdos_putch(REG8(DL));
4573: }
4574: }
4575:
4576: inline void msdos_int_21h_07h()
4577: {
4578: REG8(AL) = msdos_getch();
1.1.1.8 root 4579: // some seconds may be passed in console
1.1 root 4580: hardware_update();
4581: }
4582:
4583: inline void msdos_int_21h_08h()
4584: {
4585: REG8(AL) = msdos_getch();
1.1.1.8 root 4586: // some seconds may be passed in console
1.1 root 4587: hardware_update();
4588: }
4589:
4590: inline void msdos_int_21h_09h()
4591: {
1.1.1.21 root 4592: msdos_stdio_reopen();
4593:
1.1.1.20 root 4594: process_t *process = msdos_process_info_get(current_psp);
4595: int fd = msdos_psp_get_file_table(1, current_psp);
4596:
1.1.1.14 root 4597: char *str = (char *)(mem + SREG_BASE(DS) + REG16(DX));
4598: int len = 0;
1.1 root 4599:
1.1.1.14 root 4600: while(str[len] != '$' && len < 0x10000) {
4601: len++;
4602: }
1.1.1.20 root 4603: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 4604: // stdout is redirected to file
1.1.1.20 root 4605: msdos_write(fd, str, len);
1.1 root 4606: } else {
4607: for(int i = 0; i < len; i++) {
1.1.1.14 root 4608: msdos_putch(str[i]);
1.1 root 4609: }
4610: }
4611: }
4612:
4613: inline void msdos_int_21h_0ah()
4614: {
1.1.1.3 root 4615: int ofs = SREG_BASE(DS) + REG16(DX);
1.1 root 4616: int max = mem[ofs] - 1;
4617: UINT8 *buf = mem + ofs + 2;
4618: int chr, p = 0;
4619:
4620: while((chr = msdos_getch()) != 0x0d) {
4621: if(chr == 0x00) {
4622: // skip 2nd byte
4623: msdos_getch();
4624: } else if(chr == 0x08) {
4625: // back space
4626: if(p > 0) {
4627: p--;
1.1.1.20 root 4628: if(msdos_ctrl_code_check(buf[p])) {
4629: msdos_putch(chr);
4630: msdos_putch(chr);
4631: msdos_putch(' ');
4632: msdos_putch(' ');
4633: msdos_putch(chr);
4634: msdos_putch(chr);
4635: } else {
4636: msdos_putch(chr);
4637: msdos_putch(' ');
4638: msdos_putch(chr);
4639: }
1.1 root 4640: }
4641: } else if(p < max) {
4642: buf[p++] = chr;
4643: msdos_putch(chr);
4644: }
4645: }
4646: buf[p] = 0x0d;
4647: mem[ofs + 1] = p;
1.1.1.8 root 4648: // some seconds may be passed in console
1.1 root 4649: hardware_update();
4650: }
4651:
4652: inline void msdos_int_21h_0bh()
4653: {
4654: if(msdos_kbhit()) {
4655: REG8(AL) = 0xff;
4656: } else {
4657: REG8(AL) = 0x00;
1.1.1.14 root 4658: maybe_idle();
1.1 root 4659: }
4660: }
4661:
4662: inline void msdos_int_21h_0ch()
4663: {
4664: // clear key buffer
1.1.1.21 root 4665: msdos_stdio_reopen();
4666:
1.1.1.20 root 4667: process_t *process = msdos_process_info_get(current_psp);
4668: int fd = msdos_psp_get_file_table(0, current_psp);
4669:
4670: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 4671: // stdin is redirected to file
4672: } else {
4673: while(msdos_kbhit()) {
4674: msdos_getch();
4675: }
4676: }
4677:
4678: switch(REG8(AL)) {
4679: case 0x01:
4680: msdos_int_21h_01h();
4681: break;
4682: case 0x06:
4683: msdos_int_21h_06h();
4684: break;
4685: case 0x07:
4686: msdos_int_21h_07h();
4687: break;
4688: case 0x08:
4689: msdos_int_21h_08h();
4690: break;
4691: case 0x0a:
4692: msdos_int_21h_0ah();
4693: break;
4694: default:
1.1.1.22 root 4695: // 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));
4696: // REG16(AX) = 0x01;
4697: // m_CF = 1;
1.1 root 4698: break;
4699: }
4700: }
4701:
4702: inline void msdos_int_21h_0dh()
4703: {
4704: }
4705:
4706: inline void msdos_int_21h_0eh()
4707: {
4708: if(REG8(DL) < 26) {
4709: _chdrive(REG8(DL) + 1);
4710: msdos_cds_update(REG8(DL));
1.1.1.23! root 4711: msdos_sda_update(current_psp);
1.1 root 4712: }
4713: REG8(AL) = 26; // zdrive
4714: }
4715:
1.1.1.14 root 4716: inline void msdos_int_21h_0fh()
4717: {
4718: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4719: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
4720: char *path = msdos_fcb_path(fcb);
4721: 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 4722:
1.1.1.14 root 4723: if(hFile == INVALID_HANDLE_VALUE) {
4724: REG8(AL) = 0xff;
4725: } else {
4726: REG8(AL) = 0;
4727: fcb->current_block = 0;
4728: fcb->record_size = 128;
4729: fcb->file_size = GetFileSize(hFile, NULL);
4730: fcb->handle = hFile;
4731: fcb->cur_record = 0;
4732: }
4733: }
4734:
4735: inline void msdos_int_21h_10h()
4736: {
4737: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4738: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
4739:
4740: REG8(AL) = CloseHandle(fcb->handle) ? 0 : 0xff;
4741: }
4742:
1.1 root 4743: inline void msdos_int_21h_11h()
4744: {
1.1.1.3 root 4745: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4746: fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 4747:
4748: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 4749: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
4750: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
4751: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 4752: char *path = msdos_fcb_path(fcb);
4753: WIN32_FIND_DATA fd;
4754:
1.1.1.13 root 4755: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
4756: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
4757: FindClose(dtainfo->find_handle);
4758: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 4759: }
4760: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 4761: dtainfo->allowable_mask = (ext_fcb->flag == 0xff) ? ext_fcb->attribute : 0x20;
4762: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 4763:
1.1.1.14 root 4764: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
4765: dtainfo->allowable_mask &= ~8;
1.1 root 4766: }
1.1.1.14 root 4767: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
4768: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 4769: !msdos_find_file_has_8dot3name(&fd)) {
4770: if(!FindNextFile(dtainfo->find_handle, &fd)) {
4771: FindClose(dtainfo->find_handle);
4772: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 4773: break;
4774: }
4775: }
4776: }
1.1.1.13 root 4777: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 4778: if(ext_fcb->flag == 0xff) {
4779: ext_find->flag = 0xff;
4780: memset(ext_find->reserved, 0, 5);
4781: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
4782: }
4783: find->drive = _getdrive();
1.1.1.13 root 4784: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 4785: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
4786: find->nt_res = 0;
4787: msdos_find_file_conv_local_time(&fd);
4788: find->create_time_ms = 0;
4789: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
4790: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
4791: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
4792: find->cluster_hi = find->cluster_lo = 0;
4793: find->file_size = fd.nFileSizeLow;
4794: REG8(AL) = 0x00;
1.1.1.14 root 4795: } else if(dtainfo->allowable_mask & 8) {
1.1 root 4796: if(ext_fcb->flag == 0xff) {
4797: ext_find->flag = 0xff;
4798: memset(ext_find->reserved, 0, 5);
4799: ext_find->attribute = 8;
4800: }
4801: find->drive = _getdrive();
4802: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
4803: find->attribute = 8;
4804: find->nt_res = 0;
4805: msdos_find_file_conv_local_time(&fd);
4806: find->create_time_ms = 0;
4807: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
4808: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
4809: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
4810: find->cluster_hi = find->cluster_lo = 0;
4811: find->file_size = 0;
1.1.1.14 root 4812: dtainfo->allowable_mask &= ~8;
1.1 root 4813: REG8(AL) = 0x00;
4814: } else {
4815: REG8(AL) = 0xff;
4816: }
4817: }
4818:
4819: inline void msdos_int_21h_12h()
4820: {
1.1.1.3 root 4821: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1.1.14 root 4822: // fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 4823:
4824: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 4825: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
4826: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
4827: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 4828: WIN32_FIND_DATA fd;
4829:
1.1.1.13 root 4830: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
4831: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
4832: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 4833: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 4834: !msdos_find_file_has_8dot3name(&fd)) {
4835: if(!FindNextFile(dtainfo->find_handle, &fd)) {
4836: FindClose(dtainfo->find_handle);
4837: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 4838: break;
4839: }
4840: }
4841: } else {
1.1.1.13 root 4842: FindClose(dtainfo->find_handle);
4843: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 4844: }
4845: }
1.1.1.13 root 4846: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 4847: if(ext_fcb->flag == 0xff) {
4848: ext_find->flag = 0xff;
4849: memset(ext_find->reserved, 0, 5);
4850: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
4851: }
4852: find->drive = _getdrive();
1.1.1.13 root 4853: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 4854: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
4855: find->nt_res = 0;
4856: msdos_find_file_conv_local_time(&fd);
4857: find->create_time_ms = 0;
4858: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
4859: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
4860: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
4861: find->cluster_hi = find->cluster_lo = 0;
4862: find->file_size = fd.nFileSizeLow;
4863: REG8(AL) = 0x00;
1.1.1.14 root 4864: } else if(dtainfo->allowable_mask & 8) {
1.1 root 4865: if(ext_fcb->flag == 0xff) {
4866: ext_find->flag = 0xff;
4867: memset(ext_find->reserved, 0, 5);
4868: ext_find->attribute = 8;
4869: }
4870: find->drive = _getdrive();
4871: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
4872: find->attribute = 8;
4873: find->nt_res = 0;
4874: msdos_find_file_conv_local_time(&fd);
4875: find->create_time_ms = 0;
4876: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
4877: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
4878: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
4879: find->cluster_hi = find->cluster_lo = 0;
4880: find->file_size = 0;
1.1.1.14 root 4881: dtainfo->allowable_mask &= ~8;
1.1 root 4882: REG8(AL) = 0x00;
4883: } else {
4884: REG8(AL) = 0xff;
4885: }
4886: }
4887:
4888: inline void msdos_int_21h_13h()
4889: {
1.1.1.3 root 4890: if(remove(msdos_fcb_path((fcb_t *)(mem + SREG_BASE(DS) + REG16(DX))))) {
1.1 root 4891: REG8(AL) = 0xff;
4892: } else {
4893: REG8(AL) = 0x00;
4894: }
4895: }
4896:
1.1.1.16 root 4897: inline void msdos_int_21h_14h()
4898: {
4899: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4900: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
4901: process_t *process = msdos_process_info_get(current_psp);
4902: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
4903: DWORD num = 0;
4904:
4905: memset(mem + dta_laddr, 0, fcb->record_size);
4906: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
4907: REG8(AL) = 1;
4908: } else {
4909: UINT32 position = fcb->current_block * fcb->record_size + fcb->cur_record + num;
4910: fcb->current_block = (position & 0xffffff) / fcb->record_size;
4911: fcb->cur_record = (position & 0xffffff) % fcb->record_size;
4912: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
4913: }
4914: }
4915:
4916: inline void msdos_int_21h_15h()
1.1.1.14 root 4917: {
4918: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4919: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.16 root 4920: process_t *process = msdos_process_info_get(current_psp);
4921: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
4922: DWORD num = 0;
1.1.1.14 root 4923:
1.1.1.16 root 4924: if(!WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
4925: REG8(AL) = 1;
4926: } else {
4927: fcb->file_size = GetFileSize(fcb->handle, NULL);
4928: UINT32 position = fcb->current_block * fcb->record_size + fcb->cur_record + num;
4929: fcb->current_block = (position & 0xffffff) / fcb->record_size;
4930: fcb->cur_record = (position & 0xffffff) % fcb->record_size;
4931: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
4932: }
4933: }
4934:
4935: inline void msdos_int_21h_16h()
4936: {
4937: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4938: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.14 root 4939: char *path = msdos_fcb_path(fcb);
4940: 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 4941:
1.1.1.14 root 4942: if(hFile == INVALID_HANDLE_VALUE) {
4943: REG8(AL) = 0xff;
4944: } else {
4945: REG8(AL) = 0;
4946: fcb->current_block = 0;
4947: fcb->record_size = 128;
4948: fcb->file_size = 0;
4949: fcb->handle = hFile;
4950: fcb->cur_record = 0;
4951: }
4952: }
4953:
1.1.1.16 root 4954: inline void msdos_int_21h_17h()
4955: {
4956: ext_fcb_t *ext_fcb_src = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4957: fcb_t *fcb_src = (fcb_t *)(ext_fcb_src + (ext_fcb_src->flag == 0xff ? 1 : 0));
4958: char *path_src = msdos_fcb_path(fcb_src);
4959: ext_fcb_t *ext_fcb_dst = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + 16);
4960: fcb_t *fcb_dst = (fcb_t *)(ext_fcb_dst + (ext_fcb_dst->flag == 0xff ? 1 : 0));
4961: char *path_dst = msdos_fcb_path(fcb_dst);
4962:
4963: if(rename(path_src, path_dst)) {
4964: REG8(AL) = 0xff;
4965: } else {
4966: REG8(AL) = 0;
4967: }
4968: }
4969:
1.1 root 4970: inline void msdos_int_21h_18h()
4971: {
4972: REG8(AL) = 0x00;
4973: }
4974:
4975: inline void msdos_int_21h_19h()
4976: {
4977: REG8(AL) = _getdrive() - 1;
4978: }
4979:
4980: inline void msdos_int_21h_1ah()
4981: {
4982: process_t *process = msdos_process_info_get(current_psp);
4983:
4984: process->dta.w.l = REG16(DX);
1.1.1.3 root 4985: process->dta.w.h = SREG(DS);
1.1.1.23! root 4986: msdos_sda_update(current_psp);
1.1 root 4987: }
4988:
4989: inline void msdos_int_21h_1bh()
4990: {
4991: int drive_num = _getdrive() - 1;
4992: UINT16 seg, ofs;
4993:
4994: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
4995: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
4996: REG8(AL) = dpb->highest_sector_num + 1;
4997: REG16(CX) = dpb->bytes_per_sector;
4998: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 4999: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 5000: } else {
5001: REG8(AL) = 0xff;
1.1.1.3 root 5002: m_CF = 1;
1.1 root 5003: }
5004:
5005: }
5006:
5007: inline void msdos_int_21h_1ch()
5008: {
5009: int drive_num = REG8(DL) ? (REG8(DL) - 1) : (_getdrive() - 1);
5010: UINT16 seg, ofs;
5011:
5012: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
5013: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
5014: REG8(AL) = dpb->highest_sector_num + 1;
5015: REG16(CX) = dpb->bytes_per_sector;
5016: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 5017: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 5018: } else {
5019: REG8(AL) = 0xff;
1.1.1.3 root 5020: m_CF = 1;
1.1 root 5021: }
5022:
5023: }
5024:
5025: inline void msdos_int_21h_1dh()
5026: {
5027: REG8(AL) = 0;
5028: }
5029:
5030: inline void msdos_int_21h_1eh()
5031: {
5032: REG8(AL) = 0;
5033: }
5034:
5035: inline void msdos_int_21h_1fh()
5036: {
5037: int drive_num = _getdrive() - 1;
5038: UINT16 seg, ofs;
5039:
5040: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
5041: REG8(AL) = 0;
1.1.1.3 root 5042: SREG(DS) = seg;
5043: i386_load_segment_descriptor(DS);
1.1 root 5044: REG16(BX) = ofs;
5045: } else {
5046: REG8(AL) = 0xff;
1.1.1.3 root 5047: m_CF = 1;
1.1 root 5048: }
5049: }
5050:
5051: inline void msdos_int_21h_20h()
5052: {
5053: REG8(AL) = 0;
5054: }
5055:
1.1.1.14 root 5056: inline void msdos_int_21h_21h()
5057: {
5058: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5059: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5060:
5061: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
5062: REG8(AL) = 1;
5063: } else {
5064: process_t *process = msdos_process_info_get(current_psp);
5065: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5066: memset(mem + dta_laddr, 0, fcb->record_size);
1.1.1.16 root 5067: DWORD num = 0;
1.1.1.14 root 5068: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
5069: REG8(AL) = 1;
5070: } else {
5071: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
5072: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
1.1.1.16 root 5073: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
1.1.1.14 root 5074: }
5075: }
5076: }
5077:
5078: inline void msdos_int_21h_22h()
5079: {
5080: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5081: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5082:
5083: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
5084: REG8(AL) = 0xff;
5085: } else {
5086: process_t *process = msdos_process_info_get(current_psp);
5087: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
1.1.1.16 root 5088: DWORD num = 0;
1.1.1.14 root 5089: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL);
5090: fcb->file_size = GetFileSize(fcb->handle, NULL);
5091: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
5092: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
1.1.1.16 root 5093: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
1.1.1.14 root 5094: }
5095: }
5096:
1.1.1.16 root 5097: inline void msdos_int_21h_23h()
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: char *path = msdos_fcb_path(fcb);
5102: HANDLE hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
5103:
5104: if(hFile == INVALID_HANDLE_VALUE) {
5105: REG8(AL) = 0xff;
5106: } else {
5107: UINT32 size = GetFileSize(hFile, NULL);
5108: fcb->rand_record = size / fcb->record_size + ((size % fcb->record_size) != 0);
5109: REG8(AL) = 0;
5110: }
5111: }
5112:
5113: inline void msdos_int_21h_24h()
5114: {
5115: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5116: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5117:
5118: fcb->rand_record = fcb->current_block * fcb->record_size + fcb->cur_record;
5119: }
5120:
1.1 root 5121: inline void msdos_int_21h_25h()
5122: {
5123: *(UINT16 *)(mem + 4 * REG8(AL) + 0) = REG16(DX);
1.1.1.3 root 5124: *(UINT16 *)(mem + 4 * REG8(AL) + 2) = SREG(DS);
1.1 root 5125: }
5126:
5127: inline void msdos_int_21h_26h()
5128: {
5129: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
5130:
5131: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
5132: psp->first_mcb = REG16(DX) + 16;
5133: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
5134: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
5135: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
5136: psp->parent_psp = 0;
5137: }
5138:
1.1.1.16 root 5139: inline void msdos_int_21h_27h()
5140: {
5141: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5142: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5143:
5144: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
5145: REG8(AL) = 1;
5146: } else {
5147: process_t *process = msdos_process_info_get(current_psp);
5148: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5149: memset(mem + dta_laddr, 0, fcb->record_size * REG16(CX));
5150: DWORD num = 0;
5151: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size * REG16(CX), &num, NULL) || num == 0) {
5152: REG8(AL) = 1;
5153: } else {
5154: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
5155: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
5156: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
5157: REG16(CX) = num / fcb->record_size + ((num % fcb->record_size) != 0);
5158: }
5159: }
5160: }
5161:
5162: inline void msdos_int_21h_28h()
5163: {
5164: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5165: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5166:
5167: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
5168: REG8(AL) = 0xff;
5169: } else {
5170: process_t *process = msdos_process_info_get(current_psp);
5171: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5172: DWORD num = 0;
5173: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size * REG16(CX), &num, NULL);
5174: fcb->file_size = GetFileSize(fcb->handle, NULL);
5175: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
5176: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
5177: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
5178: REG16(CX) = num / fcb->record_size + ((num % fcb->record_size) != 0);
5179: }
5180: }
5181:
1.1 root 5182: inline void msdos_int_21h_29h()
5183: {
1.1.1.20 root 5184: int ofs = 0;//SREG_BASE(DS) + REG16(SI);
5185: char buffer[1024], name[MAX_PATH], ext[MAX_PATH];
1.1 root 5186: UINT8 drv = 0;
5187: char sep_chars[] = ":.;,=+";
5188: char end_chars[] = "\\<>|/\"[]";
5189: char spc_chars[] = " \t";
5190:
1.1.1.20 root 5191: memcpy(buffer, mem + SREG_BASE(DS) + REG16(SI), 1023);
5192: buffer[1023] = 0;
5193: memset(name, 0x20, sizeof(name));
5194: memset(ext, 0x20, sizeof(ext));
5195:
1.1 root 5196: if(REG8(AL) & 1) {
1.1.1.20 root 5197: ofs += strspn((char *)(buffer + ofs), spc_chars);
5198: if(my_strchr(sep_chars, buffer[ofs]) && buffer[ofs] != '\0') {
1.1 root 5199: ofs++;
5200: }
5201: }
1.1.1.20 root 5202: ofs += strspn((char *)(buffer + ofs), spc_chars);
1.1 root 5203:
5204: if(mem[ofs + 1] == ':') {
1.1.1.20 root 5205: if(mem[ofs] >= 'a' && mem[ofs] <= 'z') {
5206: drv = mem[ofs] - 'a' + 1;
5207: ofs += 2;
5208: } else if(mem[ofs] >= 'A' && mem[ofs] <= 'Z') {
5209: drv = mem[ofs] - 'A' + 1;
1.1 root 5210: ofs += 2;
5211: }
5212: }
1.1.1.20 root 5213: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) {
5214: UINT8 c = buffer[ofs];
5215: if(is_kanji) {
5216: is_kanji = 0;
5217: } else if(msdos_lead_byte_check(c)) {
5218: is_kanji = 1;
5219: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
1.1 root 5220: break;
5221: } else if(c >= 'a' && c <= 'z') {
5222: c -= 0x20;
5223: }
5224: ofs++;
5225: name[i] = c;
5226: }
1.1.1.20 root 5227: if(buffer[ofs] == '.') {
1.1 root 5228: ofs++;
1.1.1.20 root 5229: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) {
5230: UINT8 c = buffer[ofs];
5231: if(is_kanji) {
5232: is_kanji = 0;
5233: } else if(msdos_lead_byte_check(c)) {
5234: is_kanji = 1;
5235: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
1.1 root 5236: break;
5237: } else if(c >= 'a' && c <= 'z') {
5238: c -= 0x20;
5239: }
5240: ofs++;
5241: ext[i] = c;
5242: }
5243: }
1.1.1.20 root 5244: int si = REG16(SI) + ofs;
1.1.1.3 root 5245: int ds = SREG(DS);
1.1 root 5246: while(si > 0xffff) {
5247: si -= 0x10;
5248: ds++;
5249: }
5250: REG16(SI) = si;
1.1.1.3 root 5251: SREG(DS) = ds;
5252: i386_load_segment_descriptor(DS);
1.1 root 5253:
1.1.1.3 root 5254: UINT8 *fcb = mem + SREG_BASE(ES) + REG16(DI);
1.1.1.20 root 5255: if(!(REG8(AL) & 2) || drv != 0) {
5256: fcb[0] = drv;
5257: }
5258: if(!(REG8(AL) & 4) || name[0] != 0x20) {
5259: memcpy(fcb + 1, name, 8);
5260: }
5261: if(!(REG8(AL) & 8) || ext[0] != 0x20) {
5262: memcpy(fcb + 9, ext, 3);
5263: }
5264: for(int i = 1, found_star = 0; i < 1 + 8; i++) {
1.1 root 5265: if(fcb[i] == '*') {
5266: found_star = 1;
5267: }
5268: if(found_star) {
5269: fcb[i] = '?';
5270: }
5271: }
1.1.1.20 root 5272: for(int i = 9, found_star = 0; i < 9 + 3; i++) {
1.1 root 5273: if(fcb[i] == '*') {
5274: found_star = 1;
5275: }
5276: if(found_star) {
5277: fcb[i] = '?';
5278: }
5279: }
5280:
5281: if(drv == 0 || (drv > 0 && drv <= 26 && (GetLogicalDrives() & ( 1 << (drv - 1) )))) {
5282: if(memchr(fcb + 1, '?', 8 + 3)) {
5283: REG8(AL) = 0x01;
1.1.1.20 root 5284: } else {
5285: REG8(AL) = 0x00;
1.1 root 5286: }
5287: } else {
5288: REG8(AL) = 0xff;
5289: }
5290: }
5291:
5292: inline void msdos_int_21h_2ah()
5293: {
5294: SYSTEMTIME sTime;
5295:
5296: GetLocalTime(&sTime);
5297: REG16(CX) = sTime.wYear;
5298: REG8(DH) = (UINT8)sTime.wMonth;
5299: REG8(DL) = (UINT8)sTime.wDay;
5300: REG8(AL) = (UINT8)sTime.wDayOfWeek;
5301: }
5302:
5303: inline void msdos_int_21h_2bh()
5304: {
1.1.1.14 root 5305: REG8(AL) = 0xff;
1.1 root 5306: }
5307:
5308: inline void msdos_int_21h_2ch()
5309: {
5310: SYSTEMTIME sTime;
5311:
5312: GetLocalTime(&sTime);
5313: REG8(CH) = (UINT8)sTime.wHour;
5314: REG8(CL) = (UINT8)sTime.wMinute;
5315: REG8(DH) = (UINT8)sTime.wSecond;
1.1.1.14 root 5316: REG8(DL) = (UINT8)sTime.wMilliseconds / 10;
1.1 root 5317: }
5318:
5319: inline void msdos_int_21h_2dh()
5320: {
5321: REG8(AL) = 0x00;
5322: }
5323:
5324: inline void msdos_int_21h_2eh()
5325: {
5326: process_t *process = msdos_process_info_get(current_psp);
5327:
5328: process->verify = REG8(AL);
5329: }
5330:
5331: inline void msdos_int_21h_2fh()
5332: {
5333: process_t *process = msdos_process_info_get(current_psp);
5334:
5335: REG16(BX) = process->dta.w.l;
1.1.1.3 root 5336: SREG(ES) = process->dta.w.h;
5337: i386_load_segment_descriptor(ES);
1.1 root 5338: }
5339:
5340: inline void msdos_int_21h_30h()
5341: {
5342: // Version Flag / OEM
5343: if(REG8(AL) == 1) {
5344: REG8(BH) = 0x00; // not in ROM
5345: } else {
5346: REG8(BH) = 0xff; // OEM = Microsoft
5347: }
1.1.1.9 root 5348: REG8(AL) = major_version; // 7
5349: REG8(AH) = minor_version; // 10
1.1 root 5350: }
5351:
5352: inline void msdos_int_21h_31h()
5353: {
1.1.1.14 root 5354: msdos_mem_realloc(current_psp, REG16(DX), NULL);
1.1 root 5355: msdos_process_terminate(current_psp, REG8(AL) | 0x300, 0);
5356: }
5357:
5358: inline void msdos_int_21h_32h()
5359: {
5360: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
5361: UINT16 seg, ofs;
5362:
5363: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
5364: REG8(AL) = 0;
1.1.1.3 root 5365: SREG(DS) = seg;
5366: i386_load_segment_descriptor(DS);
1.1 root 5367: REG16(BX) = ofs;
5368: } else {
5369: REG8(AL) = 0xff;
1.1.1.3 root 5370: m_CF = 1;
1.1 root 5371: }
5372: }
5373:
5374: inline void msdos_int_21h_33h()
5375: {
5376: static UINT8 state = 0x00;
5377: char path[MAX_PATH];
5378:
5379: switch(REG8(AL)) {
5380: case 0x00:
5381: REG8(DL) = state;
5382: break;
5383: case 0x01:
5384: state = REG8(DL);
5385: break;
5386: case 0x05:
5387: GetSystemDirectory(path, MAX_PATH);
5388: if(path[0] >= 'a' && path[0] <= 'z') {
5389: REG8(DL) = path[0] - 'a' + 1;
5390: } else {
5391: REG8(DL) = path[0] - 'A' + 1;
5392: }
5393: break;
5394: case 0x06:
1.1.1.2 root 5395: // MS-DOS version (7.10)
1.1 root 5396: REG8(BL) = 7;
1.1.1.2 root 5397: REG8(BH) = 10;
1.1 root 5398: REG8(DL) = 0;
5399: REG8(DH) = 0x10; // in HMA
5400: break;
1.1.1.6 root 5401: case 0x07:
5402: if(REG8(DL) == 0) {
5403: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag &= ~0x20;
5404: } else if(REG8(DL) == 1) {
5405: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag |= 0x20;
5406: }
5407: break;
1.1 root 5408: default:
1.1.1.22 root 5409: 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 5410: REG16(AX) = 0x01;
1.1.1.3 root 5411: m_CF = 1;
1.1 root 5412: break;
5413: }
5414: }
5415:
1.1.1.23! root 5416: inline void msdos_int_21h_34h()
! 5417: {
! 5418: SREG(ES) = SDA_TOP >> 4;
! 5419: i386_load_segment_descriptor(ES);
! 5420: REG16(BX) = offsetof(sda_t, indos_flag);;
! 5421: }
! 5422:
1.1 root 5423: inline void msdos_int_21h_35h()
5424: {
5425: REG16(BX) = *(UINT16 *)(mem + 4 * REG8(AL) + 0);
1.1.1.3 root 5426: SREG(ES) = *(UINT16 *)(mem + 4 * REG8(AL) + 2);
5427: i386_load_segment_descriptor(ES);
1.1 root 5428: }
5429:
5430: inline void msdos_int_21h_36h()
5431: {
5432: struct _diskfree_t df = {0};
5433:
5434: if(_getdiskfree(REG8(DL), &df) == 0) {
5435: REG16(AX) = (UINT16)df.sectors_per_cluster;
5436: REG16(CX) = (UINT16)df.bytes_per_sector;
1.1.1.13 root 5437: REG16(BX) = df.avail_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.avail_clusters;
5438: REG16(DX) = df.total_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.total_clusters;
1.1 root 5439: } else {
5440: REG16(AX) = 0xffff;
5441: }
5442: }
5443:
5444: inline void msdos_int_21h_37h()
5445: {
1.1.1.22 root 5446: static UINT8 dev_flag = 0xff;
1.1 root 5447:
5448: switch(REG8(AL)) {
5449: case 0x00:
1.1.1.22 root 5450: {
5451: process_t *process = msdos_process_info_get(current_psp);
5452: REG8(AL) = 0x00;
5453: REG8(DL) = process->switchar;
5454: }
1.1 root 5455: break;
5456: case 0x01:
1.1.1.22 root 5457: {
5458: process_t *process = msdos_process_info_get(current_psp);
5459: REG8(AL) = 0x00;
5460: process->switchar = REG8(DL);
1.1.1.23! root 5461: msdos_sda_update(current_psp);
1.1.1.22 root 5462: }
5463: break;
5464: case 0x02:
5465: REG8(DL) = dev_flag;
5466: break;
5467: case 0x03:
5468: dev_flag = REG8(DL);
5469: break;
5470: case 0xd0:
5471: case 0xd1:
5472: case 0xd2:
5473: case 0xd3:
5474: case 0xd4:
5475: case 0xd5:
5476: case 0xd6:
5477: case 0xd7:
5478: case 0xdc:
5479: case 0xdd:
5480: case 0xde:
5481: case 0xdf:
5482: // diet ???
5483: REG16(AX) = 1;
1.1 root 5484: break;
5485: default:
1.1.1.22 root 5486: 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 5487: REG16(AX) = 1;
5488: break;
5489: }
5490: }
5491:
1.1.1.19 root 5492: int get_country_info(country_info_t *ci)
1.1.1.17 root 5493: {
5494: char LCdata[80];
5495:
1.1.1.19 root 5496: ZeroMemory(ci, offsetof(country_info_t, reserved));
1.1.1.17 root 5497: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRDIGITS, LCdata, sizeof(LCdata));
5498: ci->currency_dec_digits = atoi(LCdata);
5499: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRENCY, LCdata, sizeof(LCdata));
5500: ci->currency_format = *LCdata - '0';
5501: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDATE, LCdata, sizeof(LCdata));
5502: ci->date_format = *LCdata - '0';
5503: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SCURRENCY, LCdata, sizeof(LCdata));
5504: memcpy(&ci->currency_symbol, LCdata, 4);
5505: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDATE, LCdata, sizeof(LCdata));
5506: *ci->date_sep = *LCdata;
5507: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, LCdata, sizeof(LCdata));
5508: *ci->dec_sep = *LCdata;
5509: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SLIST, LCdata, sizeof(LCdata));
5510: *ci->list_sep = *LCdata;
5511: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, LCdata, sizeof(LCdata));
5512: *ci->thou_sep = *LCdata;
5513: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIME, LCdata, sizeof(LCdata));
5514: *ci->time_sep = *LCdata;
5515: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIMEFORMAT, LCdata, sizeof(LCdata));
5516: if(strchr(LCdata, 'H') != NULL) {
5517: ci->time_format = 1;
5518: }
1.1.1.19 root 5519: ci->case_map.w.l = 0x000c;
5520: ci->case_map.w.h = 0xffff;
1.1.1.17 root 5521: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICOUNTRY, LCdata, sizeof(LCdata));
5522: return atoi(LCdata);
5523: }
5524:
1.1.1.14 root 5525: inline void msdos_int_21h_38h()
5526: {
5527: switch(REG8(AL)) {
5528: case 0x00:
1.1.1.19 root 5529: REG16(BX) = get_country_info((country_info_t *)(mem + SREG_BASE(DS) + REG16(DX)));
1.1.1.14 root 5530: break;
5531: default:
1.1.1.22 root 5532: 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 5533: REG16(AX) = 2;
5534: m_CF = 1;
5535: break;
5536: }
5537: }
5538:
1.1 root 5539: inline void msdos_int_21h_39h(int lfn)
5540: {
1.1.1.3 root 5541: if(_mkdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 5542: REG16(AX) = errno;
1.1.1.3 root 5543: m_CF = 1;
1.1 root 5544: }
5545: }
5546:
5547: inline void msdos_int_21h_3ah(int lfn)
5548: {
1.1.1.3 root 5549: if(_rmdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 5550: REG16(AX) = errno;
1.1.1.3 root 5551: m_CF = 1;
1.1 root 5552: }
5553: }
5554:
5555: inline void msdos_int_21h_3bh(int lfn)
5556: {
1.1.1.3 root 5557: if(_chdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1.1.17 root 5558: REG16(AX) = 3; // must be 3 (path not found)
1.1.1.3 root 5559: m_CF = 1;
1.1 root 5560: }
5561: }
5562:
5563: inline void msdos_int_21h_3ch()
5564: {
1.1.1.3 root 5565: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 5566: int attr = GetFileAttributes(path);
5567: int fd = -1;
1.1.1.11 root 5568: UINT16 info;
1.1 root 5569:
1.1.1.11 root 5570: if(msdos_is_con_path(path)) {
5571: fd = _open("CON", _O_WRONLY | _O_BINARY);
5572: info = 0x80d3;
1.1.1.14 root 5573: } else if(msdos_is_nul_path(path)) {
5574: fd = _open("NUL", _O_WRONLY | _O_BINARY);
5575: info = 0x80d3;
1.1.1.20 root 5576: } else if(strncmp(path, "EMMXXXX0", 8) == 0) {
5577: fd = _open("NUL", _O_WRONLY | _O_BINARY);
5578: info = 0x80d3;
1.1 root 5579: } else {
5580: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
1.1.1.11 root 5581: info = msdos_drive_number(path);
1.1 root 5582: }
5583: if(fd != -1) {
5584: if(attr == -1) {
5585: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
5586: }
5587: SetFileAttributes(path, attr);
5588: REG16(AX) = fd;
1.1.1.11 root 5589: msdos_file_handler_open(fd, path, _isatty(fd), 2, info, current_psp);
1.1.1.20 root 5590: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 5591: } else {
5592: REG16(AX) = errno;
1.1.1.3 root 5593: m_CF = 1;
1.1 root 5594: }
5595: }
5596:
5597: inline void msdos_int_21h_3dh()
5598: {
1.1.1.3 root 5599: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 5600: int mode = REG8(AL) & 0x03;
1.1.1.11 root 5601: int fd = -1;
5602: UINT16 info;
1.1 root 5603:
5604: if(mode < 0x03) {
1.1.1.11 root 5605: if(msdos_is_con_path(path)) {
1.1.1.13 root 5606: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 5607: info = 0x80d3;
1.1.1.14 root 5608: } else if(msdos_is_nul_path(path)) {
5609: fd = msdos_open("NUL", file_mode[mode].mode);
5610: info = 0x80d3;
1.1.1.20 root 5611: } else if(strncmp(path, "EMMXXXX0", 8) == 0) {
5612: fd = msdos_open("NUL", file_mode[mode].mode);
5613: info = 0x80d3;
1.1.1.11 root 5614: } else {
1.1.1.13 root 5615: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 5616: info = msdos_drive_number(path);
5617: }
1.1 root 5618: if(fd != -1) {
5619: REG16(AX) = fd;
1.1.1.11 root 5620: msdos_file_handler_open(fd, path, _isatty(fd), mode, info, current_psp);
1.1.1.20 root 5621: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 5622: } else {
5623: REG16(AX) = errno;
1.1.1.3 root 5624: m_CF = 1;
1.1 root 5625: }
5626: } else {
5627: REG16(AX) = 0x0c;
1.1.1.3 root 5628: m_CF = 1;
1.1 root 5629: }
5630: }
5631:
5632: inline void msdos_int_21h_3eh()
5633: {
5634: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 5635: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 5636:
1.1.1.20 root 5637: if(fd < process->max_files && file_handler[fd].valid) {
5638: _close(fd);
5639: msdos_file_handler_close(fd);
5640: msdos_psp_set_file_table(REG16(BX), 0x0ff, current_psp);
1.1 root 5641: } else {
5642: REG16(AX) = 0x06;
1.1.1.3 root 5643: m_CF = 1;
1.1 root 5644: }
5645: }
5646:
5647: inline void msdos_int_21h_3fh()
5648: {
5649: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 5650: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 5651:
1.1.1.20 root 5652: if(fd < process->max_files && file_handler[fd].valid) {
5653: if(file_mode[file_handler[fd].mode].in) {
5654: if(file_handler[fd].atty) {
1.1 root 5655: // BX is stdin or is redirected to stdin
1.1.1.3 root 5656: UINT8 *buf = mem + SREG_BASE(DS) + REG16(DX);
1.1 root 5657: int max = REG16(CX);
5658: int p = 0;
5659:
5660: while(max > p) {
5661: int chr = msdos_getch();
5662:
5663: if(chr == 0x00) {
5664: // skip 2nd byte
5665: msdos_getch();
5666: } else if(chr == 0x0d) {
5667: // carriage return
5668: buf[p++] = 0x0d;
5669: if(max > p) {
5670: buf[p++] = 0x0a;
5671: }
1.1.1.14 root 5672: msdos_putch('\n');
1.1 root 5673: break;
5674: } else if(chr == 0x08) {
5675: // back space
5676: if(p > 0) {
5677: p--;
1.1.1.20 root 5678: if(msdos_ctrl_code_check(buf[p])) {
5679: msdos_putch(chr);
5680: msdos_putch(chr);
5681: msdos_putch(' ');
5682: msdos_putch(' ');
5683: msdos_putch(chr);
5684: msdos_putch(chr);
5685: } else {
5686: msdos_putch(chr);
5687: msdos_putch(' ');
5688: msdos_putch(chr);
5689: }
1.1 root 5690: }
5691: } else {
5692: buf[p++] = chr;
5693: msdos_putch(chr);
5694: }
5695: }
5696: REG16(AX) = p;
1.1.1.8 root 5697: // some seconds may be passed in console
1.1 root 5698: hardware_update();
5699: } else {
1.1.1.20 root 5700: REG16(AX) = _read(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 5701: }
5702: } else {
5703: REG16(AX) = 0x05;
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_40h()
5713: {
5714: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 5715: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 5716:
1.1.1.20 root 5717: if(fd < process->max_files && file_handler[fd].valid) {
5718: if(file_mode[file_handler[fd].mode].out) {
1.1 root 5719: if(REG16(CX)) {
1.1.1.20 root 5720: if(file_handler[fd].atty) {
1.1 root 5721: // BX is stdout/stderr or is redirected to stdout
5722: for(int i = 0; i < REG16(CX); i++) {
1.1.1.3 root 5723: msdos_putch(mem[SREG_BASE(DS) + REG16(DX) + i]);
1.1 root 5724: }
5725: REG16(AX) = REG16(CX);
5726: } else {
1.1.1.20 root 5727: REG16(AX) = msdos_write(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 5728: }
5729: } else {
1.1.1.20 root 5730: UINT32 pos = _tell(fd);
5731: _lseek(fd, 0, SEEK_END);
5732: UINT32 size = _tell(fd);
1.1.1.12 root 5733: if(pos < size) {
1.1.1.20 root 5734: _lseek(fd, pos, SEEK_SET);
5735: SetEndOfFile((HANDLE)_get_osfhandle(fd));
1.1.1.12 root 5736: } else {
5737: for(UINT32 i = size; i < pos; i++) {
5738: UINT8 tmp = 0;
1.1.1.23! root 5739: msdos_write(fd, &tmp, 1);
1.1.1.12 root 5740: }
1.1.1.20 root 5741: _lseek(fd, pos, SEEK_SET);
1.1 root 5742: }
1.1.1.23! root 5743: REG16(AX) = 0;
1.1 root 5744: }
5745: } else {
5746: REG16(AX) = 0x05;
1.1.1.3 root 5747: m_CF = 1;
1.1 root 5748: }
5749: } else {
5750: REG16(AX) = 0x06;
1.1.1.3 root 5751: m_CF = 1;
1.1 root 5752: }
5753: }
5754:
5755: inline void msdos_int_21h_41h(int lfn)
5756: {
1.1.1.3 root 5757: if(remove(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 5758: REG16(AX) = errno;
1.1.1.3 root 5759: m_CF = 1;
1.1 root 5760: }
5761: }
5762:
5763: inline void msdos_int_21h_42h()
5764: {
5765: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 5766: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 5767:
1.1.1.20 root 5768: if(fd < process->max_files && file_handler[fd].valid) {
1.1 root 5769: if(REG8(AL) < 0x03) {
5770: static int ptrname[] = { SEEK_SET, SEEK_CUR, SEEK_END };
1.1.1.20 root 5771: _lseek(fd, (REG16(CX) << 16) | REG16(DX), ptrname[REG8(AL)]);
5772: UINT32 pos = _tell(fd);
1.1 root 5773: REG16(AX) = pos & 0xffff;
5774: REG16(DX) = (pos >> 16);
5775: } else {
5776: REG16(AX) = 0x01;
1.1.1.3 root 5777: m_CF = 1;
1.1 root 5778: }
5779: } else {
5780: REG16(AX) = 0x06;
1.1.1.3 root 5781: m_CF = 1;
1.1 root 5782: }
5783: }
5784:
5785: inline void msdos_int_21h_43h(int lfn)
5786: {
1.1.1.3 root 5787: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn);
1.1 root 5788: int attr;
5789:
1.1.1.14 root 5790: if(!lfn && REG8(AL) > 2) {
5791: REG16(AX) = 0x01;
5792: m_CF = 1;
5793: return;
5794: }
5795: switch(REG8(lfn ? BL : AL)) {
1.1 root 5796: case 0x00:
5797: if((attr = GetFileAttributes(path)) != -1) {
1.1.1.14 root 5798: REG16(CX) = (UINT16)msdos_file_attribute_create((UINT16)attr);
5799: } else {
5800: REG16(AX) = (UINT16)GetLastError();
5801: m_CF = 1;
5802: }
5803: break;
5804: case 0x01:
5805: if(!SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)))) {
5806: REG16(AX) = (UINT16)GetLastError();
5807: m_CF = 1;
5808: }
5809: break;
5810: case 0x02:
5811: {
5812: DWORD size = GetCompressedFileSize(path, NULL);
5813: if(size != INVALID_FILE_SIZE) {
5814: if(size != 0 && size == GetFileSize(path, NULL)) {
5815: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
5816: // this isn't correct if the file is in the NTFS MFT
5817: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
5818: size = ((size - 1) | (sectors_per_cluster * bytes_per_sector - 1)) + 1;
5819: }
5820: }
5821: REG16(AX) = LOWORD(size);
5822: REG16(DX) = HIWORD(size);
5823: } else {
5824: REG16(AX) = (UINT16)GetLastError();
5825: m_CF = 1;
1.1 root 5826: }
1.1.1.14 root 5827: }
5828: break;
5829: case 0x03:
5830: case 0x05:
5831: case 0x07:
5832: {
5833: HANDLE hFile = CreateFile(path, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
5834: if(hFile != INVALID_HANDLE_VALUE) {
5835: FILETIME local, time;
5836: DosDateTimeToFileTime(REG16(DI), /*REG8(BL) == 5 ? 0 : */REG16(CX), &local);
5837: if(REG8(BL) == 7) {
5838: ULARGE_INTEGER hund;
5839: hund.LowPart = local.dwLowDateTime;
5840: hund.HighPart = local.dwHighDateTime;
5841: hund.QuadPart += REG16(SI) * 100000;
5842: local.dwLowDateTime = hund.LowPart;
5843: local.dwHighDateTime = hund.HighPart;
5844: }
5845: LocalFileTimeToFileTime(&local, &time);
5846: if(!SetFileTime(hFile, REG8(BL) == 0x07 ? &time : NULL,
5847: REG8(BL) == 0x05 ? &time : NULL,
5848: REG8(BL) == 0x03 ? &time : NULL)) {
5849: REG16(AX) = (UINT16)GetLastError();
5850: m_CF = 1;
5851: }
5852: CloseHandle(hFile);
5853: } else {
5854: REG16(AX) = (UINT16)GetLastError();
5855: m_CF = 1;
1.1 root 5856: }
1.1.1.14 root 5857: }
5858: break;
5859: case 0x04:
5860: case 0x06:
5861: case 0x08:
5862: {
5863: WIN32_FILE_ATTRIBUTE_DATA fad;
5864: if(GetFileAttributesEx(path, GetFileExInfoStandard, (LPVOID)&fad)) {
5865: FILETIME *time, local;
5866: time = REG8(BL) == 0x04 ? &fad.ftLastWriteTime :
5867: 0x06 ? &fad.ftLastAccessTime :
5868: &fad.ftCreationTime;
5869: FileTimeToLocalFileTime(time, &local);
5870: FileTimeToDosDateTime(&local, ®16(DI), ®16(CX));
5871: if(REG8(BL) == 0x08) {
5872: ULARGE_INTEGER hund;
5873: hund.LowPart = local.dwLowDateTime;
5874: hund.HighPart = local.dwHighDateTime;
5875: hund.QuadPart /= 100000;
5876: REG16(SI) = (UINT16)(hund.QuadPart % 200);
5877: }
5878: } else {
5879: REG16(AX) = (UINT16)GetLastError();
5880: m_CF = 1;
1.1 root 5881: }
1.1.1.14 root 5882: }
5883: break;
5884: default:
1.1.1.22 root 5885: 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 5886: REG16(AX) = 0x01;
5887: m_CF = 1;
5888: break;
5889: }
5890: }
5891:
5892: inline void msdos_int_21h_44h()
5893: {
1.1.1.22 root 5894: static UINT16 iteration_count = 0;
5895:
1.1.1.20 root 5896: process_t *process = msdos_process_info_get(current_psp);
5897: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
5898:
1.1.1.14 root 5899: UINT32 val = DRIVE_NO_ROOT_DIR;
5900:
5901: switch(REG8(AL)) {
5902: case 0x00:
5903: case 0x01:
5904: case 0x02:
5905: case 0x03:
5906: case 0x04:
5907: case 0x05:
5908: case 0x06:
5909: case 0x07:
1.1.1.20 root 5910: if(fd >= process->max_files || !file_handler[fd].valid) {
5911: REG16(AX) = 0x06;
5912: m_CF = 1;
5913: return;
1.1.1.14 root 5914: }
5915: break;
5916: case 0x08:
5917: case 0x09:
5918: if(REG8(BL) >= ('Z' - 'A' + 1)) {
5919: // invalid drive number
5920: REG16(AX) = 0x0f;
5921: m_CF = 1;
5922: return;
5923: } else {
5924: if(REG8(BL) == 0) {
5925: val = GetDriveType(NULL);
5926: } else {
5927: char tmp[8];
5928: sprintf(tmp, "%c:\\", 'A' + REG8(BL) - 1);
5929: val = GetDriveType(tmp);
5930: }
5931: if(val == DRIVE_NO_ROOT_DIR) {
5932: // no drive
5933: REG16(AX) = 0x0f;
5934: m_CF = 1;
5935: return;
1.1 root 5936: }
5937: }
5938: break;
5939: }
5940: switch(REG8(AL)) {
5941: case 0x00: // get ioctrl data
1.1.1.20 root 5942: REG16(DX) = file_handler[fd].info;
1.1 root 5943: break;
5944: case 0x01: // set ioctrl data
1.1.1.20 root 5945: file_handler[fd].info |= REG8(DL);
1.1 root 5946: break;
5947: case 0x02: // recv from character device
5948: case 0x03: // send to character device
5949: case 0x04: // recv from block device
5950: case 0x05: // send to block device
5951: REG16(AX) = 0x05;
1.1.1.3 root 5952: m_CF = 1;
1.1 root 5953: break;
5954: case 0x06: // get read status
1.1.1.20 root 5955: if(file_mode[file_handler[fd].mode].in) {
5956: if(file_handler[fd].atty) {
1.1.1.14 root 5957: REG8(AL) = msdos_kbhit() ? 0xff : 0x00;
1.1 root 5958: } else {
1.1.1.20 root 5959: REG8(AL) = eof(fd) ? 0x00 : 0xff;
1.1 root 5960: }
1.1.1.14 root 5961: } else {
5962: REG8(AL) = 0x00;
1.1 root 5963: }
5964: break;
5965: case 0x07: // get write status
1.1.1.20 root 5966: if(file_mode[file_handler[fd].mode].out) {
1.1.1.14 root 5967: REG8(AL) = 0xff;
5968: } else {
5969: REG8(AL) = 0x00;
1.1 root 5970: }
5971: break;
5972: case 0x08: // check removable drive
1.1.1.14 root 5973: if(val == DRIVE_REMOVABLE || val == DRIVE_CDROM) {
5974: // removable drive
5975: REG16(AX) = 0x00;
1.1 root 5976: } else {
1.1.1.14 root 5977: // fixed drive
5978: REG16(AX) = 0x01;
1.1 root 5979: }
5980: break;
5981: case 0x09: // check remote drive
1.1.1.14 root 5982: if(val == DRIVE_REMOTE) {
5983: // remote drive
5984: REG16(DX) = 0x1000;
1.1 root 5985: } else {
1.1.1.14 root 5986: // local drive
5987: REG16(DX) = 0x00;
1.1 root 5988: }
5989: break;
1.1.1.21 root 5990: case 0x0a: // check remote handle
5991: REG16(DX) = 0x00; // FIXME
5992: break;
1.1 root 5993: case 0x0b: // set retry count
5994: break;
1.1.1.22 root 5995: case 0x0c: // generic character device request
5996: if(REG8(CL) == 0x45) {
5997: // set iteration (retry) count
5998: iteration_count = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX));
5999: } else if(REG8(CL) == 0x4a) {
6000: // select code page
6001: active_code_page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2);
6002: msdos_nls_tables_update();
6003: } else if(REG8(CL) == 0x65) {
6004: // get iteration (retry) count
6005: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX)) = iteration_count;
6006: } else if(REG8(CL) == 0x6a) {
6007: // query selected code page
6008: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = 2; // FIXME
6009: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2) = active_code_page;
6010:
6011: CPINFO info;
6012: GetCPInfo(active_code_page, &info);
6013:
6014: if(info.MaxCharSize != 1) {
6015: for(int i = 0;; i++) {
6016: UINT8 lo = info.LeadByte[2 * i + 0];
6017: UINT8 hi = info.LeadByte[2 * i + 1];
6018:
6019: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4 + 4 * i + 0) = lo;
6020: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4 + 4 * i + 2) = hi;
6021: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) + 4;
6022:
6023: if(lo == 0 && hi == 0) {
6024: break;
6025: }
6026: }
6027: }
6028: } else if(REG8(CL) == 0x7f) {
6029: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x00) = 0;
6030: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x01) = 0;
6031: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02) = 14;
6032: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x04) = 1;
6033: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x06) = 1;
6034: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x07) = 0;
6035: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x08) = 4;
6036: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0a) = 8 * (*(UINT16 *)(mem + 0x44a));
6037: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0c) = 16 * (*(UINT8 *)(mem + 0x484) + 1);
6038: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0e) = *(UINT16 *)(mem + 0x44a);
6039: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x10) = *(UINT8 *)(mem + 0x484) + 1;
6040: } else {
6041: 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));
6042: REG16(AX) = 0x01; // invalid function
6043: m_CF = 1;
6044: }
6045: break;
6046: case 0x0d: // generic block device request
6047: if(REG8(CL) == 0x40) {
6048: // set device parameters
6049: } else if(REG8(CL) == 0x46) {
6050: // set volume serial number
6051: } else if(REG8(CL) == 0x4a) {
6052: // lock logical volume
6053: } else if(REG8(CL) == 0x4b) {
6054: // lock physical volume
6055: } else if(REG8(CL) == 0x60) {
6056: // get device parameters
6057: char dev[] = "\\\\.\\A:";
6058: dev[4] = 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
6059:
6060: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
6061: if(hFile != INVALID_HANDLE_VALUE) {
6062: DISK_GEOMETRY geo;
6063: DWORD dwSize;
6064: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
6065: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x07; // ???
6066: switch(geo.MediaType) {
6067: case F5_360_512:
6068: case F5_320_512:
6069: case F5_320_1024:
6070: case F5_180_512:
6071: case F5_160_512:
6072: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x00; // 320K/360K disk
6073: break;
6074: case F5_1Pt2_512:
6075: case F3_1Pt2_512:
6076: case F3_1Pt23_1024:
6077: case F5_1Pt23_1024:
6078: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x01; // 1.2M disk
6079: break;
6080: case F3_720_512:
6081: case F3_640_512:
6082: case F5_640_512:
6083: case F5_720_512:
6084: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x02; // 720K disk
6085: break;
6086: case F8_256_128:
6087: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x03; // single-density 8-inch disk
6088: break;
6089: case FixedMedia:
6090: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // fixed disk
6091: break;
6092: case F3_1Pt44_512:
6093: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x07; // (DOS 3.3+) other type of block device, normally 1.44M floppy
6094: break;
6095: case F3_2Pt88_512:
6096: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x09; // (DOS 5+) 2.88M floppy
6097: break;
6098: default:
6099: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // fixed disk
6100: // *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // (DOS 3.3+) other type of block device, normally 1.44M floppy
6101: break;
6102: }
6103: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x02) = (geo.MediaType == FixedMedia) ? 0x01 : 0x00;
6104: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04) = (geo.Cylinders.QuadPart > 0xffff) ? 0xffff : geo.Cylinders.QuadPart;
6105: switch(geo.MediaType) {
6106: case F5_360_512:
6107: case F5_320_512:
6108: case F5_320_1024:
6109: case F5_180_512:
6110: case F5_160_512:
6111: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06) = 0x01; // 320K/360K disk
6112: break;
6113: default:
6114: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06) = 0x00; // other drive types
6115: break;
6116: }
6117: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x00) = geo.BytesPerSector;
6118: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x02) = geo.SectorsPerTrack * geo.TracksPerCylinder;
6119: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x03) = 0;
6120: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x05) = 0;
6121: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x06) = 0;
6122: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x08) = 0;
6123: switch(geo.MediaType) {
6124: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K)
6125: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xff;
6126: break;
6127: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K)
6128: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfe;
6129: break;
6130: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K)
6131: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfd;
6132: break;
6133: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K)
6134: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfc;
6135: break;
6136: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M)
6137: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5")
6138: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf9;
6139: break;
6140: case FixedMedia: // hard disk
6141: case RemovableMedia:
6142: case Unknown:
6143: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf8;
6144: break;
6145: default:
6146: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf0;
6147: break;
6148: }
6149: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0d) = geo.SectorsPerTrack;
6150: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0f) = 1;
6151: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x11) = 0;
6152: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x15) = geo.TracksPerCylinder * geo.Cylinders.QuadPart;
6153: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x1f) = geo.Cylinders.QuadPart;
6154: // 21h BYTE device type
6155: // 22h WORD device attributes (removable or not, etc)
6156: } else {
6157: REG16(AX) = 0x0f; // invalid drive
6158: m_CF = 1;
6159: }
6160: CloseHandle(hFile);
6161: } else {
6162: REG16(AX) = 0x0f; // invalid drive
6163: m_CF = 1;
6164: }
6165: } else if(REG8(CL) == 0x66) {
6166: // get volume serial number
6167: char path[] = "A:\\";
6168: char volume_label[MAX_PATH];
6169: DWORD serial_number = 0;
6170: char file_system[MAX_PATH];
6171:
6172: path[0] = 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
6173:
6174: if(GetVolumeInformation(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) {
6175: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0;
6176: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x02) = serial_number;
6177: memset(mem + SREG_BASE(DS) + REG16(SI) + 0x06, 0x20, 11);
6178: memcpy(mem + SREG_BASE(DS) + REG16(SI) + 0x06, volume_label, min(strlen(volume_label), 11));
6179: memset(mem + SREG_BASE(DS) + REG16(SI) + 0x11, 0x20, 8);
6180: memcpy(mem + SREG_BASE(DS) + REG16(SI) + 0x11, file_system, min(strlen(file_system), 8));
6181: } else {
6182: REG16(AX) = 0x0f; // invalid drive
6183: m_CF = 1;
6184: }
6185: } else if(REG8(CL) == 0x67) {
6186: // get access flag
6187: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0;
6188: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 1;
6189: } else if(REG8(CL) == 0x68) {
6190: // sense media type
6191: char dev[64];
6192: sprintf(dev, "\\\\.\\%c:", 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1);
6193:
6194: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
6195: if(hFile != INVALID_HANDLE_VALUE) {
6196: DISK_GEOMETRY geo;
6197: DWORD dwSize;
6198: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
6199: switch(geo.MediaType) {
6200: case F3_720_512:
6201: case F5_720_512:
6202: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
6203: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x02;
6204: break;
6205: case F3_1Pt44_512:
6206: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
6207: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x07;
6208: break;
6209: case F3_2Pt88_512:
6210: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
6211: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x09;
6212: break;
6213: default:
6214: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x00;
6215: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x00; // ???
6216: break;
6217: }
6218: } else {
6219: REG16(AX) = 0x0f; // invalid drive
6220: m_CF = 1;
6221: }
6222: CloseHandle(hFile);
6223: } else {
6224: REG16(AX) = 0x0f; // invalid drive
6225: m_CF = 1;
6226: }
6227: } else if(REG8(CL) == 0x6a) {
6228: // unlock logical volume
6229: } else if(REG8(CL) == 0x6b) {
6230: // unlock physical volume
6231: } else {
6232: 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));
6233: REG16(AX) = 0x01; // invalid function
6234: m_CF = 1;
6235: }
6236: break;
6237: case 0x0e: // get logical drive map
6238: {
6239: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
6240: if(!(GetLogicalDrives() & bits)) {
6241: REG16(AX) = 0x0f; // invalid drive
6242: m_CF = 1;
6243: } else {
6244: REG8(AL) = 0;
6245: }
6246: }
6247: break;
6248: case 0x0f: // set logical drive map
6249: {
6250: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
6251: if(!(GetLogicalDrives() & bits)) {
6252: REG16(AX) = 0x0f; // invalid drive
6253: m_CF = 1;
6254: }
6255: }
6256: break;
6257: case 0x10: // query generic ioctrl capability (handle)
6258: switch(REG8(CL)) {
6259: case 0x45:
6260: case 0x4a:
6261: case 0x65:
6262: case 0x6a:
6263: case 0x7f:
6264: REG16(AX) = 0x0000; // supported
6265: break;
6266: default:
6267: REG8(AL) = 0x01; // ioctl capability not available
6268: m_CF = 1;
6269: break;
6270: }
6271: break;
6272: case 0x11: // query generic ioctrl capability (drive)
6273: switch(REG8(CL)) {
6274: case 0x40:
6275: case 0x46:
6276: case 0x4a:
6277: case 0x4b:
6278: case 0x60:
6279: case 0x66:
6280: case 0x67:
6281: case 0x68:
6282: case 0x6a:
6283: case 0x6b:
6284: REG16(AX) = 0x0000; // supported
6285: break;
6286: default:
6287: REG8(AL) = 0x01; // ioctl capability not available
6288: m_CF = 1;
6289: break;
6290: }
6291: break;
6292: case 0x12: // determine dos type
6293: case 0x51: // concurrent dos v3.2+ - installation check
6294: case 0x52: // determine dos type/get dr dos versuin
6295: REG16(AX) = 0x01; // this is not DR-DOS
6296: m_CF = 1;
6297: break;
1.1 root 6298: default:
1.1.1.22 root 6299: 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 6300: REG16(AX) = 0x01;
1.1.1.3 root 6301: m_CF = 1;
1.1 root 6302: break;
6303: }
6304: }
6305:
6306: inline void msdos_int_21h_45h()
6307: {
6308: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 6309: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 6310:
1.1.1.20 root 6311: if(fd < process->max_files && file_handler[fd].valid) {
6312: int dup_fd = _dup(fd);
6313: if(dup_fd != -1) {
6314: REG16(AX) = dup_fd;
6315: msdos_file_handler_dup(dup_fd, fd, current_psp);
6316: // msdos_psp_set_file_table(dup_fd, fd, current_psp);
6317: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp);
1.1 root 6318: } else {
6319: REG16(AX) = errno;
1.1.1.3 root 6320: m_CF = 1;
1.1 root 6321: }
6322: } else {
6323: REG16(AX) = 0x06;
1.1.1.3 root 6324: m_CF = 1;
1.1 root 6325: }
6326: }
6327:
6328: inline void msdos_int_21h_46h()
6329: {
6330: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 6331: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
6332: int dup_fd = REG16(CX);
6333: int tmp_fd = msdos_psp_get_file_table(REG16(CX), current_psp);
1.1 root 6334:
1.1.1.20 root 6335: if(REG16(BX) == REG16(CX)) {
6336: REG16(AX) = 0x06;
6337: m_CF = 1;
6338: } else if(fd < process->max_files && file_handler[fd].valid && dup_fd < process->max_files) {
6339: if(tmp_fd < process->max_files && file_handler[tmp_fd].valid) {
6340: _close(tmp_fd);
6341: msdos_file_handler_close(tmp_fd);
6342: msdos_psp_set_file_table(dup_fd, 0x0ff, current_psp);
6343: }
6344: if(_dup2(fd, dup_fd) != -1) {
6345: msdos_file_handler_dup(dup_fd, fd, current_psp);
6346: // msdos_psp_set_file_table(dup_fd, fd, current_psp);
6347: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp);
1.1 root 6348: } else {
6349: REG16(AX) = errno;
1.1.1.3 root 6350: m_CF = 1;
1.1 root 6351: }
6352: } else {
6353: REG16(AX) = 0x06;
1.1.1.3 root 6354: m_CF = 1;
1.1 root 6355: }
6356: }
6357:
6358: inline void msdos_int_21h_47h(int lfn)
6359: {
6360: char path[MAX_PATH];
6361:
6362: if(_getdcwd(REG8(DL), path, MAX_PATH) != NULL) {
6363: if(path[1] == ':') {
6364: // the returned path does not include a drive or the initial backslash
1.1.1.3 root 6365: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), (lfn ? path : msdos_short_path(path)) + 3);
1.1 root 6366: } else {
1.1.1.3 root 6367: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn ? path : msdos_short_path(path));
1.1 root 6368: }
6369: } else {
6370: REG16(AX) = errno;
1.1.1.3 root 6371: m_CF = 1;
1.1 root 6372: }
6373: }
6374:
6375: inline void msdos_int_21h_48h()
6376: {
1.1.1.19 root 6377: int seg, umb_linked;
1.1 root 6378:
1.1.1.8 root 6379: if((malloc_strategy & 0xf0) == 0x00) {
1.1.1.19 root 6380: // unlink umb not to allocate memory in umb
6381: if((umb_linked = msdos_mem_get_umb_linked()) != 0) {
6382: msdos_mem_unlink_umb();
6383: }
1.1.1.8 root 6384: if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
6385: REG16(AX) = seg;
6386: } else {
6387: REG16(AX) = 0x08;
6388: REG16(BX) = msdos_mem_get_free(first_mcb, 0);
6389: m_CF = 1;
6390: }
1.1.1.19 root 6391: if(umb_linked != 0) {
6392: msdos_mem_link_umb();
6393: }
1.1.1.8 root 6394: } else if((malloc_strategy & 0xf0) == 0x40) {
6395: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
6396: REG16(AX) = seg;
6397: } else {
6398: REG16(AX) = 0x08;
6399: REG16(BX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
6400: m_CF = 1;
6401: }
6402: } else if((malloc_strategy & 0xf0) == 0x80) {
6403: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
6404: REG16(AX) = seg;
6405: } else if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
6406: REG16(AX) = seg;
6407: } else {
6408: REG16(AX) = 0x08;
6409: REG16(BX) = max(msdos_mem_get_free(UMB_TOP >> 4, 0), msdos_mem_get_free(first_mcb, 0));
6410: m_CF = 1;
6411: }
1.1 root 6412: }
6413: }
6414:
6415: inline void msdos_int_21h_49h()
6416: {
1.1.1.14 root 6417: int mcb_seg = SREG(ES) - 1;
6418: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
6419:
6420: if(mcb->mz == 'M' || mcb->mz == 'Z') {
6421: msdos_mem_free(SREG(ES));
6422: } else {
6423: REG16(AX) = 9;
6424: m_CF = 1;
6425: }
1.1 root 6426: }
6427:
6428: inline void msdos_int_21h_4ah()
6429: {
1.1.1.14 root 6430: int mcb_seg = SREG(ES) - 1;
6431: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1 root 6432: int max_paragraphs;
6433:
1.1.1.14 root 6434: if(mcb->mz == 'M' || mcb->mz == 'Z') {
6435: if(msdos_mem_realloc(SREG(ES), REG16(BX), &max_paragraphs)) {
6436: REG16(AX) = 0x08;
6437: REG16(BX) = max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs;
6438: m_CF = 1;
6439: }
6440: } else {
6441: REG16(AX) = 7;
1.1.1.3 root 6442: m_CF = 1;
1.1 root 6443: }
6444: }
6445:
6446: inline void msdos_int_21h_4bh()
6447: {
1.1.1.3 root 6448: char *command = (char *)(mem + SREG_BASE(DS) + REG16(DX));
6449: param_block_t *param = (param_block_t *)(mem + SREG_BASE(ES) + REG16(BX));
1.1 root 6450:
6451: switch(REG8(AL)) {
6452: case 0x00:
6453: case 0x01:
6454: if(msdos_process_exec(command, param, REG8(AL))) {
6455: REG16(AX) = 0x02;
1.1.1.3 root 6456: m_CF = 1;
1.1 root 6457: }
6458: break;
1.1.1.14 root 6459: case 0x03:
6460: {
6461: int fd;
6462: if((fd = _open(command, _O_RDONLY | _O_BINARY)) == -1) {
6463: REG16(AX) = 0x02;
6464: m_CF = 1;
6465: break;
6466: }
6467: int size = _read(fd, file_buffer, sizeof(file_buffer));
6468: _close(fd);
6469:
6470: UINT16 *overlay = (UINT16 *)param;
6471:
6472: // check exe header
6473: exe_header_t *header = (exe_header_t *)file_buffer;
6474: int header_size = 0;
6475: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
6476: header_size = header->header_size * 16;
6477: // relocation
6478: int start_seg = overlay[1];
6479: for(int i = 0; i < header->relocations; i++) {
6480: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
6481: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
6482: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
6483: }
6484: }
6485: memcpy(mem + (overlay[0] << 4), file_buffer + header_size, size - header_size);
6486: }
6487: break;
1.1 root 6488: default:
1.1.1.22 root 6489: 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 6490: REG16(AX) = 0x01;
1.1.1.3 root 6491: m_CF = 1;
1.1 root 6492: break;
6493: }
6494: }
6495:
6496: inline void msdos_int_21h_4ch()
6497: {
6498: msdos_process_terminate(current_psp, REG8(AL), 1);
6499: }
6500:
6501: inline void msdos_int_21h_4dh()
6502: {
6503: REG16(AX) = retval;
6504: }
6505:
6506: inline void msdos_int_21h_4eh()
6507: {
6508: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 6509: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
6510: find_t *find = (find_t *)(mem + dta_laddr);
1.1.1.3 root 6511: char *path = msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 6512: WIN32_FIND_DATA fd;
6513:
1.1.1.14 root 6514: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
6515: find->find_magic = FIND_MAGIC;
6516: find->dta_index = dtainfo - dtalist;
1.1 root 6517: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 6518: dtainfo->allowable_mask = REG8(CL);
6519: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 6520:
1.1.1.14 root 6521: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
6522: dtainfo->allowable_mask &= ~8;
1.1 root 6523: }
1.1.1.14 root 6524: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
6525: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 6526: !msdos_find_file_has_8dot3name(&fd)) {
6527: if(!FindNextFile(dtainfo->find_handle, &fd)) {
6528: FindClose(dtainfo->find_handle);
6529: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6530: break;
6531: }
6532: }
6533: }
1.1.1.13 root 6534: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 6535: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
6536: msdos_find_file_conv_local_time(&fd);
6537: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
6538: find->size = fd.nFileSizeLow;
1.1.1.13 root 6539: strcpy(find->name, msdos_short_name(&fd));
1.1 root 6540: REG16(AX) = 0;
1.1.1.14 root 6541: } else if(dtainfo->allowable_mask & 8) {
1.1 root 6542: find->attrib = 8;
6543: find->size = 0;
6544: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 6545: dtainfo->allowable_mask &= ~8;
1.1 root 6546: REG16(AX) = 0;
6547: } else {
6548: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 6549: m_CF = 1;
1.1 root 6550: }
6551: }
6552:
6553: inline void msdos_int_21h_4fh()
6554: {
6555: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 6556: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
6557: find_t *find = (find_t *)(mem + dta_laddr);
1.1 root 6558: WIN32_FIND_DATA fd;
6559:
1.1.1.14 root 6560: if(find->find_magic != FIND_MAGIC || find->dta_index >= MAX_DTAINFO) {
6561: REG16(AX) = 0x12;
6562: m_CF = 1;
6563: return;
6564: }
6565: dtainfo_t *dtainfo = &dtalist[find->dta_index];
1.1.1.13 root 6566: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
6567: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 6568: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 6569: !msdos_find_file_has_8dot3name(&fd)) {
6570: if(!FindNextFile(dtainfo->find_handle, &fd)) {
6571: FindClose(dtainfo->find_handle);
6572: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6573: break;
6574: }
6575: }
6576: } else {
1.1.1.13 root 6577: FindClose(dtainfo->find_handle);
6578: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6579: }
6580: }
1.1.1.13 root 6581: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 6582: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
6583: msdos_find_file_conv_local_time(&fd);
6584: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
6585: find->size = fd.nFileSizeLow;
1.1.1.13 root 6586: strcpy(find->name, msdos_short_name(&fd));
1.1 root 6587: REG16(AX) = 0;
1.1.1.14 root 6588: } else if(dtainfo->allowable_mask & 8) {
1.1 root 6589: find->attrib = 8;
6590: find->size = 0;
6591: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 6592: dtainfo->allowable_mask &= ~8;
1.1 root 6593: REG16(AX) = 0;
6594: } else {
6595: REG16(AX) = 0x12;
1.1.1.3 root 6596: m_CF = 1;
1.1 root 6597: }
6598: }
6599:
6600: inline void msdos_int_21h_50h()
6601: {
1.1.1.8 root 6602: if(current_psp != REG16(BX)) {
6603: process_t *process = msdos_process_info_get(current_psp);
6604: if(process != NULL) {
6605: process->psp = REG16(BX);
6606: }
6607: current_psp = REG16(BX);
1.1.1.23! root 6608: msdos_sda_update(current_psp);
1.1.1.8 root 6609: }
1.1 root 6610: }
6611:
6612: inline void msdos_int_21h_51h()
6613: {
6614: REG16(BX) = current_psp;
6615: }
6616:
6617: inline void msdos_int_21h_52h()
6618: {
1.1.1.3 root 6619: SREG(ES) = (DOS_INFO_BASE >> 4);
6620: i386_load_segment_descriptor(ES);
1.1 root 6621: REG16(BX) = (DOS_INFO_BASE & 0x0f);
6622: }
6623:
6624: inline void msdos_int_21h_54h()
6625: {
6626: process_t *process = msdos_process_info_get(current_psp);
6627:
6628: REG8(AL) = process->verify;
6629: }
6630:
6631: inline void msdos_int_21h_55h()
6632: {
6633: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
6634:
6635: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
6636: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
6637: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
6638: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
6639: psp->parent_psp = current_psp;
6640: }
6641:
6642: inline void msdos_int_21h_56h(int lfn)
6643: {
6644: char src[MAX_PATH], dst[MAX_PATH];
1.1.1.3 root 6645: strcpy(src, msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn));
6646: strcpy(dst, msdos_trimmed_path((char *)(mem + SREG_BASE(ES) + REG16(DI)), lfn));
1.1 root 6647:
6648: if(rename(src, dst)) {
6649: REG16(AX) = errno;
1.1.1.3 root 6650: m_CF = 1;
1.1 root 6651: }
6652: }
6653:
6654: inline void msdos_int_21h_57h()
6655: {
6656: FILETIME time, local;
1.1.1.14 root 6657: FILETIME *ctime, *atime, *mtime;
1.1.1.21 root 6658: HANDLE hHandle;
1.1 root 6659:
1.1.1.21 root 6660: if((hHandle = (HANDLE)_get_osfhandle(REG16(BX))) == INVALID_HANDLE_VALUE) {
1.1.1.14 root 6661: REG16(AX) = (UINT16)GetLastError();
6662: m_CF = 1;
6663: return;
6664: }
6665: ctime = atime = mtime = NULL;
6666:
1.1 root 6667: switch(REG8(AL)) {
6668: case 0x00:
1.1.1.6 root 6669: case 0x01:
1.1.1.14 root 6670: mtime = &time;
1.1.1.6 root 6671: break;
6672: case 0x04:
6673: case 0x05:
1.1.1.14 root 6674: atime = &time;
1.1 root 6675: break;
1.1.1.6 root 6676: case 0x06:
6677: case 0x07:
1.1.1.14 root 6678: ctime = &time;
6679: break;
6680: default:
1.1.1.22 root 6681: 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 6682: REG16(AX) = 0x01;
6683: m_CF = 1;
6684: return;
6685: }
6686: if(REG8(AL) & 1) {
1.1 root 6687: DosDateTimeToFileTime(REG16(DX), REG16(CX), &local);
6688: LocalFileTimeToFileTime(&local, &time);
1.1.1.21 root 6689: if(!SetFileTime(hHandle, ctime, atime, mtime)) {
1.1 root 6690: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 6691: m_CF = 1;
1.1 root 6692: }
1.1.1.14 root 6693: } else {
1.1.1.21 root 6694: if(!GetFileTime(hHandle, ctime, atime, mtime)) {
1.1.1.14 root 6695: // assume a device and use the current time
6696: GetSystemTimeAsFileTime(&time);
6697: }
6698: FileTimeToLocalFileTime(&time, &local);
6699: FileTimeToDosDateTime(&local, ®16(DX), ®16(CX));
1.1 root 6700: }
6701: }
6702:
6703: inline void msdos_int_21h_58h()
6704: {
6705: switch(REG8(AL)) {
6706: case 0x00:
1.1.1.7 root 6707: REG16(AX) = malloc_strategy;
6708: break;
6709: case 0x01:
6710: switch(REG16(BX)) {
6711: case 0x0000:
6712: case 0x0001:
6713: case 0x0002:
6714: case 0x0040:
6715: case 0x0041:
6716: case 0x0042:
6717: case 0x0080:
6718: case 0x0081:
6719: case 0x0082:
6720: malloc_strategy = REG16(BX);
1.1.1.23! root 6721: msdos_sda_update(current_psp);
1.1.1.7 root 6722: break;
6723: default:
1.1.1.22 root 6724: 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 6725: REG16(AX) = 0x01;
6726: m_CF = 1;
6727: break;
6728: }
6729: break;
6730: case 0x02:
1.1.1.19 root 6731: REG8(AL) = msdos_mem_get_umb_linked() ? 1 : 0;
1.1.1.7 root 6732: break;
6733: case 0x03:
6734: switch(REG16(BX)) {
6735: case 0x0000:
1.1.1.19 root 6736: msdos_mem_unlink_umb();
6737: break;
1.1.1.7 root 6738: case 0x0001:
1.1.1.19 root 6739: msdos_mem_link_umb();
1.1.1.7 root 6740: break;
6741: default:
1.1.1.22 root 6742: 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 6743: REG16(AX) = 0x01;
6744: m_CF = 1;
6745: break;
6746: }
1.1 root 6747: break;
6748: default:
1.1.1.22 root 6749: 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 6750: REG16(AX) = 0x01;
1.1.1.3 root 6751: m_CF = 1;
1.1 root 6752: break;
6753: }
6754: }
6755:
6756: inline void msdos_int_21h_59h()
6757: {
1.1.1.23! root 6758: sda_t *sda = (sda_t *)(mem + SDA_TOP);
! 6759:
! 6760: REG16(AX) = sda->extended_error_code;
! 6761: REG8(BH) = sda->error_class;
! 6762: REG8(BL) = sda->suggested_action;
! 6763: REG8(CH) = sda->locus_of_last_error;
1.1 root 6764: }
6765:
6766: inline void msdos_int_21h_5ah()
6767: {
1.1.1.3 root 6768: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 6769: int len = strlen(path);
6770: char tmp[MAX_PATH];
6771:
6772: if(GetTempFileName(path, "TMP", 0, tmp)) {
6773: int fd = _open(tmp, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
6774:
6775: SetFileAttributes(tmp, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
6776: REG16(AX) = fd;
6777: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 6778: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 6779:
6780: strcpy(path, tmp);
6781: int dx = REG16(DX) + len;
1.1.1.3 root 6782: int ds = SREG(DS);
1.1 root 6783: while(dx > 0xffff) {
6784: dx -= 0x10;
6785: ds++;
6786: }
6787: REG16(DX) = dx;
1.1.1.3 root 6788: SREG(DS) = ds;
6789: i386_load_segment_descriptor(DS);
1.1 root 6790: } else {
6791: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 6792: m_CF = 1;
1.1 root 6793: }
6794: }
6795:
6796: inline void msdos_int_21h_5bh()
6797: {
1.1.1.3 root 6798: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 6799:
6800: if(_access(path, 0) == 0) {
6801: // already exists
6802: REG16(AX) = 0x50;
1.1.1.3 root 6803: m_CF = 1;
1.1 root 6804: } else {
6805: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
6806:
6807: if(fd != -1) {
6808: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
6809: REG16(AX) = fd;
6810: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 6811: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 6812: } else {
6813: REG16(AX) = errno;
1.1.1.3 root 6814: m_CF = 1;
1.1 root 6815: }
6816: }
6817: }
6818:
6819: inline void msdos_int_21h_5ch()
6820: {
6821: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 6822: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 6823:
1.1.1.20 root 6824: if(fd < process->max_files && file_handler[fd].valid) {
1.1 root 6825: if(REG8(AL) == 0 || REG8(AL) == 1) {
6826: static int modes[2] = {_LK_LOCK, _LK_UNLCK};
1.1.1.20 root 6827: UINT32 pos = _tell(fd);
6828: _lseek(fd, (REG16(CX) << 16) | REG16(DX), SEEK_SET);
6829: if(_locking(fd, modes[REG8(AL)], (REG16(SI) << 16) | REG16(DI))) {
1.1 root 6830: REG16(AX) = errno;
1.1.1.3 root 6831: m_CF = 1;
1.1 root 6832: }
1.1.1.20 root 6833: _lseek(fd, pos, SEEK_SET);
1.1 root 6834: // some seconds may be passed in _locking()
6835: hardware_update();
6836: } else {
6837: REG16(AX) = 0x01;
1.1.1.3 root 6838: m_CF = 1;
1.1 root 6839: }
6840: } else {
6841: REG16(AX) = 0x06;
1.1.1.3 root 6842: m_CF = 1;
1.1 root 6843: }
6844: }
6845:
1.1.1.22 root 6846: inline void msdos_int_21h_5dh()
6847: {
6848: switch(REG8(AL)) {
6849: case 0x06: // get address of dos swappable data area
1.1.1.23! root 6850: SREG(DS) = (SDA_TOP >> 4);
! 6851: i386_load_segment_descriptor(DS);
! 6852: REG16(SI) = offsetof(sda_t, crit_error_flag);
! 6853: REG16(CX) = 0x80;
! 6854: REG16(DX) = 0x1a;
! 6855: break;
! 6856: case 0x0b: // get dos swappable data areas
1.1.1.22 root 6857: REG16(AX) = 0x01;
6858: m_CF = 1;
6859: break;
6860: case 0x08: // set redirected printer mode
6861: case 0x09: // flush redirected printer output
6862: case 0x0a: // set extended error information
6863: break;
6864: default:
6865: 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));
6866: REG16(AX) = 0x01;
6867: m_CF = 1;
6868: break;
6869: }
6870: }
6871:
1.1 root 6872: inline void msdos_int_21h_60h(int lfn)
6873: {
1.1.1.14 root 6874: char full[MAX_PATH], *path;
6875:
1.1 root 6876: if(lfn) {
1.1.1.14 root 6877: char *name;
6878: *full = '\0';
1.1.1.3 root 6879: GetFullPathName((char *)(mem + SREG_BASE(DS) + REG16(SI)), MAX_PATH, full, &name);
1.1.1.14 root 6880: switch(REG8(CL)) {
6881: case 1:
6882: GetShortPathName(full, full, MAX_PATH);
6883: my_strupr(full);
6884: break;
6885: case 2:
6886: GetLongPathName(full, full, MAX_PATH);
6887: break;
6888: }
6889: path = full;
6890: } else {
6891: path = msdos_short_full_path((char *)(mem + SREG_BASE(DS) + REG16(SI)));
6892: }
6893: if(*path != '\0') {
6894: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), path);
1.1 root 6895: } else {
1.1.1.14 root 6896: REG16(AX) = (UINT16)GetLastError();
6897: m_CF = 1;
1.1 root 6898: }
6899: }
6900:
6901: inline void msdos_int_21h_61h()
6902: {
6903: REG8(AL) = 0;
6904: }
6905:
6906: inline void msdos_int_21h_62h()
6907: {
6908: REG16(BX) = current_psp;
6909: }
6910:
6911: inline void msdos_int_21h_63h()
6912: {
6913: switch(REG8(AL)) {
6914: case 0x00:
1.1.1.3 root 6915: SREG(DS) = (DBCS_TABLE >> 4);
6916: i386_load_segment_descriptor(DS);
1.1 root 6917: REG16(SI) = (DBCS_TABLE & 0x0f);
6918: REG8(AL) = 0x00;
6919: break;
1.1.1.22 root 6920: case 0x01: // set korean input mode
6921: case 0x02: // get korean input mode
6922: REG8(AL) = 0xff; // not supported
6923: break;
1.1 root 6924: default:
1.1.1.22 root 6925: 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 6926: REG16(AX) = 0x01;
1.1.1.3 root 6927: m_CF = 1;
1.1 root 6928: break;
6929: }
6930: }
6931:
6932: inline void msdos_int_21h_65h()
6933: {
6934: char tmp[0x10000];
6935:
6936: switch(REG8(AL)) {
1.1.1.17 root 6937: case 0x01:
6938: if(REG16(CX) >= 5) {
1.1.1.19 root 6939: UINT8 data[1 + 2 + 2 + 2 + sizeof(country_info_t)];
1.1.1.17 root 6940: if(REG16(CX) > sizeof(data)) // cx = actual transfer size
6941: REG16(CX) = sizeof(data);
6942: ZeroMemory(data, sizeof(data));
6943: data[0] = 0x01;
6944: *(UINT16 *)(data + 1) = REG16(CX) - 3;
1.1.1.19 root 6945: *(UINT16 *)(data + 3) = get_country_info((country_info_t*)(data + 7));
1.1.1.17 root 6946: *(UINT16 *)(data + 5) = active_code_page;
6947: memcpy(mem + SREG_BASE(ES) + REG16(DI), data, REG16(CX));
6948: REG16(AX) = active_code_page;
6949: } else {
6950: REG16(AX) = 1;
6951: m_CF = 1;
6952: }
6953: break;
6954: case 0x02:
6955: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x02;
6956: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (UPPERTABLE_TOP & 0x0f);
6957: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (UPPERTABLE_TOP >> 4);
6958: REG16(AX) = active_code_page;
6959: REG16(CX) = 0x05;
6960: break;
1.1.1.23! root 6961: case 0x03:
! 6962: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x02;
! 6963: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (LOWERTABLE_TOP & 0x0f);
! 6964: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (LOWERTABLE_TOP >> 4);
! 6965: REG16(AX) = active_code_page;
! 6966: REG16(CX) = 0x05;
! 6967: break;
1.1.1.17 root 6968: case 0x04:
6969: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x04;
6970: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_UPPERTABLE_TOP & 0x0f);
6971: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_UPPERTABLE_TOP >> 4);
6972: REG16(AX) = active_code_page;
6973: REG16(CX) = 0x05;
6974: break;
6975: case 0x05:
6976: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x05;
6977: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_TERMINATOR_TOP & 0x0f);
6978: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_TERMINATOR_TOP >> 4);
6979: REG16(AX) = active_code_page;
6980: REG16(CX) = 0x05;
6981: break;
6982: case 0x06:
6983: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x06;
6984: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (COLLATING_TABLE_TOP & 0x0f);
6985: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (COLLATING_TABLE_TOP >> 4);
6986: REG16(AX) = active_code_page;
6987: REG16(CX) = 0x05;
6988: break;
1.1 root 6989: case 0x07:
1.1.1.3 root 6990: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x07;
6991: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (DBCS_TOP & 0x0f);
6992: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (DBCS_TOP >> 4);
1.1.1.17 root 6993: REG16(AX) = active_code_page;
1.1 root 6994: REG16(CX) = 0x05;
6995: break;
6996: case 0x20:
1.1.1.19 root 6997: memset(tmp, 0, sizeof(tmp));
6998: tmp[0] = REG8(DL);
1.1 root 6999: my_strupr(tmp);
7000: REG8(DL) = tmp[0];
7001: break;
7002: case 0x21:
7003: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 7004: memcpy(tmp, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 7005: my_strupr(tmp);
1.1.1.3 root 7006: memcpy(mem + SREG_BASE(DS) + REG16(DX), tmp, REG16(CX));
1.1 root 7007: break;
7008: case 0x22:
1.1.1.3 root 7009: my_strupr((char *)(mem + SREG_BASE(DS) + REG16(DX)));
1.1 root 7010: break;
7011: default:
1.1.1.22 root 7012: 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 7013: REG16(AX) = 0x01;
1.1.1.3 root 7014: m_CF = 1;
1.1 root 7015: break;
7016: }
7017: }
7018:
7019: inline void msdos_int_21h_66h()
7020: {
7021: switch(REG8(AL)) {
7022: case 0x01:
7023: REG16(BX) = active_code_page;
7024: REG16(DX) = system_code_page;
7025: break;
7026: case 0x02:
7027: if(active_code_page == REG16(BX)) {
7028: REG16(AX) = 0xeb41;
7029: } else if(_setmbcp(REG16(BX)) == 0) {
7030: active_code_page = REG16(BX);
1.1.1.17 root 7031: msdos_nls_tables_update();
1.1 root 7032: REG16(AX) = 0xeb41;
7033: } else {
7034: REG16(AX) = 0x25;
1.1.1.3 root 7035: m_CF = 1;
1.1 root 7036: }
7037: break;
7038: default:
1.1.1.22 root 7039: 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 7040: REG16(AX) = 0x01;
1.1.1.3 root 7041: m_CF = 1;
1.1 root 7042: break;
7043: }
7044: }
7045:
7046: inline void msdos_int_21h_67h()
7047: {
7048: process_t *process = msdos_process_info_get(current_psp);
7049:
7050: if(REG16(BX) <= MAX_FILES) {
7051: process->max_files = max(REG16(BX), 20);
7052: } else {
7053: REG16(AX) = 0x08;
1.1.1.3 root 7054: m_CF = 1;
1.1 root 7055: }
7056: }
7057:
7058: inline void msdos_int_21h_68h()
7059: {
7060: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 7061: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 7062:
1.1.1.20 root 7063: if(fd < process->max_files && file_handler[fd].valid) {
7064: // fflush(_fdopen(fd, ""));
1.1 root 7065: } else {
7066: REG16(AX) = 0x06;
1.1.1.3 root 7067: m_CF = 1;
1.1 root 7068: }
7069: }
7070:
7071: inline void msdos_int_21h_69h()
7072: {
1.1.1.3 root 7073: drive_info_t *info = (drive_info_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 7074: char path[] = "A:\\";
7075: char volume_label[MAX_PATH];
7076: DWORD serial_number = 0;
7077: char file_system[MAX_PATH];
7078:
7079: if(REG8(BL) == 0) {
7080: path[0] = 'A' + _getdrive() - 1;
7081: } else {
7082: path[0] = 'A' + REG8(BL) - 1;
7083: }
7084:
7085: switch(REG8(AL)) {
7086: case 0x00:
7087: if(GetVolumeInformation(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) {
7088: info->info_level = 0;
7089: info->serial_number = serial_number;
7090: memset(info->volume_label, 0x20, 11);
7091: memcpy(info->volume_label, volume_label, min(strlen(volume_label), 11));
7092: memset(info->file_system, 0x20, 8);
7093: memcpy(info->file_system, file_system, min(strlen(file_system), 8));
7094: } else {
7095: REG16(AX) = errno;
1.1.1.3 root 7096: m_CF = 1;
1.1 root 7097: }
7098: break;
7099: case 0x01:
7100: REG16(AX) = 0x03;
1.1.1.3 root 7101: m_CF = 1;
1.1 root 7102: }
7103: }
7104:
7105: inline void msdos_int_21h_6ah()
7106: {
7107: REG8(AH) = 0x68;
7108: msdos_int_21h_68h();
7109: }
7110:
7111: inline void msdos_int_21h_6bh()
7112: {
7113: REG8(AL) = 0;
7114: }
7115:
7116: inline void msdos_int_21h_6ch(int lfn)
7117: {
1.1.1.3 root 7118: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn);
1.1 root 7119: int mode = REG8(BL) & 0x03;
7120:
7121: if(mode < 0x03) {
1.1.1.20 root 7122: if(_access(path, 0) == 0 || strncmp(path, "EMMXXXX0", 8) == 0) {
1.1 root 7123: // file exists
7124: if(REG8(DL) & 1) {
1.1.1.11 root 7125: int fd = -1;
7126: UINT16 info;
1.1 root 7127:
1.1.1.11 root 7128: if(msdos_is_con_path(path)) {
1.1.1.13 root 7129: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 7130: info = 0x80d3;
1.1.1.14 root 7131: } else if(msdos_is_nul_path(path)) {
7132: fd = msdos_open("NUL", file_mode[mode].mode);
7133: info = 0x80d3;
1.1.1.20 root 7134: } else if(strncmp(path, "EMMXXXX0", 8) == 0) {
7135: fd = msdos_open("NUL", file_mode[mode].mode);
7136: info = 0x80d3;
1.1.1.11 root 7137: } else {
1.1.1.13 root 7138: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 7139: info = msdos_drive_number(path);
7140: }
1.1 root 7141: if(fd != -1) {
7142: REG16(AX) = fd;
7143: REG16(CX) = 1;
1.1.1.11 root 7144: msdos_file_handler_open(fd, path, _isatty(fd), mode, info, current_psp);
1.1.1.20 root 7145: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 7146: } else {
7147: REG16(AX) = errno;
1.1.1.3 root 7148: m_CF = 1;
1.1 root 7149: }
7150: } else if(REG8(DL) & 2) {
7151: int attr = GetFileAttributes(path);
7152: int fd = -1;
1.1.1.11 root 7153: UINT16 info;
1.1 root 7154:
1.1.1.11 root 7155: if(msdos_is_con_path(path)) {
1.1.1.13 root 7156: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 7157: info = 0x80d3;
1.1.1.14 root 7158: } else if(msdos_is_nul_path(path)) {
7159: fd = msdos_open("NUL", file_mode[mode].mode);
7160: info = 0x80d3;
1.1.1.20 root 7161: } else if(strncmp(path, "EMMXXXX0", 8) == 0) {
7162: fd = msdos_open("NUL", file_mode[mode].mode);
7163: info = 0x80d3;
1.1 root 7164: } else {
7165: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
1.1.1.11 root 7166: info = msdos_drive_number(path);
1.1 root 7167: }
7168: if(fd != -1) {
7169: if(attr == -1) {
7170: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
7171: }
7172: SetFileAttributes(path, attr);
7173: REG16(AX) = fd;
7174: REG16(CX) = 3;
1.1.1.11 root 7175: msdos_file_handler_open(fd, path, _isatty(fd), 2, info, current_psp);
1.1.1.20 root 7176: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 7177: } else {
7178: REG16(AX) = errno;
1.1.1.3 root 7179: m_CF = 1;
1.1 root 7180: }
7181: } else {
7182: REG16(AX) = 0x50;
1.1.1.3 root 7183: m_CF = 1;
1.1 root 7184: }
7185: } else {
7186: // file not exists
7187: if(REG8(DL) & 0x10) {
7188: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
7189:
7190: if(fd != -1) {
7191: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
7192: REG16(AX) = fd;
7193: REG16(CX) = 2;
7194: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 7195: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 7196: } else {
7197: REG16(AX) = errno;
1.1.1.3 root 7198: m_CF = 1;
1.1 root 7199: }
7200: } else {
7201: REG16(AX) = 0x02;
1.1.1.3 root 7202: m_CF = 1;
1.1 root 7203: }
7204: }
7205: } else {
7206: REG16(AX) = 0x0c;
1.1.1.3 root 7207: m_CF = 1;
1.1 root 7208: }
7209: }
7210:
7211: inline void msdos_int_21h_710dh()
7212: {
7213: // reset drive
7214: }
7215:
1.1.1.17 root 7216: inline void msdos_int_21h_7141h(int lfn)
7217: {
7218: if(REG16(SI) == 0) {
7219: msdos_int_21h_41h(lfn);
7220: return;
7221: }
7222: if(REG16(SI) != 1) {
7223: REG16(AX) = 5;
7224: m_CF = 1;
7225: }
7226: /* wild card and matching attributes... */
7227: char tmp[MAX_PATH * 2];
7228: // copy search pathname (and quick check overrun)
7229: ZeroMemory(tmp, sizeof(tmp));
7230: tmp[MAX_PATH - 1] = '\0';
7231: tmp[MAX_PATH] = 1;
7232: strncpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(DX)), MAX_PATH);
7233:
7234: if(tmp[MAX_PATH - 1] != '\0' || tmp[MAX_PATH] != 1) {
7235: REG16(AX) = 1;
7236: m_CF = 1;
7237: return;
7238: }
7239: for(char *s = tmp; *s; ++s) {
7240: if(*s == '/') {
7241: *s = '\\';
7242: }
7243: }
7244: char *tmp_name = (char *)_mbsrchr((unsigned char *)tmp, '\\');
7245: if(tmp_name) {
7246: ++tmp_name;
7247: } else {
7248: tmp_name = strchr(tmp, ':');
7249: tmp_name = tmp_name ? tmp_name + 1 : tmp;
7250: }
7251:
7252: WIN32_FIND_DATAA fd;
7253: HANDLE fh = FindFirstFileA(tmp, &fd);
7254: if(fh == INVALID_HANDLE_VALUE) {
7255: REG16(AX) = 2;
7256: m_CF = 1;
7257: return;
7258: }
7259: do {
7260: if(msdos_find_file_check_attribute(fd.dwFileAttributes, REG8(CL), REG8(CH)) && msdos_find_file_has_8dot3name(&fd)) {
7261: strcpy(tmp_name, fd.cFileName);
7262: if(remove(msdos_trimmed_path(tmp, lfn))) {
7263: REG16(AX) = 5;
7264: m_CF = 1;
7265: break;
7266: }
7267: }
7268: } while(FindNextFileA(fh, &fd));
7269: if(!m_CF) {
7270: if(GetLastError() != ERROR_NO_MORE_FILES) {
7271: m_CF = 1;
7272: REG16(AX) = 2;
7273: }
7274: }
7275: FindClose(fh);
7276: }
7277:
1.1 root 7278: inline void msdos_int_21h_714eh()
7279: {
7280: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 7281: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
7282: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 7283: WIN32_FIND_DATA fd;
7284:
1.1.1.13 root 7285: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
7286: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
7287: FindClose(dtainfo->find_handle);
7288: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7289: }
7290: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 7291: dtainfo->allowable_mask = REG8(CL);
7292: dtainfo->required_mask = REG8(CH);
7293: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 7294:
1.1.1.14 root 7295: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
7296: dtainfo->allowable_mask &= ~8;
1.1 root 7297: }
1.1.1.14 root 7298: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
7299: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 7300: if(!FindNextFile(dtainfo->find_handle, &fd)) {
7301: FindClose(dtainfo->find_handle);
7302: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7303: break;
7304: }
7305: }
7306: }
1.1.1.13 root 7307: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 7308: find->attrib = fd.dwFileAttributes;
7309: msdos_find_file_conv_local_time(&fd);
7310: if(REG16(SI) == 0) {
7311: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
7312: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
7313: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
7314: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
7315: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
7316: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
7317: } else {
7318: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
7319: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
7320: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
7321: }
7322: find->size_hi = fd.nFileSizeHigh;
7323: find->size_lo = fd.nFileSizeLow;
7324: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 7325: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14 root 7326: REG16(AX) = dtainfo - dtalist + 1;
7327: } else if(dtainfo->allowable_mask & 8) {
1.1 root 7328: // volume label
7329: find->attrib = 8;
7330: find->size_hi = find->size_lo = 0;
7331: strcpy(find->full_name, process->volume_label);
7332: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 7333: dtainfo->allowable_mask &= ~8;
7334: REG16(AX) = dtainfo - dtalist + 1;
1.1 root 7335: } else {
7336: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 7337: m_CF = 1;
1.1 root 7338: }
7339: }
7340:
7341: inline void msdos_int_21h_714fh()
7342: {
7343: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 7344: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 7345: WIN32_FIND_DATA fd;
7346:
1.1.1.14 root 7347: if(REG16(BX) - 1u >= MAX_DTAINFO) {
7348: REG16(AX) = 6;
1.1.1.13 root 7349: m_CF = 1;
7350: return;
7351: }
1.1.1.14 root 7352: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 7353: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
7354: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 7355: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 7356: if(!FindNextFile(dtainfo->find_handle, &fd)) {
7357: FindClose(dtainfo->find_handle);
7358: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7359: break;
7360: }
7361: }
7362: } else {
1.1.1.13 root 7363: FindClose(dtainfo->find_handle);
7364: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7365: }
7366: }
1.1.1.13 root 7367: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 7368: find->attrib = fd.dwFileAttributes;
7369: msdos_find_file_conv_local_time(&fd);
7370: if(REG16(SI) == 0) {
7371: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
7372: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
7373: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
7374: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
7375: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
7376: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
7377: } else {
7378: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
7379: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
7380: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
7381: }
7382: find->size_hi = fd.nFileSizeHigh;
7383: find->size_lo = fd.nFileSizeLow;
7384: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 7385: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14 root 7386: } else if(dtainfo->allowable_mask & 8) {
1.1 root 7387: // volume label
7388: find->attrib = 8;
7389: find->size_hi = find->size_lo = 0;
7390: strcpy(find->full_name, process->volume_label);
7391: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 7392: dtainfo->allowable_mask &= ~8;
1.1 root 7393: } else {
7394: REG16(AX) = 0x12;
1.1.1.3 root 7395: m_CF = 1;
1.1 root 7396: }
7397: }
7398:
7399: inline void msdos_int_21h_71a0h()
7400: {
7401: DWORD max_component_len, file_sys_flag;
7402:
1.1.1.14 root 7403: 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))) {
7404: REG16(BX) = (UINT16)file_sys_flag & (FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK | FILE_VOLUME_IS_COMPRESSED);
7405: REG16(BX) |= 0x4000; // supports LFN functions
1.1 root 7406: REG16(CX) = (UINT16)max_component_len; // 255
7407: REG16(DX) = (UINT16)max_component_len + 5; // 260
7408: } else {
7409: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 7410: m_CF = 1;
1.1 root 7411: }
7412: }
7413:
7414: inline void msdos_int_21h_71a1h()
7415: {
1.1.1.14 root 7416: if(REG16(BX) - 1u >= MAX_DTAINFO) {
7417: REG16(AX) = 6;
1.1.1.13 root 7418: m_CF = 1;
7419: return;
7420: }
1.1.1.14 root 7421: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 7422: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
7423: FindClose(dtainfo->find_handle);
7424: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7425: }
7426: }
7427:
7428: inline void msdos_int_21h_71a6h()
7429: {
7430: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 7431: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
7432:
1.1.1.3 root 7433: UINT8 *buffer = (UINT8 *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 7434: struct _stat64 status;
7435: DWORD serial_number = 0;
7436:
1.1.1.20 root 7437: if(fd < process->max_files && file_handler[fd].valid) {
7438: if(_fstat64(fd, &status) == 0) {
7439: if(file_handler[fd].path[1] == ':') {
1.1 root 7440: // NOTE: we need to consider the network file path "\\host\share\"
7441: char volume[] = "A:\\";
1.1.1.20 root 7442: volume[0] = file_handler[fd].path[1];
1.1 root 7443: GetVolumeInformation(volume, NULL, 0, &serial_number, NULL, NULL, NULL, 0);
7444: }
1.1.1.20 root 7445: *(UINT32 *)(buffer + 0x00) = GetFileAttributes(file_handler[fd].path);
1.1 root 7446: *(UINT32 *)(buffer + 0x04) = (UINT32)(status.st_ctime & 0xffffffff);
7447: *(UINT32 *)(buffer + 0x08) = (UINT32)((status.st_ctime >> 32) & 0xffffffff);
7448: *(UINT32 *)(buffer + 0x0c) = (UINT32)(status.st_atime & 0xffffffff);
7449: *(UINT32 *)(buffer + 0x10) = (UINT32)((status.st_atime >> 32) & 0xffffffff);
7450: *(UINT32 *)(buffer + 0x14) = (UINT32)(status.st_mtime & 0xffffffff);
7451: *(UINT32 *)(buffer + 0x18) = (UINT32)((status.st_mtime >> 32) & 0xffffffff);
7452: *(UINT32 *)(buffer + 0x1c) = serial_number;
7453: *(UINT32 *)(buffer + 0x20) = (UINT32)((status.st_size >> 32) & 0xffffffff);
7454: *(UINT32 *)(buffer + 0x24) = (UINT32)(status.st_size & 0xffffffff);
7455: *(UINT32 *)(buffer + 0x28) = status.st_nlink;
1.1.1.14 root 7456: // this is dummy id and it will be changed when it is reopened...
1.1 root 7457: *(UINT32 *)(buffer + 0x2c) = 0;
1.1.1.20 root 7458: *(UINT32 *)(buffer + 0x30) = file_handler[fd].id;
1.1 root 7459: } else {
7460: REG16(AX) = errno;
1.1.1.3 root 7461: m_CF = 1;
1.1 root 7462: }
7463: } else {
7464: REG16(AX) = 0x06;
1.1.1.3 root 7465: m_CF = 1;
1.1 root 7466: }
7467: }
7468:
7469: inline void msdos_int_21h_71a7h()
7470: {
7471: switch(REG8(BL)) {
7472: case 0x00:
1.1.1.3 root 7473: if(!FileTimeToDosDateTime((FILETIME *)(mem + SREG_BASE(DS) + REG16(SI)), ®16(DX), ®16(CX))) {
1.1 root 7474: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 7475: m_CF = 1;
1.1 root 7476: }
7477: break;
7478: case 0x01:
7479: // NOTE: we need to check BH that shows 10-millisecond untils past time in CX
1.1.1.3 root 7480: if(!DosDateTimeToFileTime(REG16(DX), REG16(CX), (FILETIME *)(mem + SREG_BASE(ES) + REG16(DI)))) {
1.1 root 7481: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 7482: m_CF = 1;
1.1 root 7483: }
7484: break;
7485: default:
1.1.1.22 root 7486: 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 7487: REG16(AX) = 0x01;
1.1.1.3 root 7488: m_CF = 1;
1.1 root 7489: break;
7490: }
7491: }
7492:
7493: inline void msdos_int_21h_71a8h()
7494: {
7495: if(REG8(DH) == 0) {
7496: char tmp[MAX_PATH], fcb[MAX_PATH];
1.1.1.3 root 7497: strcpy(tmp, msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 7498: memset(fcb, 0x20, sizeof(fcb));
7499: int len = strlen(tmp);
1.1.1.21 root 7500: for(int i = 0, pos = 0; i < len; i++) {
1.1 root 7501: if(tmp[i] == '.') {
7502: pos = 8;
7503: } else {
7504: if(msdos_lead_byte_check(tmp[i])) {
7505: fcb[pos++] = tmp[i++];
7506: }
7507: fcb[pos++] = tmp[i];
7508: }
7509: }
1.1.1.3 root 7510: memcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), fcb, 11);
1.1 root 7511: } else {
1.1.1.3 root 7512: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 7513: }
7514: }
7515:
1.1.1.22 root 7516: inline void msdos_int_21h_71aah()
7517: {
7518: char drv[] = "A:", path[MAX_PATH];
7519: char *hoge=(char *)(mem + SREG_BASE(DS) + REG16(DX));
7520:
7521: if(REG8(BL) == 0) {
7522: drv[0] = 'A' + _getdrive() - 1;
7523: } else {
7524: drv[0] = 'A' + REG8(BL) - 1;
7525: }
7526: switch(REG8(BH)) {
7527: case 0x00:
7528: if(DefineDosDevice(0, drv, (char *)(mem + SREG_BASE(DS) + REG16(DX))) == 0) {
7529: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
7530: if(GetLogicalDrives() & bits) {
7531: REG16(AX) = 0x0f; // invalid drive
7532: } else {
7533: REG16(AX) = 0x03; // path not found
7534: }
7535: m_CF = 1;
7536: }
7537: break;
7538: case 0x01:
7539: if(DefineDosDevice(DDD_REMOVE_DEFINITION, drv, NULL) == 0) {
7540: REG16(AX) = 0x0f; // invalid drive
7541: m_CF = 1;
7542: }
7543: break;
7544: case 0x02:
7545: if(QueryDosDevice(drv, path, MAX_PATH) == 0) {
7546: REG16(AX) = 0x0f; // invalid drive
7547: m_CF = 1;
7548: } else if(strncmp(path, "\\??\\", 4) != 0) {
7549: REG16(AX) = 0x0f; // invalid drive
7550: m_CF = 1;
7551: } else {
7552: strcpy((char *)(mem + SREG_BASE(DS) + REG16(DX)), path + 4);
7553: }
7554: break;
7555: default:
7556: 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));
7557: REG16(AX) = 0x01;
7558: m_CF = 1;
7559: break;
7560: }
7561: }
7562:
1.1.1.14 root 7563: inline void msdos_int_21h_7300h()
7564: {
7565: if(REG8(AL) == 0) {
7566: REG8(AL) = REG8(CL);
7567: REG8(AH) = 0;
7568: } else {
7569: REG16(AX) = 0x01;
7570: m_CF = 1;
7571: }
7572: }
7573:
7574: inline void msdos_int_21h_7302h()
7575: {
7576: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
7577: UINT16 seg, ofs;
7578:
7579: if(REG16(CX) < 0x3f) {
7580: REG8(AL) = 0x18;
7581: m_CF = 1;
7582: } else if(!msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
7583: REG8(AL) = 0xff;
7584: m_CF = 1;
7585: } else {
7586: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 2, mem + (seg << 4) + ofs, sizeof(dpb_t));
7587: }
7588: }
7589:
1.1 root 7590: inline void msdos_int_21h_7303h()
7591: {
1.1.1.3 root 7592: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
7593: ext_space_info_t *info = (ext_space_info_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 7594: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
7595:
7596: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
7597: info->size_of_structure = sizeof(ext_space_info_t);
7598: info->structure_version = 0;
7599: info->sectors_per_cluster = sectors_per_cluster;
7600: info->bytes_per_sector = bytes_per_sector;
7601: info->available_clusters_on_drive = free_clusters;
7602: info->total_clusters_on_drive = total_clusters;
7603: info->available_sectors_on_drive = sectors_per_cluster * free_clusters;
7604: info->total_sectors_on_drive = sectors_per_cluster * total_clusters;
7605: info->available_allocation_units = free_clusters; // ???
7606: info->total_allocation_units = total_clusters; // ???
7607: } else {
7608: REG16(AX) = errno;
1.1.1.3 root 7609: m_CF = 1;
1.1 root 7610: }
7611: }
7612:
7613: inline void msdos_int_25h()
7614: {
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: HANDLE hFile = CreateFile(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
7636: if(hFile == INVALID_HANDLE_VALUE) {
7637: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 7638: m_CF = 1;
1.1 root 7639: } else {
1.1.1.19 root 7640: UINT32 top_sector = REG16(DX);
7641: UINT16 sector_num = REG16(CX);
7642: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX);
7643:
7644: if(sector_num == 0xffff) {
7645: top_sector = *(UINT32 *)(mem + buffer_addr + 0);
7646: sector_num = *(UINT16 *)(mem + buffer_addr + 4);
7647: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6);
7648: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8);
7649: buffer_addr = (seg << 4) + ofs;
7650: }
7651: // if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
7652: // REG8(AL) = 0x02; // drive not ready
7653: // m_CF = 1;
7654: // } else
7655: if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1.1 root 7656: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 7657: m_CF = 1;
1.1.1.19 root 7658: } else if(ReadFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 7659: REG8(AL) = 0x0b; // read error
1.1.1.3 root 7660: m_CF = 1;
1.1 root 7661: }
7662: CloseHandle(hFile);
7663: }
7664: }
7665: }
7666:
7667: inline void msdos_int_26h()
7668: {
7669: // this operation may cause serious damage for drives, so always returns error...
7670: UINT16 seg, ofs;
7671: DWORD dwSize;
7672:
1.1.1.3 root 7673: #if defined(HAS_I386)
7674: I386OP(pushf)();
7675: #else
7676: PREFIX86(_pushf());
7677: #endif
1.1 root 7678:
7679: if(!(REG8(AL) < 26)) {
7680: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 7681: m_CF = 1;
1.1 root 7682: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
7683: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 7684: m_CF = 1;
1.1 root 7685: } else {
7686: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
7687: char dev[64];
7688: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
7689:
7690: if(dpb->media_type == 0xf8) {
7691: // this drive is not a floppy
1.1.1.6 root 7692: // if(!(((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag & 0x40)) {
7693: // fatalerror("This application tried the absolute disk write to drive %c:\n", 'A' + REG8(AL));
7694: // }
1.1 root 7695: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 7696: m_CF = 1;
1.1 root 7697: } else {
7698: HANDLE hFile = CreateFile(dev, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
7699: if(hFile == INVALID_HANDLE_VALUE) {
7700: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 7701: m_CF = 1;
1.1 root 7702: } else {
1.1.1.19 root 7703: UINT32 top_sector = REG16(DX);
7704: UINT16 sector_num = REG16(CX);
7705: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX);
7706:
7707: if(sector_num == 0xffff) {
7708: top_sector = *(UINT32 *)(mem + buffer_addr + 0);
7709: sector_num = *(UINT16 *)(mem + buffer_addr + 4);
7710: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6);
7711: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8);
7712: buffer_addr = (seg << 4) + ofs;
7713: }
1.1 root 7714: if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
7715: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 7716: m_CF = 1;
1.1.1.19 root 7717: } else if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1.1 root 7718: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 7719: m_CF = 1;
1.1.1.19 root 7720: } else if(WriteFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 7721: REG8(AL) = 0x0a; // write error
1.1.1.3 root 7722: m_CF = 1;
1.1 root 7723: }
7724: CloseHandle(hFile);
7725: }
7726: }
7727: }
7728: }
7729:
7730: inline void msdos_int_27h()
7731: {
1.1.1.14 root 7732: msdos_mem_realloc(SREG(CS), (REG16(DX) + 15) >> 4, NULL);
1.1.1.3 root 7733: msdos_process_terminate(SREG(CS), retval | 0x300, 0);
1.1.1.14 root 7734:
7735: // int_21h_4bh succeeded
7736: m_CF = 0;
1.1 root 7737: }
7738:
7739: inline void msdos_int_29h()
7740: {
1.1.1.14 root 7741: #if 1
7742: // need to check escape sequences
1.1 root 7743: msdos_putch(REG8(AL));
1.1.1.14 root 7744: #else
7745: DWORD num;
7746: vram_flush();
1.1.1.23! root 7747: WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ®8(AL), 1, &num, NULL);
1.1.1.14 root 7748: cursor_moved = true;
7749: #endif
1.1 root 7750: }
7751:
7752: inline void msdos_int_2eh()
7753: {
7754: char tmp[MAX_PATH], command[MAX_PATH], opt[MAX_PATH];
7755: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 7756: strcpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(SI)));
1.1 root 7757: char *token = my_strtok(tmp, " ");
7758: strcpy(command, token);
7759: strcpy(opt, token + strlen(token) + 1);
7760:
7761: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
7762: param->env_seg = 0;
7763: param->cmd_line.w.l = 44;
7764: param->cmd_line.w.h = (WORK_TOP >> 4);
7765: param->fcb1.w.l = 24;
7766: param->fcb1.w.h = (WORK_TOP >> 4);
7767: param->fcb2.w.l = 24;
7768: param->fcb2.w.h = (WORK_TOP >> 4);
7769:
7770: memset(mem + WORK_TOP + 24, 0x20, 20);
7771:
7772: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
7773: cmd_line->len = strlen(opt);
7774: strcpy(cmd_line->cmd, opt);
7775: cmd_line->cmd[cmd_line->len] = 0x0d;
7776:
7777: msdos_process_exec(command, param, 0);
7778: REG8(AL) = 0;
7779: }
7780:
1.1.1.22 root 7781: inline void msdos_int_2fh_01h()
7782: {
7783: switch(REG8(AL)) {
7784: case 0x00:
7785: REG8(AL) = 0x01; // print.com is not installed, can't install
7786: break;
7787: default:
7788: 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));
7789: REG16(AX) = 0x01;
7790: m_CF = 1;
7791: break;
7792: }
7793: }
7794:
7795: inline void msdos_int_2fh_05h()
7796: {
7797: switch(REG8(AL)) {
7798: case 0x00:
7799: REG8(AL) = 0x01; // critical error handler is not installed, can't install
7800: break;
7801: default:
7802: 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));
7803: REG16(AX) = 0x01;
7804: m_CF = 1;
7805: break;
7806: }
7807: }
7808:
7809: inline void msdos_int_2fh_06h()
7810: {
7811: switch(REG8(AL)) {
7812: case 0x00:
7813: REG8(AL) = 0x01; // assign is not installed, can't install
7814: break;
7815: default:
7816: 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));
7817: REG16(AX) = 0x01;
7818: m_CF = 1;
7819: break;
7820: }
7821: }
7822:
7823: inline void msdos_int_2fh_08h()
7824: {
7825: switch(REG8(AL)) {
7826: case 0x00:
7827: REG8(AL) = 0x01; // driver.sys is not installed, can't install
7828: break;
7829: default:
7830: 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));
7831: REG16(AX) = 0x01;
7832: m_CF = 1;
7833: break;
7834: }
7835: }
7836:
7837: inline void msdos_int_2fh_10h()
7838: {
7839: switch(REG8(AL)) {
7840: case 0x00:
7841: REG8(AL) = 0x01; // share is not installed, can't install
7842: break;
7843: default:
7844: 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));
7845: REG16(AX) = 0x01;
7846: m_CF = 1;
7847: break;
7848: }
7849: }
7850:
7851: inline void msdos_int_2fh_11h()
7852: {
7853: switch(REG8(AL)) {
7854: case 0x00:
7855: REG8(AL) = 0x01; // mscdex is not installed, can't install
7856: break;
7857: default:
7858: 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));
7859: REG16(AX) = 0x01;
7860: m_CF = 1;
7861: break;
7862: }
7863: }
7864:
1.1.1.21 root 7865: inline void msdos_int_2fh_12h()
7866: {
7867: switch(REG8(AL)) {
1.1.1.22 root 7868: case 0x00:
7869: REG8(AL) = 0xff;
7870: break;
1.1.1.21 root 7871: case 0x16:
7872: if(REG16(BX) < 20) {
7873: SREG(ES) = SFT_TOP >> 4;
7874: i386_load_segment_descriptor(ES);
7875: REG16(DI) = 6 + 0x3b * REG16(BX);
7876:
7877: // update system file table
7878: UINT8* sft = mem + SFT_TOP + 6 + 0x3b * REG16(BX);
7879: if(file_handler[REG16(BX)].valid) {
7880: int count = 0;
7881: for(int i = 0; i < 20; i++) {
7882: if(msdos_psp_get_file_table(i, current_psp) == REG16(BX)) {
7883: count++;
7884: }
7885: }
7886: *(UINT16 *)(sft + 0x00) = count ? count : 0xffff;
7887: *(UINT32 *)(sft + 0x15) = _tell(REG16(BX));
7888: _lseek(REG16(BX), 0, SEEK_END);
7889: *(UINT32 *)(sft + 0x11) = _tell(REG16(BX));
7890: _lseek(REG16(BX), *(UINT32 *)(sft + 0x15), SEEK_SET);
7891: } else {
7892: memset(sft, 0, 0x3b);
7893: }
7894: } else {
7895: REG16(AX) = 0x06;
7896: m_CF = 1;
7897: }
7898: break;
7899: case 0x20:
7900: {
7901: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
7902:
7903: if(fd < 20) {
7904: SREG(ES) = current_psp;
7905: i386_load_segment_descriptor(ES);
7906: REG16(DI) = offsetof(psp_t, file_table) + fd;
7907: } else {
7908: REG16(AX) = 0x06;
7909: m_CF = 1;
7910: }
7911: }
7912: break;
1.1.1.22 root 7913: case 0x2e:
7914: if(REG8(DL) == 0x00 || REG8(DL) == 0x02 || REG8(DL) == 0x04 || REG8(DL) == 0x06) {
7915: SREG(ES) = ERR_TABLE_TOP >> 4;
7916: i386_load_segment_descriptor(ES);
7917: REG16(DI) = 0;
7918: }
7919: break;
7920: default:
7921: 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));
7922: REG16(AX) = 0x01;
7923: m_CF = 1;
7924: break;
7925: }
7926: }
7927:
7928: inline void msdos_int_2fh_14h()
7929: {
7930: switch(REG8(AL)) {
7931: case 0x00:
7932: REG8(AL) = 0x01; // nlsfunc.com is not installed, can't install
7933: break;
7934: default:
7935: 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));
7936: REG16(AX) = 0x01;
7937: m_CF = 1;
7938: break;
7939: }
7940: }
7941:
7942: inline void msdos_int_2fh_15h()
7943: {
7944: switch(REG8(AL)) {
7945: case 0x00:
7946: // function not supported, do not clear AX
7947: break;
7948: case 0x0b:
7949: // mscdex.exe is not installed
7950: break;
7951: case 0xff:
7952: // corelcdx is not installed
7953: break;
1.1.1.21 root 7954: default:
1.1.1.22 root 7955: 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 7956: REG16(AX) = 0x01;
7957: m_CF = 1;
7958: break;
7959: }
7960: }
7961:
1.1 root 7962: inline void msdos_int_2fh_16h()
7963: {
7964: switch(REG8(AL)) {
7965: case 0x00:
1.1.1.14 root 7966: if(no_windows) {
7967: REG8(AL) = 0;
7968: } else {
1.1 root 7969: OSVERSIONINFO osvi;
7970: ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
7971: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
7972: GetVersionEx(&osvi);
7973: REG8(AL) = osvi.dwMajorVersion;
7974: REG8(AH) = osvi.dwMinorVersion;
7975: }
7976: break;
1.1.1.22 root 7977: case 0x0a:
7978: if(!no_windows) {
7979: OSVERSIONINFO osvi;
7980: ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
7981: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
7982: GetVersionEx(&osvi);
7983: REG16(AX) = 0x0000;
7984: REG8(BH) = osvi.dwMajorVersion;
7985: REG8(BL) = osvi.dwMinorVersion;
7986: REG16(CX) = 0x0003; // enhanced
7987: }
7988: break;
7989: case 0x0e:
7990: case 0x0f:
7991: case 0x11:
7992: case 0x12:
7993: case 0x13:
7994: case 0x14:
7995: case 0x87:
7996: // function not supported, do not clear AX
7997: break;
1.1.1.14 root 7998: case 0x80:
7999: Sleep(10);
8000: hardware_update();
8001: REG8(AL) = 0;
8002: break;
1.1.1.22 root 8003: case 0x8e:
8004: REG16(AX) = 0x00; // failed
8005: break;
1.1.1.20 root 8006: case 0x8f:
8007: switch(REG8(DH)) {
8008: case 0x00:
8009: case 0x02:
8010: case 0x03:
8011: REG16(AX) = 0x00;
8012: break;
8013: case 0x01:
8014: REG16(AX) = 0x168f;
8015: break;
8016: }
8017: break;
1.1 root 8018: default:
1.1.1.22 root 8019: 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));
8020: REG16(AX) = 0x01;
8021: m_CF = 1;
8022: break;
8023: }
8024: }
8025:
8026: inline void msdos_int_2fh_19h()
8027: {
8028: switch(REG8(AL)) {
8029: case 0x00:
8030: // shellb.com is not installed
8031: REG8(AL) = 0x00;
8032: break;
8033: case 0x01:
8034: case 0x02:
8035: case 0x03:
8036: case 0x04:
8037: REG16(AX) = 0x01;
8038: m_CF = 1;
8039: break;
8040: default:
8041: 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 8042: REG16(AX) = 0x01;
1.1.1.3 root 8043: m_CF = 1;
1.1 root 8044: break;
8045: }
8046: }
8047:
8048: inline void msdos_int_2fh_1ah()
8049: {
8050: switch(REG8(AL)) {
8051: case 0x00:
8052: // ansi.sys is installed
8053: REG8(AL) = 0xff;
8054: break;
8055: default:
1.1.1.22 root 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_1bh()
8064: {
8065: switch(REG8(AL)) {
8066: case 0x00:
8067: // xma2ems.sys is not installed
8068: REG8(AL) = 0x00;
8069: break;
8070: default:
8071: 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 8072: REG16(AX) = 0x01;
1.1.1.3 root 8073: m_CF = 1;
1.1 root 8074: break;
8075: }
8076: }
8077:
8078: inline void msdos_int_2fh_43h()
8079: {
8080: switch(REG8(AL)) {
8081: case 0x00:
1.1.1.19 root 8082: // xms is installed ?
8083: #ifdef SUPPORT_XMS
8084: if(support_xms) {
8085: REG8(AL) = 0x80;
8086: } else
8087: #endif
8088: REG8(AL) = 0x00;
8089: break;
8090: case 0x10:
8091: REG16(BX) = XMS_OFFSET;
8092: SREG(ES) = XMS_TOP >> 4;
8093: i386_load_segment_descriptor(ES);
1.1 root 8094: break;
8095: default:
1.1.1.22 root 8096: 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));
8097: REG16(AX) = 0x01;
8098: m_CF = 1;
8099: break;
8100: }
8101: }
8102:
8103: inline void msdos_int_2fh_46h()
8104: {
8105: switch(REG8(AL)) {
8106: case 0x80:
8107: // windows v3.0 is not installed
8108: break;
8109: default:
8110: 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));
8111: REG16(AX) = 0x01;
8112: m_CF = 1;
8113: break;
8114: }
8115: }
8116:
8117: inline void msdos_int_2fh_48h()
8118: {
8119: switch(REG8(AL)) {
8120: case 0x00:
8121: // doskey is not installed
8122: break;
8123: case 0x10:
8124: msdos_int_21h_0ah();
8125: REG16(AX) = 0x00;
8126: break;
8127: default:
8128: 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 8129: REG16(AX) = 0x01;
1.1.1.3 root 8130: m_CF = 1;
1.1 root 8131: break;
8132: }
8133: }
8134:
8135: inline void msdos_int_2fh_4ah()
8136: {
1.1.1.19 root 8137: // hma is not installed
1.1 root 8138: switch(REG8(AL)) {
8139: case 0x01:
8140: case 0x02:
1.1.1.19 root 8141: // hma is not used
1.1 root 8142: REG16(BX) = 0;
1.1.1.3 root 8143: SREG(ES) = 0xffff;
8144: i386_load_segment_descriptor(ES);
1.1 root 8145: REG16(DI) = 0xffff;
8146: break;
1.1.1.19 root 8147: case 0x03:
8148: // unable to allocate
8149: REG16(DI) = 0xffff;
8150: break;
8151: case 0x04:
8152: // function not supported, do not clear AX
8153: break;
1.1.1.22 root 8154: case 0x10: // smartdrv installation check
8155: case 0x11: // dblspace installation check
8156: break;
8157: default:
8158: 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));
8159: REG16(AX) = 0x01;
8160: m_CF = 1;
8161: break;
8162: }
8163: }
8164:
8165: inline void msdos_int_2fh_4bh()
8166: {
8167: switch(REG8(AL)) {
8168: case 0x02:
8169: // task switcher not loaded, do not clear AX
8170: break;
1.1 root 8171: default:
1.1.1.22 root 8172: 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 8173: REG16(AX) = 0x01;
1.1.1.3 root 8174: m_CF = 1;
1.1 root 8175: break;
8176: }
8177: }
8178:
8179: inline void msdos_int_2fh_4fh()
8180: {
8181: switch(REG8(AL)) {
8182: case 0x00:
8183: REG16(AX) = 0;
8184: REG8(DL) = 1; // major version
8185: REG8(DH) = 0; // minor version
8186: break;
8187: case 0x01:
8188: REG16(AX) = 0;
8189: REG16(BX) = active_code_page;
8190: break;
8191: default:
1.1.1.22 root 8192: 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));
8193: REG16(AX) = 0x01;
8194: m_CF = 1;
8195: break;
8196: }
8197: }
8198:
8199: inline void msdos_int_2fh_55h()
8200: {
8201: switch(REG8(AL)) {
8202: case 0x00:
8203: case 0x01:
8204: // 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));
8205: break;
8206: default:
8207: 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 8208: REG16(AX) = 0x01;
1.1.1.3 root 8209: m_CF = 1;
1.1 root 8210: break;
8211: }
8212: }
8213:
8214: inline void msdos_int_2fh_aeh()
8215: {
8216: switch(REG8(AL)) {
8217: case 0x00:
8218: REG8(AL) = 0;
8219: break;
8220: case 0x01:
8221: {
8222: char command[MAX_PATH];
8223: memset(command, 0, sizeof(command));
1.1.1.3 root 8224: memcpy(command, mem + SREG_BASE(DS) + REG16(SI) + 1, mem[SREG_BASE(DS) + REG16(SI)]);
1.1 root 8225:
8226: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
8227: param->env_seg = 0;
8228: param->cmd_line.w.l = 44;
8229: param->cmd_line.w.h = (WORK_TOP >> 4);
8230: param->fcb1.w.l = 24;
8231: param->fcb1.w.h = (WORK_TOP >> 4);
8232: param->fcb2.w.l = 24;
8233: param->fcb2.w.h = (WORK_TOP >> 4);
8234:
8235: memset(mem + WORK_TOP + 24, 0x20, 20);
8236:
8237: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
1.1.1.3 root 8238: cmd_line->len = mem[SREG_BASE(DS) + REG16(BX) + 1];
8239: memcpy(cmd_line->cmd, mem + SREG_BASE(DS) + REG16(BX) + 2, cmd_line->len);
1.1 root 8240: cmd_line->cmd[cmd_line->len] = 0x0d;
8241:
8242: if(msdos_process_exec(command, param, 0)) {
8243: REG16(AX) = 0x02;
1.1.1.3 root 8244: m_CF = 1;
1.1 root 8245: }
8246: }
8247: break;
8248: default:
1.1.1.22 root 8249: 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 8250: REG16(AX) = 0x01;
1.1.1.3 root 8251: m_CF = 1;
1.1 root 8252: break;
8253: }
8254: }
8255:
8256: inline void msdos_int_2fh_b7h()
8257: {
8258: switch(REG8(AL)) {
8259: case 0x00:
8260: // append is not installed
8261: REG8(AL) = 0;
8262: break;
1.1.1.22 root 8263: case 0x07:
8264: case 0x11:
8265: break;
1.1 root 8266: default:
1.1.1.22 root 8267: 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 8268: REG16(AX) = 0x01;
1.1.1.3 root 8269: m_CF = 1;
1.1 root 8270: break;
8271: }
8272: }
8273:
1.1.1.19 root 8274: inline void msdos_int_67h_40h()
8275: {
8276: if(!support_ems) {
8277: REG8(AH) = 0x84;
8278: } else {
8279: REG8(AH) = 0x00;
8280: }
8281: }
8282:
8283: inline void msdos_int_67h_41h()
8284: {
8285: if(!support_ems) {
8286: REG8(AH) = 0x84;
8287: } else {
8288: REG8(AH) = 0x00;
8289: REG16(BX) = EMS_TOP >> 4;
8290: }
8291: }
8292:
8293: inline void msdos_int_67h_42h()
8294: {
8295: if(!support_ems) {
8296: REG8(AH) = 0x84;
8297: } else {
8298: REG8(AH) = 0x00;
8299: REG16(BX) = free_ems_pages;
8300: REG16(DX) = MAX_EMS_PAGES;
8301: }
8302: }
8303:
8304: inline void msdos_int_67h_43h()
8305: {
8306: if(!support_ems) {
8307: REG8(AH) = 0x84;
8308: } else if(REG16(BX) > MAX_EMS_PAGES) {
8309: REG8(AH) = 0x87;
8310: } else if(REG16(BX) > free_ems_pages) {
8311: REG8(AH) = 0x88;
8312: } else if(REG16(BX) == 0) {
8313: REG8(AH) = 0x89;
8314: } else {
8315: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
8316: if(!ems_handles[i].allocated) {
8317: ems_allocate_pages(i, REG16(BX));
8318: REG8(AH) = 0x00;
8319: REG16(DX) = i;
8320: return;
8321: }
8322: }
8323: REG8(AH) = 0x85;
8324: }
8325: }
8326:
8327: inline void msdos_int_67h_44h()
8328: {
8329: if(!support_ems) {
8330: REG8(AH) = 0x84;
8331: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
8332: REG8(AH) = 0x83;
8333: } else if(!(REG16(BX) == 0xffff || REG16(BX) < ems_handles[REG16(DX)].pages)) {
8334: REG8(AH) = 0x8a;
8335: // } else if(!(REG8(AL) < 4)) {
8336: // REG8(AH) = 0x8b;
8337: } else if(REG16(BX) == 0xffff) {
8338: ems_unmap_page(REG8(AL) & 3);
8339: REG8(AH) = 0x00;
8340: } else {
8341: ems_map_page(REG8(AL) & 3, REG16(DX), REG16(BX));
8342: REG8(AH) = 0x00;
8343: }
8344: }
8345:
8346: inline void msdos_int_67h_45h()
8347: {
8348: if(!support_ems) {
8349: REG8(AH) = 0x84;
8350: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
8351: REG8(AH) = 0x83;
8352: } else {
8353: ems_release_pages(REG16(DX));
8354: REG8(AH) = 0x00;
8355: }
8356: }
8357:
8358: inline void msdos_int_67h_46h()
8359: {
8360: if(!support_ems) {
8361: REG8(AH) = 0x84;
8362: } else {
8363: REG16(AX) = 0x0032; // EMS 3.2
8364: // REG16(AX) = 0x0040; // EMS 4.0
8365: }
8366: }
8367:
8368: inline void msdos_int_67h_47h()
8369: {
8370: // NOTE: the map data should be stored in the specified ems page, not process data
8371: process_t *process = msdos_process_info_get(current_psp);
8372:
8373: if(!support_ems) {
8374: REG8(AH) = 0x84;
8375: // } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
8376: // REG8(AH) = 0x83;
8377: } else if(process->ems_pages_stored) {
8378: REG8(AH) = 0x8d;
8379: } else {
8380: for(int i = 0; i < 4; i++) {
8381: process->ems_pages[i].handle = ems_pages[i].handle;
8382: process->ems_pages[i].page = ems_pages[i].page;
8383: process->ems_pages[i].mapped = ems_pages[i].mapped;
8384: }
8385: process->ems_pages_stored = true;
8386: REG8(AH) = 0x00;
8387: }
8388: }
8389:
8390: inline void msdos_int_67h_48h()
8391: {
8392: // NOTE: the map data should be restored from the specified ems page, not process data
8393: process_t *process = msdos_process_info_get(current_psp);
8394:
8395: if(!support_ems) {
8396: REG8(AH) = 0x84;
8397: // } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
8398: // REG8(AH) = 0x83;
8399: } else if(!process->ems_pages_stored) {
8400: REG8(AH) = 0x8e;
8401: } else {
8402: for(int i = 0; i < 4; i++) {
8403: if(process->ems_pages[i].mapped) {
8404: ems_map_page(i, process->ems_pages[i].handle, process->ems_pages[i].page);
8405: } else {
8406: ems_unmap_page(i);
8407: }
8408: }
8409: process->ems_pages_stored = false;
8410: REG8(AH) = 0x00;
8411: }
8412: }
8413:
8414: inline void msdos_int_67h_4bh()
8415: {
8416: if(!support_ems) {
8417: REG8(AH) = 0x84;
8418: } else {
8419: REG8(AH) = 0x00;
8420: REG16(BX) = 0;
8421: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
8422: if(ems_handles[i].allocated) {
8423: REG16(BX)++;
8424: }
8425: }
8426: }
8427: }
8428:
8429: inline void msdos_int_67h_4ch()
8430: {
8431: if(!support_ems) {
8432: REG8(AH) = 0x84;
8433: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
8434: REG8(AH) = 0x83;
8435: } else {
8436: REG8(AH) = 0x00;
8437: REG16(BX) = ems_handles[REG16(DX)].pages;
8438: }
8439: }
8440:
8441: inline void msdos_int_67h_4dh()
8442: {
8443: if(!support_ems) {
8444: REG8(AH) = 0x84;
8445: } else {
8446: REG8(AH) = 0x00;
8447: REG16(BX) = 0;
8448: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
8449: if(ems_handles[i].allocated) {
8450: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 0) = i;
8451: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 2) = ems_handles[i].pages;
8452: REG16(BX)++;
8453: }
8454: }
8455: }
8456: }
8457:
1.1.1.20 root 8458: inline void msdos_int_67h_4eh()
8459: {
8460: if(!support_ems) {
8461: REG8(AH) = 0x84;
8462: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01 || REG8(AL) == 0x02) {
8463: if(REG8(AL) == 0x00 || REG8(AL) == 0x02) {
8464: // save page map
8465: for(int i = 0; i < 4; i++) {
8466: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = ems_pages[i].mapped ? ems_pages[i].handle : 0xffff;
8467: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = ems_pages[i].mapped ? ems_pages[i].page : 0xffff;
8468: }
8469: }
8470: if(REG8(AL) == 0x01 || REG8(AL) == 0x02) {
8471: // restore page map
8472: for(int i = 0; i < 4; i++) {
8473: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0);
8474: UINT16 page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2);
8475:
8476: if(handle < MAX_EMS_HANDLES && ems_handles[handle].allocated && page < ems_handles[handle].pages) {
8477: ems_map_page(i, handle, page);
8478: } else {
8479: ems_unmap_page(i);
8480: }
8481: }
8482: }
8483: REG8(AH) = 0x00;
8484: } else if(REG8(AL) == 0x03) {
8485: REG8(AH) = 0x00;
1.1.1.21 root 8486: REG8(AL) = 4 * 4;
8487: } else {
1.1.1.22 root 8488: 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 8489: REG8(AH) = 0x8f;
8490: }
8491: }
8492:
8493: inline void msdos_int_67h_4fh()
8494: {
8495: if(!support_ems) {
8496: REG8(AH) = 0x84;
8497: } else if(REG8(AL) == 0x00) {
8498: int count = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI));
8499:
8500: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI)) = count;
8501: for(int i = 0; i < count; i++) {
8502: UINT16 segment = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 2 * i);
8503: UINT16 physical = ((segment << 4) - EMS_TOP) / 0x4000;
8504:
8505: // if(!(physical < 4)) {
8506: // REG8(AH) = 0x8b;
8507: // return;
8508: // }
8509: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 0) = segment;
8510: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 2) = ems_pages[physical & 3].handle;
8511: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 4) = ems_pages[physical & 3].mapped ? ems_pages[physical & 3].page : 0xffff;
8512: }
8513: REG8(AH) = 0x00;
8514: } else if(REG8(AL) == 0x01) {
8515: int count = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI));
8516:
8517: for(int i = 0; i < count; i++) {
8518: UINT16 segment = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 0);
8519: UINT16 physical = ((segment << 4) - EMS_TOP) / 0x4000;
8520: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 2);
8521: UINT16 logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 4);
8522:
8523: // if(!(physical < 4)) {
8524: // REG8(AH) = 0x8b;
8525: // return;
8526: // } else
8527: if(!(handle < MAX_EMS_HANDLES && ems_handles[handle].allocated)) {
8528: REG8(AH) = 0x83;
8529: return;
8530: } else if(logical == 0xffff) {
8531: ems_unmap_page(physical & 3);
8532: } else if(logical < ems_handles[handle].pages) {
8533: ems_map_page(physical & 3, handle, logical);
8534: } else {
8535: REG8(AH) = 0x8a;
8536: return;
8537: }
8538: }
8539: REG8(AH) = 0x00;
8540: } else if(REG8(AL) == 0x02) {
8541: REG8(AH) = 0x00;
8542: REG8(AL) = 2 + REG16(BX) * 6;
1.1.1.20 root 8543: } else {
1.1.1.22 root 8544: 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 8545: REG8(AH) = 0x8f;
8546: }
8547: }
8548:
8549: inline void msdos_int_67h_50h()
8550: {
8551: if(!support_ems) {
8552: REG8(AH) = 0x84;
8553: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
8554: REG8(AH) = 0x83;
8555: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
8556: for(int i = 0; i < REG16(CX); i++) {
8557: int logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0);
8558: int physical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2);
8559:
8560: if(REG8(AL) == 0x01) {
8561: physical = ((physical << 4) - EMS_TOP) / 0x4000;
8562: }
8563: // if(!(physical < 4)) {
8564: // REG8(AH) = 0x8b;
8565: // return;
8566: // } else
8567: if(logical == 0xffff) {
8568: ems_unmap_page(physical & 3);
8569: } else if(logical < ems_handles[REG16(DX)].pages) {
8570: ems_map_page(physical & 3, REG16(DX), logical);
8571: } else {
8572: REG8(AH) = 0x8a;
8573: return;
8574: }
8575: }
8576: REG8(AH) = 0x00;
8577: } else {
1.1.1.22 root 8578: 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 8579: REG8(AH) = 0x8f;
8580: }
8581: }
8582:
1.1.1.19 root 8583: inline void msdos_int_67h_51h()
8584: {
8585: if(!support_ems) {
8586: REG8(AH) = 0x84;
8587: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
8588: REG8(AH) = 0x83;
8589: } else if(REG16(BX) > MAX_EMS_PAGES) {
8590: REG8(AH) = 0x87;
8591: } else if(REG16(BX) > free_ems_pages + ems_handles[REG16(DX)].pages) {
8592: REG8(AH) = 0x88;
8593: } else {
8594: ems_reallocate_pages(REG16(DX), REG16(BX));
8595: REG8(AH) = 0x00;
8596: }
8597: }
8598:
1.1.1.20 root 8599: inline void msdos_int_67h_52h()
8600: {
8601: if(!support_ems) {
8602: REG8(AH) = 0x84;
8603: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
8604: REG8(AH) = 0x83;
8605: } else if(REG8(AL) == 0x00) {
8606: REG8(AL) = 0x00; // handle is volatile
8607: REG8(AH) = 0x00;
8608: } else if(REG8(AL) == 0x01) {
8609: if(REG8(BL) == 0x00) {
8610: REG8(AH) = 0x00;
8611: } else {
8612: REG8(AH) = 0x90; // undefined attribute type
8613: }
8614: } else if(REG8(AL) == 0x02) {
8615: REG8(AL) = 0x00; // only volatile handles supported
8616: REG8(AH) = 0x00;
8617: } else {
1.1.1.22 root 8618: 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 8619: REG8(AH) = 0x8f;
8620: }
8621: }
8622:
1.1.1.19 root 8623: inline void msdos_int_67h_53h()
8624: {
8625: if(!support_ems) {
8626: REG8(AH) = 0x84;
8627: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
8628: REG8(AH) = 0x83;
8629: } else if(REG8(AL) == 0x00) {
8630: memcpy(mem + SREG_BASE(ES) + REG16(DI), ems_handles[REG16(DX)].name, 8);
8631: REG8(AH) = 0x00;
8632: } else if(REG8(AL) == 0x01) {
8633: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
8634: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) {
8635: REG8(AH) = 0xa1;
8636: return;
8637: }
8638: }
8639: REG8(AH) = 0x00;
8640: memcpy(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8);
8641: } else {
1.1.1.22 root 8642: 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 8643: REG8(AH) = 0x8f;
1.1.1.19 root 8644: }
8645: }
8646:
8647: inline void msdos_int_67h_54h()
8648: {
8649: if(!support_ems) {
8650: REG8(AH) = 0x84;
8651: } else if(REG8(AL) == 0x00) {
8652: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
8653: if(ems_handles[i].allocated) {
8654: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, ems_handles[i].name, 10);
8655: } else {
8656: memset(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, 0, 10);
8657: }
8658: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 0) = i;
8659: }
8660: REG8(AH) = 0x00;
8661: REG8(AL) = MAX_EMS_HANDLES;
8662: } else if(REG8(AL) == 0x01) {
8663: REG8(AH) = 0xa0; // not found
8664: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
8665: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) {
8666: REG8(AH) = 0x00;
8667: REG16(DX) = i;
8668: break;
8669: }
8670: }
8671: } else if(REG8(AL) == 0x02) {
8672: REG8(AH) = 0x00;
8673: REG16(BX) = MAX_EMS_HANDLES;
8674: } else {
1.1.1.22 root 8675: 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 8676: REG8(AH) = 0x8f;
8677: }
8678: }
8679:
8680: inline void msdos_int_67h_57h_tmp()
8681: {
8682: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00);
8683: UINT8 src_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04);
8684: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x05);
8685: UINT16 src_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07);
8686: UINT16 src_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x09);
8687: UINT8 dest_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0b);
8688: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c);
8689: UINT16 dest_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0e);
8690: UINT16 dest_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x10);
8691:
8692: UINT8 *src_buffer, *dest_buffer;
8693: UINT32 src_addr, dest_addr;
8694: UINT32 src_addr_max, dest_addr_max;
8695:
8696: if(src_type == 0) {
8697: src_buffer = mem;
8698: src_addr = (src_seg << 4) + src_ofs;
8699: src_addr_max = MAX_MEM;
8700: } else {
8701: if(!(src_handle < MAX_EMS_HANDLES && ems_handles[src_handle].allocated)) {
8702: REG8(AH) = 0x83;
8703: return;
8704: } else if(!(src_seg < ems_handles[src_handle].pages)) {
8705: REG8(AH) = 0x8a;
8706: return;
8707: }
8708: src_buffer = ems_handles[src_handle].buffer + 0x4000 * src_seg;
8709: src_addr = src_ofs;
8710: src_addr_max = 0x4000;
8711: }
8712: if(dest_type == 0) {
8713: dest_buffer = mem;
8714: dest_addr = (dest_seg << 4) + dest_ofs;
8715: dest_addr_max = MAX_MEM;
8716: } else {
8717: if(!(dest_handle < MAX_EMS_HANDLES && ems_handles[dest_handle].allocated)) {
8718: REG8(AH) = 0x83;
8719: return;
8720: } else if(!(dest_seg < ems_handles[dest_handle].pages)) {
8721: REG8(AH) = 0x8a;
8722: return;
8723: }
8724: dest_buffer = ems_handles[dest_handle].buffer + 0x4000 * dest_seg;
8725: dest_addr = dest_ofs;
8726: dest_addr_max = 0x4000;
8727: }
8728: for(int i = 0; i < copy_length; i++) {
8729: if(src_addr < src_addr_max && dest_addr < dest_addr_max) {
8730: if(REG8(AL) == 0x00) {
8731: dest_buffer[dest_addr++] = src_buffer[src_addr++];
8732: } else if(REG8(AL) == 0x01) {
8733: UINT8 tmp = dest_buffer[dest_addr];
8734: dest_buffer[dest_addr++] = src_buffer[src_addr];
8735: src_buffer[src_addr++] = tmp;
8736: }
8737: } else {
8738: REG8(AH) = 0x93;
8739: return;
8740: }
8741: }
8742: REG8(AH) = 0x80;
8743: }
8744:
8745: inline void msdos_int_67h_57h()
8746: {
8747: if(!support_ems) {
8748: REG8(AH) = 0x84;
8749: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
8750: struct {
8751: UINT16 handle;
8752: UINT16 page;
8753: bool mapped;
8754: } tmp_pages[4];
8755:
8756: // unmap pages to copy memory data to ems buffer
8757: for(int i = 0; i < 4; i++) {
8758: tmp_pages[i].handle = ems_pages[i].handle;
8759: tmp_pages[i].page = ems_pages[i].page;
8760: tmp_pages[i].mapped = ems_pages[i].mapped;
8761: ems_unmap_page(i);
8762: }
8763:
8764: // run move/exchange operation
8765: msdos_int_67h_57h_tmp();
8766:
8767: // restore unmapped pages
8768: for(int i = 0; i < 4; i++) {
8769: if(tmp_pages[i].mapped) {
8770: ems_map_page(i, tmp_pages[i].handle, tmp_pages[i].page);
8771: }
8772: }
8773: } else {
1.1.1.22 root 8774: 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 8775: REG8(AH) = 0x8f;
8776: }
8777: }
8778:
8779: inline void msdos_int_67h_58h()
8780: {
8781: if(!support_ems) {
8782: REG8(AH) = 0x84;
8783: } else if(REG8(AL) == 0x00) {
8784: for(int i = 0; i < 4; i++) {
8785: *(UINT16 *)(mem +SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = (EMS_TOP + 0x4000 * i) >> 4;
8786: *(UINT16 *)(mem +SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = i;
8787: }
8788: REG8(AH) = 0x00;
8789: REG16(CX) = 4;
8790: } else if(REG8(AL) == 0x01) {
8791: REG8(AH) = 0x00;
8792: REG16(CX) = 4;
8793: } else {
1.1.1.22 root 8794: 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 8795: REG8(AH) = 0x8f;
8796: }
8797: }
8798:
8799: inline void msdos_int_67h_5ah()
8800: {
8801: if(!support_ems) {
1.1.1.19 root 8802: REG8(AH) = 0x84;
1.1.1.20 root 8803: } else if(REG16(BX) > MAX_EMS_PAGES) {
8804: REG8(AH) = 0x87;
8805: } else if(REG16(BX) > free_ems_pages) {
8806: REG8(AH) = 0x88;
8807: // } else if(REG16(BX) == 0) {
8808: // REG8(AH) = 0x89;
8809: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
8810: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
8811: if(!ems_handles[i].allocated) {
8812: ems_allocate_pages(i, REG16(BX));
8813: REG8(AH) = 0x00;
8814: REG16(DX) = i;
8815: return;
8816: }
8817: }
8818: REG8(AH) = 0x85;
8819: } else {
1.1.1.22 root 8820: 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 8821: REG8(AH) = 0x8f;
1.1.1.19 root 8822: }
8823: }
8824:
8825: #ifdef SUPPORT_XMS
8826:
8827: inline void msdos_call_xms_00h()
8828: {
8829: REG16(AX) = 0x0270; // V2.70
8830: REG16(BX) = 0x0000;
8831: // REG16(DX) = 0x0000; // hma does not exist
8832: REG16(DX) = 0x0001; // hma does exist
8833: }
8834:
8835: inline void msdos_call_xms_01h()
8836: {
8837: REG16(AX) = 0x0000;
8838: // REG8(BL) = 0x90; // hma does not exist
8839: REG8(BL) = 0x91; // hma is already used
8840: }
8841:
8842: inline void msdos_call_xms_02h()
8843: {
8844: REG16(AX) = 0x0000;
8845: // REG8(BL) = 0x90; // hma does not exist
8846: REG8(BL) = 0x91; // hma is already used
8847: }
8848:
8849: inline void msdos_call_xms_03h()
8850: {
8851: i386_set_a20_line(1);
8852: REG16(AX) = 0x0001;
8853: REG8(BL) = 0x00;
8854: }
8855:
8856: inline void msdos_call_xms_04h()
8857: {
1.1.1.21 root 8858: i386_set_a20_line(0);
8859: REG16(AX) = 0x0001;
8860: REG8(BL) = 0x00;
1.1.1.19 root 8861: }
8862:
8863: inline void msdos_call_xms_05h()
8864: {
8865: i386_set_a20_line(1);
8866: REG16(AX) = 0x0001;
8867: REG8(BL) = 0x00;
1.1.1.21 root 8868: xms_a20_local_enb_count++;
1.1.1.19 root 8869: }
8870:
8871: void msdos_call_xms_06h()
8872: {
1.1.1.21 root 8873: if(xms_a20_local_enb_count > 0) {
8874: xms_a20_local_enb_count--;
8875: }
8876: if(xms_a20_local_enb_count == 0) {
1.1.1.19 root 8877: i386_set_a20_line(0);
1.1.1.21 root 8878: }
8879: if((m_a20_mask >> 20) & 1) {
1.1.1.19 root 8880: REG16(AX) = 0x0000;
8881: REG8(BL) = 0x94;
1.1.1.21 root 8882: } else {
8883: REG16(AX) = 0x0001;
8884: REG8(BL) = 0x00;
1.1.1.19 root 8885: }
8886: }
8887:
8888: inline void msdos_call_xms_07h()
8889: {
8890: REG16(AX) = (m_a20_mask >> 20) & 1;
8891: REG8(BL) = 0x00;
8892: }
8893:
8894: inline void msdos_call_xms_08h()
8895: {
8896: REG16(AX) = REG16(DX) = 0x0000;
8897:
8898: int mcb_seg = EMB_TOP >> 4;
8899:
8900: while(1) {
8901: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
8902:
8903: if(mcb->psp == 0) {
8904: if(REG16(AX) < mcb->size_kb()) {
8905: REG16(AX) = mcb->size_kb();
8906: }
8907: REG16(DX) += mcb->size_kb();
8908: }
8909: if(mcb->mz == 'Z') {
8910: break;
8911: }
8912: mcb_seg += 1 + mcb->paragraphs();
8913: }
8914:
8915: if(REG16(AX) == 0 && REG16(DX) == 0) {
8916: REG8(BL) = 0xa0;
8917: } else {
8918: REG8(BL) = 0x00;
8919: }
8920: }
8921:
8922: inline void msdos_call_xms_09h()
8923: {
8924: for(int i = 1; i <= MAX_XMS_HANDLES; i++) {
8925: if(!xms_handles[i].allocated) {
8926: if((xms_handles[i].seg = msdos_mem_alloc(EMB_TOP >> 4, REG16(DX) * 64, 0)) != -1) {
8927: xms_handles[i].size_kb = REG16(DX);
8928: xms_handles[i].lock = 0;
8929: xms_handles[i].allocated = true;
8930:
8931: REG16(AX) = 0x0001;
8932: REG16(DX) = i;
8933: REG8(BL) = 0x00;
8934: } else {
8935: REG16(AX) = REG16(DX) = 0x0000;
8936: REG8(BL) = 0xa0;
8937: }
8938: return;
8939: }
8940: }
8941: REG16(AX) = REG16(DX) = 0x0000;
8942: REG8(BL) = 0xa1;
8943: }
8944:
8945: inline void msdos_call_xms_0ah()
8946: {
8947: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
8948: REG16(AX) = 0x0000;
8949: REG8(BL) = 0xa2;
8950: } else if(xms_handles[REG16(DX)].lock > 0) {
8951: REG16(AX) = 0x0000;
8952: REG8(BL) = 0xab;
8953: } else {
8954: msdos_mem_free(xms_handles[REG16(DX)].seg);
8955: xms_handles[REG16(DX)].allocated = false;
8956:
8957: REG16(AX) = 0x0001;
8958: REG8(BL) = 0x00;
8959: }
8960: }
8961:
8962: inline void msdos_call_xms_0bh()
8963: {
8964: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00);
8965: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04);
8966: UINT32 src_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06);
8967: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0a);
8968: UINT32 dest_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c);
8969:
8970: UINT8 *src_buffer, *dest_buffer;
8971: UINT32 src_addr_max, dest_addr_max;
8972:
8973: if(src_handle == 0) {
8974: src_buffer = mem;
8975: src_addr = (((src_addr >> 16) & 0xffff) << 4) + (src_addr & 0xffff);
8976: src_addr_max = MAX_MEM;
8977: } else {
8978: if(!(src_handle >= 1 && src_handle <= MAX_XMS_HANDLES && xms_handles[src_handle].allocated)) {
8979: REG16(AX) = 0x0000;
8980: REG8(BL) = 0xa3;
8981: return;
8982: }
8983: src_buffer = mem + (xms_handles[src_handle].seg << 4);
8984: src_addr_max = xms_handles[src_handle].size_kb * 1024;
8985: }
8986: if(dest_handle == 0) {
8987: dest_buffer = mem;
8988: dest_addr = (((dest_addr >> 16) & 0xffff) << 4) + (dest_addr & 0xffff);
8989: dest_addr_max = MAX_MEM;
8990: } else {
8991: if(!(dest_handle >= 1 && dest_handle <= MAX_XMS_HANDLES && xms_handles[dest_handle].allocated)) {
8992: REG16(AX) = 0x0000;
8993: REG8(BL) = 0xa5;
8994: return;
8995: }
8996: dest_buffer = mem + (xms_handles[dest_handle].seg << 4);
8997: dest_addr_max = xms_handles[dest_handle].size_kb * 1024;
8998: }
8999: for(int i = 0; i < copy_length; i++) {
9000: if(src_addr < src_addr_max && dest_addr < dest_addr_max) {
9001: dest_buffer[dest_addr++] = src_buffer[src_addr++];
9002: } else {
9003: break;
9004: }
9005: }
9006: REG16(AX) = 0x0001;
9007: REG8(BL) = 0x00;
9008: }
9009:
9010: inline void msdos_call_xms_0ch()
9011: {
9012: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
9013: REG16(AX) = 0x0000;
9014: REG8(BL) = 0xa2;
9015: } else {
9016: xms_handles[REG16(DX)].lock++;
9017: REG16(AX) = 0x0001;
9018: REG8(BL) = 0x00;
9019: UINT32 addr = xms_handles[REG16(DX)].seg << 4;
9020: REG16(DX) = (addr >> 16) & 0xffff;
9021: REG16(BX) = (addr ) & 0xffff;
9022: }
9023: }
9024:
9025: inline void msdos_call_xms_0dh()
9026: {
9027: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
9028: REG16(AX) = 0x0000;
9029: REG8(BL) = 0xa2;
9030: } else if(!(xms_handles[REG16(DX)].lock > 0)) {
9031: REG16(AX) = 0x0000;
9032: REG8(BL) = 0xaa;
9033: } else {
9034: xms_handles[REG16(DX)].lock--;
9035: REG16(AX) = 0x0001;
9036: REG8(BL) = 0x00;
9037: }
9038: }
9039:
9040: inline void msdos_call_xms_0eh()
9041: {
9042: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
9043: REG16(AX) = 0x0000;
9044: REG8(BL) = 0xa2;
9045: } else {
9046: REG16(AX) = 0x0001;
9047: REG8(BH) = xms_handles[REG16(DX)].lock;
9048: REG8(BL) = 0x00;
9049: for(int i = 1; i <= MAX_XMS_HANDLES; i++) {
9050: if(!xms_handles[i].allocated) {
9051: REG8(BL)++;
9052: }
9053: }
9054: REG16(DX) = xms_handles[REG16(DX)].size_kb;
9055: }
9056: }
9057:
9058: inline void msdos_call_xms_0fh()
9059: {
9060: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
9061: REG16(AX) = 0x0000;
9062: REG8(BL) = 0xa2;
9063: } else if(xms_handles[REG16(DX)].lock > 0) {
9064: REG16(AX) = 0x0000;
9065: REG8(BL) = 0xab;
9066: } else if(msdos_mem_realloc(xms_handles[REG16(DX)].seg, REG16(BX) * 64, NULL)) {
9067: REG16(AX) = 0x0000;
9068: REG8(BL) = 0xa0;
9069: } else {
9070: REG16(AX) = 0x0001;
9071: REG8(BL) = 0x00;
9072: }
9073: }
9074:
9075: inline void msdos_call_xms_10h()
9076: {
9077: int seg;
9078:
9079: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(DX), 0)) != -1) {
9080: REG16(AX) = 0x0001;
9081: REG16(BX) = seg;
9082: } else {
9083: REG16(AX) = 0x0000;
9084: REG8(BL) = 0xb0;
9085: REG16(DX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
9086: }
9087: }
9088:
9089: inline void msdos_call_xms_11h()
9090: {
9091: int mcb_seg = REG16(DX) - 1;
9092: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
9093:
9094: if(mcb->mz == 'M' || mcb->mz == 'Z') {
9095: msdos_mem_free(REG16(DX));
9096: REG16(AX) = 0x0001;
9097: REG8(BL) = 0x00;
9098: } else {
9099: REG16(AX) = 0x0000;
9100: REG8(BL) = 0xb2;
9101: }
9102: }
9103:
9104: inline void msdos_call_xms_12h()
9105: {
9106: int mcb_seg = REG16(DX) - 1;
9107: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
9108: int max_paragraphs;
9109:
9110: if(mcb->mz == 'M' || mcb->mz == 'Z') {
9111: if(!msdos_mem_realloc(REG16(DX), REG16(BX), &max_paragraphs)) {
9112: REG16(AX) = 0x0001;
9113: REG8(BL) = 0x00;
9114: } else {
9115: REG16(AX) = 0x0000;
9116: REG8(BL) = 0xb0;
9117: REG16(DX) = max_paragraphs;
9118: }
9119: } else {
9120: REG16(AX) = 0x0000;
9121: REG8(BL) = 0xb2;
9122: }
9123: }
9124:
9125: #endif
9126:
1.1 root 9127: void msdos_syscall(unsigned num)
9128: {
1.1.1.22 root 9129: #ifdef ENABLE_DEBUG_SYSCALL
9130: if(num == 0x68) {
9131: // dummy interrupt for EMS (int 67h)
9132: 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));
9133: } else if(num == 0x69) {
9134: // dummy interrupt for XMS (call far)
9135: 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));
9136: } else if(num == 0x6a) {
9137: // dummy interrupt for case map routine pointed in the country info
9138: } else {
9139: 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));
9140: }
9141: #endif
9142:
1.1 root 9143: switch(num) {
9144: case 0x00:
9145: error("division by zero\n");
9146: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
9147: break;
9148: case 0x04:
9149: error("overflow\n");
9150: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
9151: break;
9152: case 0x06:
9153: // NOTE: ish.com has illegal instruction...
1.1.1.14 root 9154: if(!ignore_illegal_insn) {
9155: error("illegal instruction\n");
9156: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
9157: } else {
9158: #if defined(HAS_I386)
9159: m_eip++;
9160: #else
9161: m_pc++;
9162: #endif
9163: }
1.1 root 9164: break;
1.1.1.8 root 9165: case 0x08:
1.1.1.14 root 9166: // pcbios_irq0(); // this causes too slow emulation...
1.1.1.8 root 9167: case 0x09:
9168: case 0x0a:
9169: case 0x0b:
9170: case 0x0c:
9171: case 0x0d:
9172: case 0x0e:
9173: case 0x0f:
9174: // EOI
9175: pic[0].isr &= ~(1 << (num - 0x08));
9176: pic_update();
9177: break;
1.1 root 9178: case 0x10:
9179: // PC BIOS - Video
1.1.1.14 root 9180: if(!restore_console_on_exit) {
1.1.1.15 root 9181: change_console_size(scr_width, scr_height);
1.1 root 9182: }
1.1.1.3 root 9183: m_CF = 0;
1.1 root 9184: switch(REG8(AH)) {
1.1.1.16 root 9185: case 0x00: pcbios_int_10h_00h(); break;
1.1 root 9186: case 0x01: pcbios_int_10h_01h(); break;
9187: case 0x02: pcbios_int_10h_02h(); break;
9188: case 0x03: pcbios_int_10h_03h(); break;
9189: case 0x05: pcbios_int_10h_05h(); break;
9190: case 0x06: pcbios_int_10h_06h(); break;
9191: case 0x07: pcbios_int_10h_07h(); break;
9192: case 0x08: pcbios_int_10h_08h(); break;
9193: case 0x09: pcbios_int_10h_09h(); break;
9194: case 0x0a: pcbios_int_10h_0ah(); break;
9195: case 0x0b: break;
9196: case 0x0c: break;
9197: case 0x0d: break;
9198: case 0x0e: pcbios_int_10h_0eh(); break;
9199: case 0x0f: pcbios_int_10h_0fh(); break;
9200: case 0x10: break;
1.1.1.14 root 9201: case 0x11: pcbios_int_10h_11h(); break;
9202: case 0x12: pcbios_int_10h_12h(); break;
1.1 root 9203: case 0x13: pcbios_int_10h_13h(); break;
9204: case 0x18: REG8(AL) = 0x86; break;
1.1.1.14 root 9205: case 0x1a: pcbios_int_10h_1ah(); break;
1.1.1.11 root 9206: case 0x1b: break;
1.1 root 9207: case 0x1c: REG8(AL) = 0x00; break;
9208: case 0x1d: pcbios_int_10h_1dh(); break;
1.1.1.22 root 9209: case 0x4f: pcbios_int_10h_4fh(); break;
9210: case 0x80: m_CF = 1; break; // unknown
9211: case 0x81: m_CF = 1; break; // unknown
1.1 root 9212: case 0x82: pcbios_int_10h_82h(); break;
1.1.1.22 root 9213: case 0x83: pcbios_int_10h_83h(); break;
9214: case 0x8b: break;
9215: case 0x8c: m_CF = 1; break; // unknown
9216: case 0x8d: m_CF = 1; break; // unknown
9217: case 0x8e: m_CF = 1; break; // unknown
9218: case 0x90: pcbios_int_10h_90h(); break;
9219: case 0x91: pcbios_int_10h_91h(); break;
9220: case 0x92: break;
9221: case 0x93: break;
9222: case 0xef: pcbios_int_10h_efh(); break;
1.1 root 9223: case 0xfe: pcbios_int_10h_feh(); break;
9224: case 0xff: pcbios_int_10h_ffh(); break;
9225: default:
1.1.1.22 root 9226: 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));
9227: m_CF = 1;
1.1 root 9228: break;
9229: }
9230: break;
9231: case 0x11:
9232: // PC BIOS - Get Equipment List
1.1.1.11 root 9233: #ifdef SUPPORT_FPU
9234: REG16(AX) = 0x22;
9235: #else
1.1 root 9236: REG16(AX) = 0x20;
1.1.1.11 root 9237: #endif
1.1 root 9238: break;
9239: case 0x12:
9240: // PC BIOS - Get Memory Size
9241: REG16(AX) = MEMORY_END / 1024;
9242: break;
9243: case 0x13:
9244: // PC BIOS - Disk
1.1.1.22 root 9245: // 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 9246: REG8(AH) = 0xff;
1.1.1.3 root 9247: m_CF = 1;
1.1 root 9248: break;
9249: case 0x14:
9250: // PC BIOS - Serial I/O
1.1.1.22 root 9251: // 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 9252: REG8(AH) = 0xff;
1.1.1.3 root 9253: m_CF = 1;
1.1 root 9254: break;
9255: case 0x15:
9256: // PC BIOS
1.1.1.3 root 9257: m_CF = 0;
1.1 root 9258: switch(REG8(AH)) {
1.1.1.14 root 9259: case 0x10: pcbios_int_15h_10h(); break;
1.1 root 9260: case 0x23: pcbios_int_15h_23h(); break;
9261: case 0x24: pcbios_int_15h_24h(); break;
9262: case 0x49: pcbios_int_15h_49h(); break;
1.1.1.22 root 9263: case 0x50: pcbios_int_15h_50h(); break;
1.1 root 9264: case 0x86: pcbios_int_15h_86h(); break;
9265: case 0x87: pcbios_int_15h_87h(); break;
9266: case 0x88: pcbios_int_15h_88h(); break;
9267: case 0x89: pcbios_int_15h_89h(); break;
1.1.1.21 root 9268: case 0x8a: pcbios_int_15h_8ah(); break;
1.1.1.22 root 9269: case 0xc0: // PS/2 ???
9270: case 0xc1:
9271: case 0xc2:
9272: REG8(AH) = 0x86;
9273: m_CF = 1;
9274: break;
1.1.1.3 root 9275: #if defined(HAS_I386)
1.1 root 9276: case 0xc9: pcbios_int_15h_c9h(); break;
1.1.1.3 root 9277: #endif
1.1 root 9278: case 0xca: pcbios_int_15h_cah(); break;
1.1.1.22 root 9279: case 0xe8: pcbios_int_15h_e8h(); break;
1.1 root 9280: default:
1.1.1.22 root 9281: 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));
9282: REG8(AH) = 0x86;
1.1.1.3 root 9283: m_CF = 1;
1.1 root 9284: break;
9285: }
9286: break;
9287: case 0x16:
9288: // PC BIOS - Keyboard
1.1.1.3 root 9289: m_CF = 0;
1.1 root 9290: switch(REG8(AH)) {
9291: case 0x00: pcbios_int_16h_00h(); break;
9292: case 0x01: pcbios_int_16h_01h(); break;
9293: case 0x02: pcbios_int_16h_02h(); break;
9294: case 0x03: pcbios_int_16h_03h(); break;
9295: case 0x05: pcbios_int_16h_05h(); break;
9296: case 0x10: pcbios_int_16h_00h(); break;
9297: case 0x11: pcbios_int_16h_01h(); break;
9298: case 0x12: pcbios_int_16h_12h(); break;
9299: case 0x13: pcbios_int_16h_13h(); break;
9300: case 0x14: pcbios_int_16h_14h(); break;
1.1.1.22 root 9301: case 0xda: break; // unknown
9302: case 0xff: break; // unknown
1.1 root 9303: default:
1.1.1.22 root 9304: 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 9305: break;
9306: }
9307: break;
9308: case 0x17:
9309: // PC BIOS - Printer
1.1.1.22 root 9310: // 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 9311: break;
9312: case 0x1a:
9313: // PC BIOS - Timer
1.1.1.3 root 9314: m_CF = 0;
1.1 root 9315: switch(REG8(AH)) {
9316: case 0x00: pcbios_int_1ah_00h(); break;
9317: case 0x01: break;
9318: case 0x02: pcbios_int_1ah_02h(); break;
9319: case 0x03: break;
9320: case 0x04: pcbios_int_1ah_04h(); break;
9321: case 0x05: break;
9322: case 0x0a: pcbios_int_1ah_0ah(); break;
9323: case 0x0b: break;
1.1.1.14 root 9324: case 0x35: break; // Word Perfect Third Party Interface?
9325: case 0x36: break; // Word Perfect Third Party Interface
9326: case 0x70: break; // SNAP? (Simple Network Application Protocol)
1.1 root 9327: default:
1.1.1.22 root 9328: 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 9329: break;
9330: }
9331: break;
9332: case 0x20:
1.1.1.3 root 9333: msdos_process_terminate(SREG(CS), retval, 1);
1.1 root 9334: break;
9335: case 0x21:
9336: // MS-DOS System Call
1.1.1.3 root 9337: m_CF = 0;
1.1 root 9338: switch(REG8(AH)) {
9339: case 0x00: msdos_int_21h_00h(); break;
9340: case 0x01: msdos_int_21h_01h(); break;
9341: case 0x02: msdos_int_21h_02h(); break;
9342: case 0x03: msdos_int_21h_03h(); break;
9343: case 0x04: msdos_int_21h_04h(); break;
9344: case 0x05: msdos_int_21h_05h(); break;
9345: case 0x06: msdos_int_21h_06h(); break;
9346: case 0x07: msdos_int_21h_07h(); break;
9347: case 0x08: msdos_int_21h_08h(); break;
9348: case 0x09: msdos_int_21h_09h(); break;
9349: case 0x0a: msdos_int_21h_0ah(); break;
9350: case 0x0b: msdos_int_21h_0bh(); break;
9351: case 0x0c: msdos_int_21h_0ch(); break;
9352: case 0x0d: msdos_int_21h_0dh(); break;
9353: case 0x0e: msdos_int_21h_0eh(); break;
1.1.1.14 root 9354: case 0x0f: msdos_int_21h_0fh(); break;
9355: case 0x10: msdos_int_21h_10h(); break;
1.1 root 9356: case 0x11: msdos_int_21h_11h(); break;
9357: case 0x12: msdos_int_21h_12h(); break;
9358: case 0x13: msdos_int_21h_13h(); break;
1.1.1.16 root 9359: case 0x14: msdos_int_21h_14h(); break;
9360: case 0x15: msdos_int_21h_15h(); break;
1.1.1.14 root 9361: case 0x16: msdos_int_21h_16h(); break;
1.1.1.16 root 9362: case 0x17: msdos_int_21h_17h(); break;
1.1 root 9363: case 0x18: msdos_int_21h_18h(); break;
9364: case 0x19: msdos_int_21h_19h(); break;
9365: case 0x1a: msdos_int_21h_1ah(); break;
9366: case 0x1b: msdos_int_21h_1bh(); break;
9367: case 0x1c: msdos_int_21h_1ch(); break;
9368: case 0x1d: msdos_int_21h_1dh(); break;
9369: case 0x1e: msdos_int_21h_1eh(); break;
9370: case 0x1f: msdos_int_21h_1fh(); break;
9371: case 0x20: msdos_int_21h_20h(); break;
1.1.1.14 root 9372: case 0x21: msdos_int_21h_21h(); break;
9373: case 0x22: msdos_int_21h_22h(); break;
1.1.1.16 root 9374: case 0x23: msdos_int_21h_23h(); break;
9375: case 0x24: msdos_int_21h_24h(); break;
1.1 root 9376: case 0x25: msdos_int_21h_25h(); break;
9377: case 0x26: msdos_int_21h_26h(); break;
1.1.1.16 root 9378: case 0x27: msdos_int_21h_27h(); break;
9379: case 0x28: msdos_int_21h_28h(); break;
1.1 root 9380: case 0x29: msdos_int_21h_29h(); break;
9381: case 0x2a: msdos_int_21h_2ah(); break;
9382: case 0x2b: msdos_int_21h_2bh(); break;
9383: case 0x2c: msdos_int_21h_2ch(); break;
9384: case 0x2d: msdos_int_21h_2dh(); break;
9385: case 0x2e: msdos_int_21h_2eh(); break;
9386: case 0x2f: msdos_int_21h_2fh(); break;
9387: case 0x30: msdos_int_21h_30h(); break;
9388: case 0x31: msdos_int_21h_31h(); break;
9389: case 0x32: msdos_int_21h_32h(); break;
9390: case 0x33: msdos_int_21h_33h(); break;
1.1.1.23! root 9391: case 0x34: msdos_int_21h_34h(); break;
1.1 root 9392: case 0x35: msdos_int_21h_35h(); break;
9393: case 0x36: msdos_int_21h_36h(); break;
9394: case 0x37: msdos_int_21h_37h(); break;
1.1.1.14 root 9395: case 0x38: msdos_int_21h_38h(); break;
1.1 root 9396: case 0x39: msdos_int_21h_39h(0); break;
9397: case 0x3a: msdos_int_21h_3ah(0); break;
9398: case 0x3b: msdos_int_21h_3bh(0); break;
9399: case 0x3c: msdos_int_21h_3ch(); break;
9400: case 0x3d: msdos_int_21h_3dh(); break;
9401: case 0x3e: msdos_int_21h_3eh(); break;
9402: case 0x3f: msdos_int_21h_3fh(); break;
9403: case 0x40: msdos_int_21h_40h(); break;
9404: case 0x41: msdos_int_21h_41h(0); break;
9405: case 0x42: msdos_int_21h_42h(); break;
9406: case 0x43: msdos_int_21h_43h(0); break;
9407: case 0x44: msdos_int_21h_44h(); break;
9408: case 0x45: msdos_int_21h_45h(); break;
9409: case 0x46: msdos_int_21h_46h(); break;
9410: case 0x47: msdos_int_21h_47h(0); break;
9411: case 0x48: msdos_int_21h_48h(); break;
9412: case 0x49: msdos_int_21h_49h(); break;
9413: case 0x4a: msdos_int_21h_4ah(); break;
9414: case 0x4b: msdos_int_21h_4bh(); break;
9415: case 0x4c: msdos_int_21h_4ch(); break;
9416: case 0x4d: msdos_int_21h_4dh(); break;
9417: case 0x4e: msdos_int_21h_4eh(); break;
9418: case 0x4f: msdos_int_21h_4fh(); break;
9419: case 0x50: msdos_int_21h_50h(); break;
9420: case 0x51: msdos_int_21h_51h(); break;
9421: case 0x52: msdos_int_21h_52h(); break;
9422: // 0x53: translate bios parameter block to drive param bock
9423: case 0x54: msdos_int_21h_54h(); break;
9424: case 0x55: msdos_int_21h_55h(); break;
9425: case 0x56: msdos_int_21h_56h(0); break;
9426: case 0x57: msdos_int_21h_57h(); break;
9427: case 0x58: msdos_int_21h_58h(); break;
9428: case 0x59: msdos_int_21h_59h(); break;
9429: case 0x5a: msdos_int_21h_5ah(); break;
9430: case 0x5b: msdos_int_21h_5bh(); break;
9431: case 0x5c: msdos_int_21h_5ch(); break;
1.1.1.22 root 9432: case 0x5d: msdos_int_21h_5dh(); break;
1.1 root 9433: // 0x5e: ms-network
9434: // 0x5f: ms-network
9435: case 0x60: msdos_int_21h_60h(0); break;
9436: case 0x61: msdos_int_21h_61h(); break;
9437: case 0x62: msdos_int_21h_62h(); break;
9438: case 0x63: msdos_int_21h_63h(); break;
9439: // 0x64: set device driver lockahead flag
9440: case 0x65: msdos_int_21h_65h(); break;
9441: case 0x66: msdos_int_21h_66h(); break;
9442: case 0x67: msdos_int_21h_67h(); break;
9443: case 0x68: msdos_int_21h_68h(); break;
9444: case 0x69: msdos_int_21h_69h(); break;
9445: case 0x6a: msdos_int_21h_6ah(); break;
9446: case 0x6b: msdos_int_21h_6bh(); break;
9447: case 0x6c: msdos_int_21h_6ch(0); break;
9448: // 0x6d: find first rom program
9449: // 0x6e: find next rom program
9450: // 0x6f: get/set rom scan start address
9451: // 0x70: windows95 get/set internationalization information
9452: case 0x71:
9453: // windows95 long filename functions
9454: switch(REG8(AL)) {
9455: case 0x0d: msdos_int_21h_710dh(); break;
9456: case 0x39: msdos_int_21h_39h(1); break;
9457: case 0x3a: msdos_int_21h_3ah(1); break;
9458: case 0x3b: msdos_int_21h_3bh(1); break;
1.1.1.17 root 9459: case 0x41: msdos_int_21h_7141h(1); break;
1.1 root 9460: case 0x43: msdos_int_21h_43h(1); break;
9461: case 0x47: msdos_int_21h_47h(1); break;
9462: case 0x4e: msdos_int_21h_714eh(); break;
9463: case 0x4f: msdos_int_21h_714fh(); break;
9464: case 0x56: msdos_int_21h_56h(1); break;
9465: case 0x60: msdos_int_21h_60h(1); break;
9466: case 0x6c: msdos_int_21h_6ch(1); break;
9467: case 0xa0: msdos_int_21h_71a0h(); break;
9468: case 0xa1: msdos_int_21h_71a1h(); break;
9469: case 0xa6: msdos_int_21h_71a6h(); break;
9470: case 0xa7: msdos_int_21h_71a7h(); break;
9471: case 0xa8: msdos_int_21h_71a8h(); break;
9472: // 0xa9: server create/open file
1.1.1.22 root 9473: case 0xaa: msdos_int_21h_71aah(); break;
1.1 root 9474: default:
1.1.1.22 root 9475: 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 9476: REG16(AX) = 0x7100;
1.1.1.3 root 9477: m_CF = 1;
1.1 root 9478: break;
9479: }
9480: break;
9481: // 0x72: Windows95 beta - LFN FindClose
9482: case 0x73:
9483: // windows95 fat32 functions
9484: switch(REG8(AL)) {
1.1.1.14 root 9485: case 0x00: msdos_int_21h_7300h(); break;
9486: // 0x01: set drive locking ???
9487: case 0x02: msdos_int_21h_7302h(); break;
1.1 root 9488: case 0x03: msdos_int_21h_7303h(); break;
9489: // 0x04: set dpb to use for formatting
9490: default:
1.1.1.22 root 9491: 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 9492: REG16(AX) = 0x7300;
1.1.1.3 root 9493: m_CF = 1;
1.1 root 9494: break;
9495: }
9496: break;
9497: default:
1.1.1.22 root 9498: 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 9499: REG16(AX) = 0x01;
1.1.1.3 root 9500: m_CF = 1;
1.1 root 9501: break;
9502: }
1.1.1.3 root 9503: if(m_CF) {
1.1.1.23! root 9504: sda_t *sda = (sda_t *)(mem + SDA_TOP);
! 9505: sda->extended_error_code = REG16(AX);
! 9506: switch(sda->extended_error_code) {
! 9507: case 4: // Too many open files
! 9508: case 8: // Insufficient memory
! 9509: sda->error_class = 1; // Out of resource
! 9510: break;
! 9511: case 5: // Access denied
! 9512: sda->error_class = 3; // Authorization
! 9513: break;
! 9514: case 7: // Memory control block destroyed
! 9515: sda->error_class = 4; // Internal
! 9516: break;
! 9517: case 2: // File not found
! 9518: case 3: // Path not found
! 9519: case 15: // Invaid drive specified
! 9520: case 18: // No more files
! 9521: sda->error_class = 8; // Not found
! 9522: break;
! 9523: case 32: // Sharing violation
! 9524: case 33: // Lock violation
! 9525: sda->error_class = 10; // Locked
! 9526: break;
! 9527: // case 16: // Removal of current directory attempted
! 9528: case 19: // Attempted write on protected disk
! 9529: case 21: // Drive not ready
! 9530: // case 29: // Write failure
! 9531: // case 30: // Read failure
! 9532: // case 82: // Cannot create subdirectory
! 9533: sda->error_class = 11; // Media
! 9534: break;
! 9535: case 80: // File already exists
! 9536: sda->error_class = 12; // Already exist
! 9537: break;
! 9538: default:
! 9539: sda->error_class = 13; // Unknown
! 9540: break;
! 9541: }
! 9542: sda->suggested_action = 1; // Retry
! 9543: sda->locus_of_last_error = 1; // Unknown
1.1 root 9544: }
9545: break;
9546: case 0x22:
9547: fatalerror("int 22h (terminate address)\n");
9548: case 0x23:
9549: msdos_process_terminate(current_psp, (retval & 0xff) | 0x100, 1);
9550: break;
9551: case 0x24:
9552: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
9553: break;
9554: case 0x25:
9555: msdos_int_25h();
9556: break;
9557: case 0x26:
9558: msdos_int_26h();
9559: break;
9560: case 0x27:
9561: msdos_int_27h();
9562: break;
9563: case 0x28:
9564: Sleep(10);
9565: break;
9566: case 0x29:
9567: msdos_int_29h();
9568: break;
9569: case 0x2e:
9570: msdos_int_2eh();
9571: break;
9572: case 0x2f:
9573: // multiplex interrupt
9574: switch(REG8(AH)) {
1.1.1.22 root 9575: case 0x00: break;
9576: case 0x01: msdos_int_2fh_01h(); break;
9577: case 0x05: msdos_int_2fh_05h(); break;
9578: case 0x06: msdos_int_2fh_06h(); break;
9579: case 0x08: msdos_int_2fh_08h(); break;
9580: case 0x10: msdos_int_2fh_10h(); break;
9581: case 0x11: msdos_int_2fh_11h(); break;
1.1.1.21 root 9582: case 0x12: msdos_int_2fh_12h(); break;
1.1.1.22 root 9583: case 0x14: msdos_int_2fh_14h(); break;
9584: case 0x15: msdos_int_2fh_15h(); break;
1.1 root 9585: case 0x16: msdos_int_2fh_16h(); break;
1.1.1.22 root 9586: case 0x19: msdos_int_2fh_19h(); break;
1.1 root 9587: case 0x1a: msdos_int_2fh_1ah(); break;
1.1.1.22 root 9588: case 0x1b: msdos_int_2fh_1bh(); break;
1.1 root 9589: case 0x43: msdos_int_2fh_43h(); break;
1.1.1.22 root 9590: case 0x46: msdos_int_2fh_46h(); break;
9591: case 0x48: msdos_int_2fh_48h(); break;
1.1 root 9592: case 0x4a: msdos_int_2fh_4ah(); break;
1.1.1.22 root 9593: case 0x4b: msdos_int_2fh_4bh(); break;
9594: case 0x4c: break; // unknown
9595: case 0x4d: break; // unknown
9596: case 0x4e: break; // unknown
1.1 root 9597: case 0x4f: msdos_int_2fh_4fh(); break;
1.1.1.22 root 9598: case 0x55: msdos_int_2fh_55h(); break;
9599: case 0x58: break; // unknown
9600: case 0x74: break; // unknown
1.1 root 9601: case 0xae: msdos_int_2fh_aeh(); break;
9602: case 0xb7: msdos_int_2fh_b7h(); break;
1.1.1.22 root 9603: case 0xe9: break; // unknown
9604: case 0xfe: break; // norton utilities ???
9605: default:
9606: 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));
9607: break;
1.1 root 9608: }
9609: break;
1.1.1.19 root 9610: case 0x68:
9611: // dummy interrupt for EMS (int 67h)
9612: switch(REG8(AH)) {
9613: case 0x40: msdos_int_67h_40h(); break;
9614: case 0x41: msdos_int_67h_41h(); break;
9615: case 0x42: msdos_int_67h_42h(); break;
9616: case 0x43: msdos_int_67h_43h(); break;
9617: case 0x44: msdos_int_67h_44h(); break;
9618: case 0x45: msdos_int_67h_45h(); break;
9619: case 0x46: msdos_int_67h_46h(); break;
9620: case 0x47: msdos_int_67h_47h(); break;
9621: case 0x48: msdos_int_67h_48h(); break;
1.1.1.20 root 9622: // 0x49: LIM EMS - Reserved - Get I/O Port Address (Undocumented in EMS 3.2)
9623: // 0x4a: LIM EMS - Reserved - Get Translation Array (Undocumented in EMS 3.2)
1.1.1.19 root 9624: case 0x4b: msdos_int_67h_4bh(); break;
9625: case 0x4c: msdos_int_67h_4ch(); break;
9626: case 0x4d: msdos_int_67h_4dh(); break;
1.1.1.20 root 9627: case 0x4e: msdos_int_67h_4eh(); break;
1.1.1.21 root 9628: case 0x4f: msdos_int_67h_4fh(); break;
1.1.1.20 root 9629: case 0x50: msdos_int_67h_50h(); break;
1.1.1.19 root 9630: case 0x51: msdos_int_67h_51h(); break;
1.1.1.20 root 9631: case 0x52: msdos_int_67h_52h(); break;
1.1.1.19 root 9632: case 0x53: msdos_int_67h_53h(); break;
9633: case 0x54: msdos_int_67h_54h(); break;
1.1.1.20 root 9634: // 0x55: LIM EMS 4.0 - Alter Page Map And JUMP
9635: // 0x56: LIM EMS 4.0 - Alter Page Map And CALL
9636: case 0x57: msdos_int_67h_57h(); break;
9637: case 0x58: msdos_int_67h_58h(); break;
9638: // 0x59: LIM EMS 4.0 - Get Expanded Memory Hardware Information (for DOS Kernel)
9639: case 0x5a: msdos_int_67h_5ah(); break;
9640: // 0x5b: LIM EMS 4.0 - Alternate Map Register Set (for DOS Kernel)
9641: // 0x5c: LIM EMS 4.0 - Prepate Expanded Memory Hardware For Warm Boot
9642: // 0x5d: LIM EMS 4.0 - Enable/Disable OS Function Set Functions (for DOS Kernel)
1.1.1.19 root 9643: default:
1.1.1.22 root 9644: 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 9645: REG8(AH) = 0x84;
9646: break;
9647: }
9648: break;
9649: #ifdef SUPPORT_XMS
9650: case 0x69:
9651: // dummy interrupt for XMS (call far)
9652: switch(REG8(AH)) {
9653: case 0x00: msdos_call_xms_00h(); break;
9654: case 0x01: msdos_call_xms_01h(); break;
9655: case 0x02: msdos_call_xms_02h(); break;
9656: case 0x03: msdos_call_xms_03h(); break;
9657: case 0x04: msdos_call_xms_04h(); break;
9658: case 0x05: msdos_call_xms_05h(); break;
9659: case 0x06: msdos_call_xms_06h(); break;
9660: case 0x07: msdos_call_xms_07h(); break;
9661: case 0x08: msdos_call_xms_08h(); break;
9662: case 0x09: msdos_call_xms_09h(); break;
9663: case 0x0a: msdos_call_xms_0ah(); break;
9664: case 0x0b: msdos_call_xms_0bh(); break;
9665: case 0x0c: msdos_call_xms_0ch(); break;
9666: case 0x0d: msdos_call_xms_0dh(); break;
9667: case 0x0e: msdos_call_xms_0eh(); break;
9668: case 0x0f: msdos_call_xms_0fh(); break;
9669: case 0x10: msdos_call_xms_10h(); break;
9670: case 0x11: msdos_call_xms_11h(); break;
9671: case 0x12: msdos_call_xms_12h(); break;
9672: // 0x88: XMS 3.0 - Query free extended memory
9673: // 0x89: XMS 3.0 - Allocate any extended memory
9674: // 0x8e: XMS 3.0 - Get extended EMB handle information
9675: // 0x8f: XMS 3.0 - Reallocate any extended memory block
9676: default:
1.1.1.22 root 9677: 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 9678: REG16(AX) = 0x0000;
9679: REG8(BL) = 0x80;
9680: break;
9681: }
9682: break;
9683: #endif
9684: case 0x6a:
9685: // dummy interrupt for case map routine pointed in the country info
9686: if(REG8(AL) >= 0x80) {
9687: char tmp[2] = {0};
9688: tmp[0] = REG8(AL);
9689: my_strupr(tmp);
9690: REG8(AL) = tmp[0];
9691: }
9692: break;
1.1.1.8 root 9693: case 0x70:
9694: case 0x71:
9695: case 0x72:
9696: case 0x73:
9697: case 0x74:
9698: case 0x75:
9699: case 0x76:
9700: case 0x77:
9701: // EOI
9702: if((pic[1].isr &= ~(1 << (num - 0x70))) == 0) {
9703: pic[0].isr &= ~(1 << 2); // master
9704: }
9705: pic_update();
9706: break;
1.1 root 9707: default:
1.1.1.22 root 9708: // 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 9709: break;
9710: }
9711:
9712: // update cursor position
9713: if(cursor_moved) {
9714: CONSOLE_SCREEN_BUFFER_INFO csbi;
1.1.1.23! root 9715: GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
1.1.1.15 root 9716: if(!restore_console_on_exit) {
9717: scr_top = csbi.srWindow.Top;
9718: }
1.1 root 9719: mem[0x450 + mem[0x462] * 2] = csbi.dwCursorPosition.X;
1.1.1.14 root 9720: mem[0x451 + mem[0x462] * 2] = csbi.dwCursorPosition.Y - scr_top;
1.1 root 9721: cursor_moved = false;
9722: }
9723: }
9724:
9725: // init
9726:
9727: int msdos_init(int argc, char *argv[], char *envp[], int standard_env)
9728: {
9729: // init file handler
9730: memset(file_handler, 0, sizeof(file_handler));
9731: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
9732: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
9733: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
1.1.1.21 root 9734: #ifdef MAP_AUX_DEVICE_TO_FILE
1.1 root 9735: if(_open("stdaux.txt", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
1.1.1.21 root 9736: #else
9737: if(_open("NUL", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
9738: #endif
9739: msdos_file_handler_open(3, "STDAUX", 0, 2, 0x80c0, 0);
1.1 root 9740: }
1.1.1.21 root 9741: #ifdef MAP_PRN_DEVICE_TO_FILE
1.1 root 9742: if(_open("stdprn.txt", _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 4) {
1.1.1.21 root 9743: #else
9744: if(_open("NUL", _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 4) {
1.1 root 9745: #endif
1.1.1.21 root 9746: msdos_file_handler_open(4, "STDPRN", 0, 1, 0xa8c0, 0);
9747: }
1.1 root 9748: _dup2(0, DUP_STDIN);
9749: _dup2(1, DUP_STDOUT);
9750: _dup2(2, DUP_STDERR);
1.1.1.21 root 9751: _dup2(3, DUP_STDAUX);
9752: _dup2(4, DUP_STDPRN);
1.1 root 9753:
9754: // init process
9755: memset(process, 0, sizeof(process));
9756:
1.1.1.13 root 9757: // init dtainfo
9758: msdos_dta_info_init();
9759:
1.1 root 9760: // init memory
9761: memset(mem, 0, sizeof(mem));
9762:
9763: // bios data area
1.1.1.23! root 9764: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 9765: CONSOLE_SCREEN_BUFFER_INFO csbi;
9766: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 9767: CONSOLE_FONT_INFO cfi;
9768: GetCurrentConsoleFont(hStdout, FALSE, &cfi);
9769:
9770: int regen = min(scr_width * scr_height * 2, 0x8000);
9771: text_vram_top_address = TEXT_VRAM_TOP;
9772: text_vram_end_address = text_vram_top_address + regen;
9773: shadow_buffer_top_address = SHADOW_BUF_TOP;
9774: shadow_buffer_end_address = shadow_buffer_top_address + regen;
9775:
9776: if(regen > 0x4000) {
9777: regen = 0x8000;
9778: vram_pages = 1;
9779: } else if(regen > 0x2000) {
9780: regen = 0x4000;
9781: vram_pages = 2;
9782: } else if(regen > 0x1000) {
9783: regen = 0x2000;
9784: vram_pages = 4;
9785: } else {
9786: regen = 0x1000;
9787: vram_pages = 8;
9788: }
1.1 root 9789:
1.1.1.14 root 9790: #ifdef SUPPORT_FPU
9791: *(UINT16 *)(mem + 0x410) = 0x22;
9792: #else
1.1 root 9793: *(UINT16 *)(mem + 0x410) = 0x20;
1.1.1.14 root 9794: #endif
1.1 root 9795: *(UINT16 *)(mem + 0x413) = MEMORY_END / 1024;
9796: *(UINT8 *)(mem + 0x449) = 0x03;//0x73;
1.1.1.14 root 9797: *(UINT16 *)(mem + 0x44a) = csbi.dwSize.X;
9798: *(UINT16 *)(mem + 0x44c) = regen;
1.1 root 9799: *(UINT16 *)(mem + 0x44e) = 0;
9800: *(UINT8 *)(mem + 0x450) = csbi.dwCursorPosition.X;
1.1.1.14 root 9801: *(UINT8 *)(mem + 0x451) = csbi.dwCursorPosition.Y - scr_top;
1.1 root 9802: *(UINT8 *)(mem + 0x460) = 7;
9803: *(UINT8 *)(mem + 0x461) = 7;
9804: *(UINT8 *)(mem + 0x462) = 0;
9805: *(UINT16 *)(mem + 0x463) = 0x3d4;
1.1.1.19 root 9806: *(UINT8 *)(mem + 0x465) = 0x09;
9807: *(UINT32 *)(mem + 0x46c) = get_ticks_since_midnight(timeGetTime());
1.1.1.14 root 9808: *(UINT8 *)(mem + 0x484) = csbi.srWindow.Bottom - csbi.srWindow.Top;
9809: *(UINT8 *)(mem + 0x485) = cfi.dwFontSize.Y;
9810: *(UINT8 *)(mem + 0x487) = 0x60;
9811: *(UINT8 *)(mem + 0x496) = 0x10; // enhanced keyboard installed
9812:
9813: // initial screen
9814: SMALL_RECT rect;
9815: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
9816: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
9817: for(int y = 0, ofs1 = TEXT_VRAM_TOP, ofs2 = SHADOW_BUF_TOP; y < scr_height; y++) {
9818: for(int x = 0; x < scr_width; x++) {
9819: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Char.AsciiChar;
9820: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Attributes;
9821: }
9822: }
1.1 root 9823:
9824: // dos info
9825: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
1.1.1.19 root 9826: dos_info->magic_word = 1;
1.1 root 9827: dos_info->first_mcb = MEMORY_TOP >> 4;
9828: dos_info->first_dpb.w.l = 0;
9829: dos_info->first_dpb.w.h = DPB_TOP >> 4;
9830: dos_info->first_sft.w.l = 0;
1.1.1.21 root 9831: dos_info->first_sft.w.h = SFT_TOP >> 4;
1.1.1.19 root 9832: dos_info->max_sector_len = 512;
9833: dos_info->disk_buf_info.w.l = offsetof(dos_info_t, disk_buf_heads);
9834: dos_info->disk_buf_info.w.h = DOS_INFO_TOP >> 4;
1.1 root 9835: dos_info->cds.w.l = 0;
9836: dos_info->cds.w.h = CDS_TOP >> 4;
9837: dos_info->fcb_table.w.l = 0;
9838: dos_info->fcb_table.w.h = FCB_TABLE_TOP >> 4;
9839: dos_info->last_drive = 'Z' - 'A' + 1;
9840: dos_info->buffers_x = 20;
9841: dos_info->buffers_y = 0;
1.1.1.14 root 9842: dos_info->boot_drive = 'C' - 'A' + 1;
1.1.1.19 root 9843: dos_info->nul_device.next_driver = 0xffffffffU;
9844: dos_info->nul_device.attributes = 0x8004U;
9845: dos_info->nul_device.strategy = 0xffffU;
9846: dos_info->nul_device.interrupt = 0xffffU;
9847: memcpy(dos_info->nul_device.dev_name, "NUL ", 8);
9848: dos_info->disk_buf_heads.w.l = 0;
9849: dos_info->disk_buf_heads.w.h = DISK_BUF_TOP >> 4;
1.1.1.20 root 9850: dos_info->first_umb_fcb = UMB_TOP >> 4;
9851: dos_info->first_mcb_2 = MEMORY_TOP >> 4;
1.1.1.17 root 9852:
1.1 root 9853: char *env;
9854: if((env = getenv("LASTDRIVE")) != NULL) {
9855: if(env[0] >= 'A' && env[0] <= 'Z') {
9856: dos_info->last_drive = env[0] - 'A' + 1;
9857: } else if(env[0] >= 'a' && env[0] <= 'z') {
9858: dos_info->last_drive = env[0] - 'a' + 1;
9859: }
9860: }
9861: if((env = getenv("windir")) != NULL) {
9862: if(env[0] >= 'A' && env[0] <= 'Z') {
9863: dos_info->boot_drive = env[0] - 'A' + 1;
9864: } else if(env[0] >= 'a' && env[0] <= 'z') {
9865: dos_info->boot_drive = env[0] - 'a' + 1;
9866: }
9867: }
1.1.1.3 root 9868: #if defined(HAS_I386)
1.1 root 9869: dos_info->i386_or_later = 1;
1.1.1.3 root 9870: #else
9871: dos_info->i386_or_later = 0;
9872: #endif
1.1.1.17 root 9873: dos_info->ext_mem_size = (min(MAX_MEM, 0x4000000) - 0x100000) >> 10;
1.1 root 9874:
1.1.1.19 root 9875: // init mcb
1.1 root 9876: int seg = MEMORY_TOP >> 4;
1.1.1.19 root 9877:
9878: // iret table
9879: // note: int 2eh vector should address the routine in command.com,
9880: // and some softwares invite (int 2eh vector segment) - 1 must address the mcb of command.com.
9881: // so move iret table into allocated memory block
9882: // http://www5c.biglobe.ne.jp/~ecb/assembler2/2_6.html
9883: msdos_mcb_create(seg++, 'M', -1, IRET_SIZE >> 4);
9884: IRET_TOP = seg << 4;
9885: seg += IRET_SIZE >> 4;
9886: memset(mem + IRET_TOP, 0xcf, IRET_SIZE);
9887:
9888: // dummy xms/ems device
9889: msdos_mcb_create(seg++, 'M', -1, XMS_SIZE >> 4);
9890: XMS_TOP = seg << 4;
9891: seg += XMS_SIZE >> 4;
9892:
9893: // environment
1.1 root 9894: msdos_mcb_create(seg++, 'M', -1, ENV_SIZE >> 4);
9895: int env_seg = seg;
9896: int ofs = 0;
1.1.1.15 root 9897: char env_path[8192] = "", *path;
1.1 root 9898:
9899: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1.1.14 root 9900: if(_strnicmp(*p, "MSDOS_PATH=", 11) == 0) {
9901: sprintf(env_path, "%s;", *p + 11);
9902: break;
9903: }
9904: }
9905: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1.1.9 root 9906: if(_strnicmp(*p, "PATH=", 5) == 0) {
1.1.1.14 root 9907: strcat(env_path, *p + 5);
1.1.1.9 root 9908: break;
9909: }
9910: }
1.1.1.18 root 9911: if((path = getenv("MSDOS_COMSPEC")) != NULL ||
9912: (path = msdos_search_command_com(argv[0], env_path)) != NULL) {
1.1.1.15 root 9913: strcpy(comspec_path, path);
9914: }
9915:
1.1.1.9 root 9916: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1 root 9917: // lower to upper
9918: char tmp[ENV_SIZE], name[ENV_SIZE], value[ENV_SIZE];
9919: int value_pos = 0;
9920: strcpy(tmp, *p);
9921: for(int i = 0;; i++) {
9922: if(tmp[i] == '=') {
9923: tmp[i] = '\0';
9924: sprintf(name, ";%s;", tmp);
9925: strcpy(value, tmp + (value_pos = i + 1));
9926: tmp[i] = '=';
9927: break;
9928: } else if(tmp[i] >= 'a' && tmp[i] <= 'z') {
9929: tmp[i] = tmp[i] - 'a' + 'A';
9930: }
9931: }
1.1.1.18 root 9932: if(strncmp(tmp, "MSDOS_COMSPEC=", 14) == 0) {
9933: // ignore MSDOS_COMSPEC
9934: } else if(standard_env && strstr(";COMSPEC;INCLUDE;LIB;PATH;PROMPT;TEMP;TMP;TZ;", name) == NULL) {
9935: // ignore non standard environments
9936: } else {
1.1 root 9937: if(strncmp(tmp, "COMSPEC=", 8) == 0) {
1.1.1.14 root 9938: strcpy(tmp, "COMSPEC=C:\\COMMAND.COM");
1.1 root 9939: } else if(strncmp(tmp, "PATH=", 5) == 0 || strncmp(tmp, "TEMP=", 5) == 0 || strncmp(tmp, "TMP=", 4) == 0) {
9940: tmp[value_pos] = '\0';
9941: char *token = my_strtok(value, ";");
9942: while(token != NULL) {
9943: if(strlen(token) != 0) {
1.1.1.8 root 9944: char *path = msdos_remove_double_quote(token), tmp_path[MAX_PATH];
9945: if(strlen(path) != 0) {
9946: GetShortPathName(path, tmp_path, MAX_PATH);
9947: strcat(tmp, tmp_path);
9948: strcat(tmp, ";");
1.1 root 9949: }
9950: }
9951: token = my_strtok(NULL, ";");
9952: }
9953: tmp[strlen(tmp) - 1] = '\0';
9954: my_strupr(tmp);
9955: }
9956: int len = strlen(tmp);
1.1.1.14 root 9957: if(ofs + len + 1 + (2 + (8 + 1 + 3)) + 2 > ENV_SIZE) {
1.1 root 9958: fatalerror("too many environments\n");
9959: }
9960: memcpy(mem + (seg << 4) + ofs, tmp, len);
9961: ofs += len + 1;
9962: }
9963: }
9964: seg += (ENV_SIZE >> 4);
9965:
9966: // psp
9967: msdos_mcb_create(seg++, 'M', -1, PSP_SIZE >> 4);
9968: current_psp = seg;
1.1.1.14 root 9969: msdos_psp_create(seg, seg + (PSP_SIZE >> 4), -1, env_seg);
1.1 root 9970: seg += (PSP_SIZE >> 4);
9971:
1.1.1.19 root 9972: // first free mcb in conventional memory
9973: msdos_mcb_create(seg, 'Z', 0, (MEMORY_END >> 4) - seg - 2);
1.1.1.8 root 9974: first_mcb = seg;
9975:
1.1.1.19 root 9976: // dummy mcb to link to umb
9977: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', -1, (UMB_TOP >> 4) - (MEMORY_END >> 4));
9978:
9979: // first free mcb in upper memory block
1.1.1.8 root 9980: msdos_mcb_create(UMB_TOP >> 4, 'Z', 0, (UMB_END >> 4) - (UMB_TOP >> 4) - 1);
1.1 root 9981:
1.1.1.19 root 9982: #ifdef SUPPORT_XMS
9983: // first free mcb in extended memory block
9984: msdos_mcb_create(EMB_TOP >> 4, 'Z', 0, (EMB_END >> 4) - (EMB_TOP >> 4) - 1);
9985: #endif
9986:
9987: // interrupt vector
9988: for(int i = 0; i < 0x80; i++) {
9989: *(UINT16 *)(mem + 4 * i + 0) = i;
9990: *(UINT16 *)(mem + 4 * i + 2) = (IRET_TOP >> 4);
9991: }
9992: *(UINT16 *)(mem + 4 * 0x08 + 0) = 0x0005; // irq0
9993: *(UINT16 *)(mem + 4 * 0x08 + 2) = 0xffff;
9994: *(UINT16 *)(mem + 4 * 0x22 + 0) = 0x0000; // boot
9995: *(UINT16 *)(mem + 4 * 0x22 + 2) = 0xffff;
9996: *(UINT16 *)(mem + 4 * 0x67 + 0) = 0x0000; // ems
9997: *(UINT16 *)(mem + 4 * 0x67 + 2) = XMS_TOP >> 4;
9998:
9999: // ems (int 67h) and xms (call far)
10000: mem[XMS_TOP + 0] = 0xcd; // int 68h (dummy)
10001: mem[XMS_TOP + 1] = 0x68;
10002: mem[XMS_TOP + 2] = 0xcf; // iret
10003: #ifdef SUPPORT_XMS
10004: if(support_xms) {
10005: mem[XMS_TOP + 4] = 0xcd; // int 69h (dummy)
10006: mem[XMS_TOP + 5] = 0x69;
10007: mem[XMS_TOP + 6] = 0xcb; // retf
10008: } else
10009: #endif
10010: mem[XMS_TOP + 4] = 0xcb; // retf
10011: memcpy(mem + XMS_TOP + 0x0a, "EMMXXXX0", 8);
10012:
10013: // case map routine (call far)
10014: mem[0xffffc] = 0xcd; // int 6ah (dummy)
10015: mem[0xffffd] = 0x6a;
10016: mem[0xffffe] = 0xcb; // retf
10017:
1.1.1.14 root 10018: // have irq0 call system timer tick
1.1.1.19 root 10019: mem[0xffff5] = 0xcd; // int 1ch
10020: mem[0xffff6] = 0x1c;
10021: mem[0xffff7] = 0xea; // jmp (IRET_TOP >> 4):0008
10022: mem[0xffff8] = 0x08;
10023: mem[0xffff9] = 0x00;
10024: mem[0xffffa] = ((IRET_TOP >> 4) ) & 0xff;
10025: mem[0xffffb] = ((IRET_TOP >> 4) >> 8) & 0xff;
1.1.1.14 root 10026:
1.1 root 10027: // boot
10028: mem[0xffff0] = 0xf4; // halt
10029: mem[0xffff1] = 0xcd; // int 21h
10030: mem[0xffff2] = 0x21;
10031: mem[0xffff3] = 0xcb; // retf
10032:
10033: // param block
10034: // + 0: param block (22bytes)
10035: // +24: fcb1/2 (20bytes)
10036: // +44: command tail (128bytes)
10037: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
10038: param->env_seg = 0;
10039: param->cmd_line.w.l = 44;
10040: param->cmd_line.w.h = (WORK_TOP >> 4);
10041: param->fcb1.w.l = 24;
10042: param->fcb1.w.h = (WORK_TOP >> 4);
10043: param->fcb2.w.l = 24;
10044: param->fcb2.w.h = (WORK_TOP >> 4);
10045:
10046: memset(mem + WORK_TOP + 24, 0x20, 20);
10047:
10048: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
10049: if(argc > 1) {
10050: sprintf(cmd_line->cmd, " %s", argv[1]);
10051: for(int i = 2; i < argc; i++) {
10052: char tmp[128];
10053: sprintf(tmp, "%s %s", cmd_line->cmd, argv[i]);
10054: strcpy(cmd_line->cmd, tmp);
10055: }
10056: cmd_line->len = (UINT8)strlen(cmd_line->cmd);
10057: } else {
10058: cmd_line->len = 0;
10059: }
10060: cmd_line->cmd[cmd_line->len] = 0x0d;
10061:
10062: // system file table
1.1.1.21 root 10063: *(UINT32 *)(mem + SFT_TOP + 0) = 0xffffffff;
10064: *(UINT16 *)(mem + SFT_TOP + 4) = 20;
1.1 root 10065:
1.1.1.19 root 10066: // disk buffer header (from DOSBox)
10067: *(UINT16 *)(mem + DISK_BUF_TOP + 0) = 0xffff; // forward ptr
10068: *(UINT16 *)(mem + DISK_BUF_TOP + 2) = 0xffff; // backward ptr
10069: *(UINT8 *)(mem + DISK_BUF_TOP + 4) = 0xff; // not in use
10070: *(UINT8 *)(mem + DISK_BUF_TOP + 10) = 0x01; // number of FATs
10071: *(UINT32 *)(mem + DISK_BUF_TOP + 13) = 0xffffffff; // pointer to DPB
10072:
1.1 root 10073: // current directory structure
10074: msdos_cds_update(_getdrive() - 1);
10075:
10076: // fcb table
10077: *(UINT32 *)(mem + FCB_TABLE_TOP + 0) = 0xffffffff;
1.1.1.14 root 10078: *(UINT16 *)(mem + FCB_TABLE_TOP + 4) = 0;
1.1 root 10079:
1.1.1.22 root 10080: // error table
10081: *(UINT8 *)(mem + ERR_TABLE_TOP + 0) = 0xff;
10082: *(UINT8 *)(mem + ERR_TABLE_TOP + 1) = 0x04;
10083: *(UINT8 *)(mem + ERR_TABLE_TOP + 2) = 0x00;
10084: *(UINT8 *)(mem + ERR_TABLE_TOP + 3) = 0x00;
10085:
1.1.1.17 root 10086: // nls stuff
10087: msdos_nls_tables_init();
1.1 root 10088:
10089: // execute command
10090: if(msdos_process_exec(argv[0], param, 0)) {
10091: fatalerror("'%s' not found\n", argv[0]);
10092: }
10093: retval = 0;
10094: return(0);
10095: }
10096:
10097: #define remove_std_file(path) { \
10098: int fd = _open(path, _O_RDONLY | _O_BINARY); \
10099: if(fd != -1) { \
10100: _lseek(fd, 0, SEEK_END); \
10101: int size = _tell(fd); \
10102: _close(fd); \
10103: if(size == 0) { \
10104: remove(path); \
10105: } \
10106: } \
10107: }
10108:
10109: void msdos_finish()
10110: {
10111: for(int i = 0; i < MAX_FILES; i++) {
10112: if(file_handler[i].valid) {
10113: _close(i);
10114: }
10115: }
1.1.1.21 root 10116: #ifdef MAP_AUX_DEVICE_TO_FILE
1.1 root 10117: remove_std_file("stdaux.txt");
1.1.1.21 root 10118: #endif
10119: #ifdef MAP_PRN_DEVICE_TO_FILE
1.1 root 10120: remove_std_file("stdprn.txt");
10121: #endif
10122: msdos_dbcs_table_finish();
10123: }
10124:
10125: /* ----------------------------------------------------------------------------
10126: PC/AT hardware emulation
10127: ---------------------------------------------------------------------------- */
10128:
10129: void hardware_init()
10130: {
1.1.1.3 root 10131: CPU_INIT_CALL(CPU_MODEL);
1.1 root 10132: CPU_RESET_CALL(CPU_MODEL);
1.1.1.14 root 10133: m_IF = 1;
1.1.1.3 root 10134: #if defined(HAS_I386)
1.1 root 10135: cpu_type = (REG32(EDX) >> 8) & 0x0f;
10136: cpu_step = (REG32(EDX) >> 0) & 0x0f;
1.1.1.3 root 10137: #endif
10138: i386_set_a20_line(0);
1.1.1.14 root 10139:
1.1.1.19 root 10140: ems_init();
1.1 root 10141: pic_init();
1.1.1.8 root 10142: #ifdef PIT_ALWAYS_RUNNING
10143: pit_init();
10144: #else
1.1 root 10145: pit_active = 0;
10146: #endif
1.1.1.8 root 10147: cmos_init();
10148: kbd_init();
1.1 root 10149: }
10150:
1.1.1.10 root 10151: void hardware_finish()
10152: {
10153: #if defined(HAS_I386)
10154: vtlb_free(m_vtlb);
10155: #endif
1.1.1.19 root 10156: ems_finish();
1.1.1.10 root 10157: }
10158:
1.1 root 10159: void hardware_run()
10160: {
10161: int ops = 0;
10162:
1.1.1.22 root 10163: #ifdef EXPORT_DEBUG_TO_FILE
10164: fdebug = fopen("debug.log", "w");
10165: #endif
1.1.1.3 root 10166: while(!m_halted) {
1.1.1.22 root 10167: #ifdef ENABLE_DEBUG_DASM
10168: if(dasm > 0) {
1.1 root 10169: char buffer[256];
1.1.1.3 root 10170: #if defined(HAS_I386)
1.1.1.22 root 10171: UINT32 flags = get_flags();
1.1.1.19 root 10172: UINT32 eip = m_eip;
1.1.1.3 root 10173: #else
1.1.1.22 root 10174: UINT32 flags = CompressFlags();
1.1.1.19 root 10175: UINT32 eip = m_pc - SREG_BASE(CS);
1.1.1.3 root 10176: #endif
10177: UINT8 *oprom = mem + SREG_BASE(CS) + eip;
1.1 root 10178:
1.1.1.3 root 10179: #if defined(HAS_I386)
10180: if(m_operand_size) {
1.1 root 10181: CPU_DISASSEMBLE_CALL(x86_32);
1.1.1.3 root 10182: } else
10183: #endif
10184: CPU_DISASSEMBLE_CALL(x86_16);
1.1.1.22 root 10185:
10186: 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",
10187: 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,
10188: #if defined(HAS_I386)
10189: PROTECTED_MODE ? "PE" : "--",
10190: #else
10191: "--",
10192: #endif
10193: (flags & 0x40000) ? 'A' : '-',
10194: (flags & 0x20000) ? 'V' : '-',
10195: (flags & 0x10000) ? 'R' : '-',
10196: (flags & 0x04000) ? 'N' : '-',
10197: (flags & 0x02000) ? '1' : '0',
10198: (flags & 0x01000) ? '1' : '0',
10199: (flags & 0x00800) ? 'O' : '-',
10200: (flags & 0x00400) ? 'D' : '-',
10201: (flags & 0x00200) ? 'I' : '-',
10202: (flags & 0x00100) ? 'T' : '-',
10203: (flags & 0x00080) ? 'S' : '-',
10204: (flags & 0x00040) ? 'Z' : '-',
10205: (flags & 0x00010) ? 'A' : '-',
10206: (flags & 0x00004) ? 'P' : '-',
10207: (flags & 0x00001) ? 'C' : '-');
10208: fprintf(fdebug, "%04X:%04X\t%s\n", SREG(CS), (unsigned)eip, buffer);
10209: dasm--;
1.1 root 10210: }
10211: #endif
1.1.1.3 root 10212: #if defined(HAS_I386)
10213: m_cycles = 1;
1.1 root 10214: CPU_EXECUTE_CALL(i386);
1.1.1.3 root 10215: #else
10216: CPU_EXECUTE_CALL(CPU_MODEL);
10217: #endif
1.1.1.14 root 10218: #if defined(HAS_I386)
10219: if(m_eip != m_prev_eip) {
10220: #else
10221: if(m_pc != m_prevpc) {
10222: #endif
10223: iops++;
10224: }
1.1.1.8 root 10225: if(++ops == 16384) {
1.1 root 10226: hardware_update();
10227: ops = 0;
10228: }
10229: }
1.1.1.22 root 10230: #ifdef EXPORT_DEBUG_TO_FILE
10231: fclose(fdebug);
10232: #endif
1.1 root 10233: }
10234:
10235: void hardware_update()
10236: {
1.1.1.8 root 10237: static UINT32 prev_time = 0;
10238: UINT32 cur_time = timeGetTime();
10239:
10240: if(prev_time != cur_time) {
10241: // update pit and raise irq0
10242: #ifndef PIT_ALWAYS_RUNNING
10243: if(pit_active)
10244: #endif
10245: {
10246: if(pit_run(0, cur_time)) {
10247: pic_req(0, 0, 1);
10248: }
10249: pit_run(1, cur_time);
10250: pit_run(2, cur_time);
10251: }
10252: // check key input and raise irq1
1.1.1.14 root 10253: static UINT32 prev_tick = 0;
10254: UINT32 cur_tick = cur_time / 32;
10255: if(prev_tick != cur_tick) {
10256: // update keyboard flags
10257: UINT8 state;
10258: state = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
10259: state |= (GetAsyncKeyState(VK_CAPITAL) & 0x0001) ? 0x40 : 0;
10260: state |= (GetAsyncKeyState(VK_NUMLOCK) & 0x0001) ? 0x20 : 0;
10261: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
10262: state |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
10263: state |= (GetAsyncKeyState(VK_CONTROL) & 0x8000) ? 0x04 : 0;
10264: state |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
10265: state |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
10266: mem[0x417] = state;
10267: state = (GetAsyncKeyState(VK_INSERT ) & 0x8000) ? 0x80 : 0;
10268: state |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
10269: state |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
10270: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
10271: // state |= (GetAsyncKeyState(VK_PAUSE ) & 0x0001) ? 0x08 : 0;
10272: // state |= (GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x04 : 0;
10273: state |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
10274: state |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
10275: mem[0x418] = state;
10276:
10277: // update keyboard input
1.1.1.8 root 10278: if(check_key_input()) {
10279: pic_req(0, 1, 1);
10280: }
1.1.1.14 root 10281: prev_tick = cur_tick;
1.1.1.8 root 10282: }
1.1.1.19 root 10283: // update daily timer counter
10284: pcbios_update_daily_timer_counter(cur_time);
1.1.1.8 root 10285: prev_time = cur_time;
1.1 root 10286: }
10287: }
10288:
1.1.1.19 root 10289: // ems
10290:
10291: void ems_init()
10292: {
10293: memset(ems_handles, 0, sizeof(ems_handles));
10294: memset(ems_pages, 0, sizeof(ems_pages));
10295: free_ems_pages = MAX_EMS_PAGES;
10296: }
10297:
10298: void ems_finish()
10299: {
10300: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
10301: if(ems_handles[i].buffer) {
10302: free(ems_handles[i].buffer);
10303: ems_handles[i].buffer = NULL;
10304: }
10305: }
10306: }
10307:
10308: void ems_allocate_pages(int handle, int pages)
10309: {
10310: if(pages > 0) {
10311: ems_handles[handle].buffer = (UINT8 *)calloc(1, 0x4000 * pages);
10312: } else {
10313: ems_handles[handle].buffer = NULL;
10314: }
10315: ems_handles[handle].pages = pages;
10316: ems_handles[handle].allocated = true;
10317: free_ems_pages -= pages;
10318: }
10319:
10320: void ems_reallocate_pages(int handle, int pages)
10321: {
10322: if(ems_handles[handle].allocated) {
10323: if(ems_handles[handle].pages != pages) {
10324: UINT8 *new_buffer = NULL;
10325:
10326: if(pages > 0) {
10327: new_buffer = (UINT8 *)calloc(1, 0x4000 * pages);
10328: }
10329: if(ems_handles[handle].buffer) {
10330: if(new_buffer) {
10331: if(pages > ems_handles[handle].pages) {
10332: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * ems_handles[handle].pages);
10333: } else {
10334: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * pages);
10335: }
10336: }
10337: free(ems_handles[handle].buffer);
10338: ems_handles[handle].buffer = NULL;
10339: }
10340: free_ems_pages += ems_handles[handle].pages;
10341:
10342: ems_handles[handle].buffer = new_buffer;
10343: ems_handles[handle].pages = pages;
10344: free_ems_pages -= pages;
10345: }
10346: } else {
10347: ems_allocate_pages(handle, pages);
10348: }
10349: }
10350:
10351: void ems_release_pages(int handle)
10352: {
10353: if(ems_handles[handle].allocated) {
10354: if(ems_handles[handle].buffer) {
10355: free(ems_handles[handle].buffer);
10356: ems_handles[handle].buffer = NULL;
10357: }
10358: free_ems_pages += ems_handles[handle].pages;
10359: ems_handles[handle].allocated = false;
10360: }
10361: }
10362:
10363: void ems_map_page(int physical, int handle, int logical)
10364: {
10365: if(ems_pages[physical].mapped) {
10366: if(ems_pages[physical].handle == handle && ems_pages[physical].page == logical) {
10367: return;
10368: }
10369: ems_unmap_page(physical);
10370: }
10371: if(ems_handles[handle].allocated && ems_handles[handle].buffer && logical < ems_handles[handle].pages) {
10372: memcpy(mem + EMS_TOP + 0x4000 * physical, ems_handles[handle].buffer + 0x4000 * logical, 0x4000);
10373: }
10374: ems_pages[physical].handle = handle;
10375: ems_pages[physical].page = logical;
10376: ems_pages[physical].mapped = true;
10377: }
10378:
10379: void ems_unmap_page(int physical)
10380: {
10381: if(ems_pages[physical].mapped) {
10382: int handle = ems_pages[physical].handle;
10383: int logical = ems_pages[physical].page;
10384:
10385: if(ems_handles[handle].allocated && ems_handles[handle].buffer && logical < ems_handles[handle].pages) {
10386: memcpy(ems_handles[handle].buffer + 0x4000 * logical, mem + EMS_TOP + 0x4000 * physical, 0x4000);
10387: }
10388: ems_pages[physical].mapped = false;
10389: }
10390: }
10391:
1.1 root 10392: // pic
10393:
10394: void pic_init()
10395: {
1.1.1.8 root 10396: memset(pic, 0, sizeof(pic));
10397: pic[0].imr = pic[1].imr = 0xff;
1.1 root 10398:
10399: // from bochs bios
10400: pic_write(0, 0, 0x11); // icw1 = 11h
10401: pic_write(0, 1, 0x08); // icw2 = 08h
10402: pic_write(0, 1, 0x04); // icw3 = 04h
10403: pic_write(0, 1, 0x01); // icw4 = 01h
10404: pic_write(0, 1, 0xb8); // ocw1 = b8h
10405: pic_write(1, 0, 0x11); // icw1 = 11h
10406: pic_write(1, 1, 0x70); // icw2 = 70h
10407: pic_write(1, 1, 0x02); // icw3 = 02h
10408: pic_write(1, 1, 0x01); // icw4 = 01h
10409: }
10410:
10411: void pic_write(int c, UINT32 addr, UINT8 data)
10412: {
10413: if(addr & 1) {
10414: if(pic[c].icw2_r) {
10415: // icw2
10416: pic[c].icw2 = data;
10417: pic[c].icw2_r = 0;
10418: } else if(pic[c].icw3_r) {
10419: // icw3
10420: pic[c].icw3 = data;
10421: pic[c].icw3_r = 0;
10422: } else if(pic[c].icw4_r) {
10423: // icw4
10424: pic[c].icw4 = data;
10425: pic[c].icw4_r = 0;
10426: } else {
10427: // ocw1
10428: pic[c].imr = data;
10429: }
10430: } else {
10431: if(data & 0x10) {
10432: // icw1
10433: pic[c].icw1 = data;
10434: pic[c].icw2_r = 1;
10435: pic[c].icw3_r = (data & 2) ? 0 : 1;
10436: pic[c].icw4_r = data & 1;
10437: pic[c].irr = 0;
10438: pic[c].isr = 0;
10439: pic[c].imr = 0;
10440: pic[c].prio = 0;
10441: if(!(pic[c].icw1 & 1)) {
10442: pic[c].icw4 = 0;
10443: }
10444: pic[c].ocw3 = 0;
10445: } else if(data & 8) {
10446: // ocw3
10447: if(!(data & 2)) {
10448: data = (data & ~1) | (pic[c].ocw3 & 1);
10449: }
10450: if(!(data & 0x40)) {
10451: data = (data & ~0x20) | (pic[c].ocw3 & 0x20);
10452: }
10453: pic[c].ocw3 = data;
10454: } else {
10455: // ocw2
10456: int level = 0;
10457: if(data & 0x40) {
10458: level = data & 7;
10459: } else {
10460: if(!pic[c].isr) {
10461: return;
10462: }
10463: level = pic[c].prio;
10464: while(!(pic[c].isr & (1 << level))) {
10465: level = (level + 1) & 7;
10466: }
10467: }
10468: if(data & 0x80) {
10469: pic[c].prio = (level + 1) & 7;
10470: }
10471: if(data & 0x20) {
10472: pic[c].isr &= ~(1 << level);
10473: }
10474: }
10475: }
10476: pic_update();
10477: }
10478:
10479: UINT8 pic_read(int c, UINT32 addr)
10480: {
10481: if(addr & 1) {
10482: return(pic[c].imr);
10483: } else {
10484: // polling mode is not supported...
10485: //if(pic[c].ocw3 & 4) {
10486: // return ???;
10487: //}
10488: if(pic[c].ocw3 & 1) {
10489: return(pic[c].isr);
10490: } else {
10491: return(pic[c].irr);
10492: }
10493: }
10494: }
10495:
10496: void pic_req(int c, int level, int signal)
10497: {
10498: if(signal) {
10499: pic[c].irr |= (1 << level);
10500: } else {
10501: pic[c].irr &= ~(1 << level);
10502: }
10503: pic_update();
10504: }
10505:
10506: int pic_ack()
10507: {
10508: // ack (INTA=L)
10509: pic[pic_req_chip].isr |= pic_req_bit;
10510: pic[pic_req_chip].irr &= ~pic_req_bit;
10511: if(pic_req_chip > 0) {
10512: // update isr and irr of master
10513: UINT8 slave = 1 << (pic[pic_req_chip].icw3 & 7);
10514: pic[pic_req_chip - 1].isr |= slave;
10515: pic[pic_req_chip - 1].irr &= ~slave;
10516: }
10517: //if(pic[pic_req_chip].icw4 & 1) {
10518: // 8086 mode
10519: int vector = (pic[pic_req_chip].icw2 & 0xf8) | pic_req_level;
10520: //} else {
10521: // // 8080 mode
10522: // UINT16 addr = (UINT16)pic[pic_req_chip].icw2 << 8;
10523: // if(pic[pic_req_chip].icw1 & 4) {
10524: // addr |= (pic[pic_req_chip].icw1 & 0xe0) | (pic_req_level << 2);
10525: // } else {
10526: // addr |= (pic[pic_req_chip].icw1 & 0xc0) | (pic_req_level << 3);
10527: // }
10528: // vector = 0xcd | (addr << 8);
10529: //}
10530: if(pic[pic_req_chip].icw4 & 2) {
10531: // auto eoi
10532: pic[pic_req_chip].isr &= ~pic_req_bit;
10533: }
10534: return(vector);
10535: }
10536:
10537: void pic_update()
10538: {
10539: for(int c = 0; c < 2; c++) {
10540: UINT8 irr = pic[c].irr;
10541: if(c + 1 < 2) {
10542: // this is master
10543: if(pic[c + 1].irr & (~pic[c + 1].imr)) {
10544: // request from slave
10545: irr |= 1 << (pic[c + 1].icw3 & 7);
10546: }
10547: }
10548: irr &= (~pic[c].imr);
10549: if(!irr) {
10550: break;
10551: }
10552: if(!(pic[c].ocw3 & 0x20)) {
10553: irr |= pic[c].isr;
10554: }
10555: int level = pic[c].prio;
10556: UINT8 bit = 1 << level;
10557: while(!(irr & bit)) {
10558: level = (level + 1) & 7;
10559: bit = 1 << level;
10560: }
10561: if((c + 1 < 2) && (pic[c].icw3 & bit)) {
10562: // check slave
10563: continue;
10564: }
10565: if(pic[c].isr & bit) {
10566: break;
10567: }
10568: // interrupt request
10569: pic_req_chip = c;
10570: pic_req_level = level;
10571: pic_req_bit = bit;
1.1.1.3 root 10572: i386_set_irq_line(INPUT_LINE_IRQ, HOLD_LINE);
1.1 root 10573: return;
10574: }
1.1.1.3 root 10575: i386_set_irq_line(INPUT_LINE_IRQ, CLEAR_LINE);
1.1.1.2 root 10576: }
1.1 root 10577:
10578: // pit
10579:
1.1.1.22 root 10580: #define PIT_FREQ 1193182ULL
1.1 root 10581: #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)
10582:
10583: void pit_init()
10584: {
1.1.1.8 root 10585: memset(pit, 0, sizeof(pit));
1.1 root 10586: for(int ch = 0; ch < 3; ch++) {
10587: pit[ch].count = 0x10000;
10588: pit[ch].ctrl_reg = 0x34;
10589: pit[ch].mode = 3;
10590: }
10591:
10592: // from bochs bios
10593: pit_write(3, 0x34);
10594: pit_write(0, 0x00);
10595: pit_write(0, 0x00);
10596: }
10597:
10598: void pit_write(int ch, UINT8 val)
10599: {
1.1.1.8 root 10600: #ifndef PIT_ALWAYS_RUNNING
1.1 root 10601: if(!pit_active) {
10602: pit_active = 1;
10603: pit_init();
10604: }
1.1.1.8 root 10605: #endif
1.1 root 10606: switch(ch) {
10607: case 0:
10608: case 1:
10609: case 2:
10610: // write count register
10611: if(!pit[ch].low_write && !pit[ch].high_write) {
10612: if(pit[ch].ctrl_reg & 0x10) {
10613: pit[ch].low_write = 1;
10614: }
10615: if(pit[ch].ctrl_reg & 0x20) {
10616: pit[ch].high_write = 1;
10617: }
10618: }
10619: if(pit[ch].low_write) {
10620: pit[ch].count_reg = val;
10621: pit[ch].low_write = 0;
10622: } else if(pit[ch].high_write) {
10623: if((pit[ch].ctrl_reg & 0x30) == 0x20) {
10624: pit[ch].count_reg = val << 8;
10625: } else {
10626: pit[ch].count_reg |= val << 8;
10627: }
10628: pit[ch].high_write = 0;
10629: }
10630: // start count
1.1.1.8 root 10631: if(!pit[ch].low_write && !pit[ch].high_write) {
10632: if(pit[ch].mode == 0 || pit[ch].mode == 4 || pit[ch].prev_time == 0) {
10633: pit[ch].count = PIT_COUNT_VALUE(ch);
10634: pit[ch].prev_time = timeGetTime();
10635: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 10636: }
10637: }
10638: break;
10639: case 3: // ctrl reg
10640: if((val & 0xc0) == 0xc0) {
10641: // i8254 read-back command
10642: for(ch = 0; ch < 3; ch++) {
10643: if(!(val & 0x10) && !pit[ch].status_latched) {
10644: pit[ch].status = pit[ch].ctrl_reg & 0x3f;
10645: pit[ch].status_latched = 1;
10646: }
10647: if(!(val & 0x20) && !pit[ch].count_latched) {
10648: pit_latch_count(ch);
10649: }
10650: }
10651: break;
10652: }
10653: ch = (val >> 6) & 3;
10654: if(val & 0x30) {
10655: static int modes[8] = {0, 1, 2, 3, 4, 5, 2, 3};
10656: pit[ch].mode = modes[(val >> 1) & 7];
10657: pit[ch].count_latched = 0;
10658: pit[ch].low_read = pit[ch].high_read = 0;
10659: pit[ch].low_write = pit[ch].high_write = 0;
10660: pit[ch].ctrl_reg = val;
10661: // stop count
1.1.1.8 root 10662: pit[ch].prev_time = pit[ch].expired_time = 0;
1.1 root 10663: pit[ch].count_reg = 0;
10664: } else if(!pit[ch].count_latched) {
10665: pit_latch_count(ch);
10666: }
10667: break;
10668: }
10669: }
10670:
10671: UINT8 pit_read(int ch)
10672: {
1.1.1.8 root 10673: #ifndef PIT_ALWAYS_RUNNING
1.1 root 10674: if(!pit_active) {
10675: pit_active = 1;
10676: pit_init();
10677: }
1.1.1.8 root 10678: #endif
1.1 root 10679: switch(ch) {
10680: case 0:
10681: case 1:
10682: case 2:
10683: if(pit[ch].status_latched) {
10684: pit[ch].status_latched = 0;
10685: return(pit[ch].status);
10686: }
10687: // if not latched, through current count
10688: if(!pit[ch].count_latched) {
10689: if(!pit[ch].low_read && !pit[ch].high_read) {
10690: pit_latch_count(ch);
10691: }
10692: }
10693: // return latched count
10694: if(pit[ch].low_read) {
10695: pit[ch].low_read = 0;
10696: if(!pit[ch].high_read) {
10697: pit[ch].count_latched = 0;
10698: }
10699: return(pit[ch].latch & 0xff);
10700: } else if(pit[ch].high_read) {
10701: pit[ch].high_read = 0;
10702: pit[ch].count_latched = 0;
10703: return((pit[ch].latch >> 8) & 0xff);
10704: }
10705: }
10706: return(0xff);
10707: }
10708:
1.1.1.8 root 10709: int pit_run(int ch, UINT32 cur_time)
1.1 root 10710: {
1.1.1.8 root 10711: if(pit[ch].expired_time != 0 && cur_time >= pit[ch].expired_time) {
1.1 root 10712: pit[ch].count = PIT_COUNT_VALUE(ch);
1.1.1.8 root 10713: pit[ch].prev_time = pit[ch].expired_time;
10714: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
10715: if(cur_time >= pit[ch].expired_time) {
10716: pit[ch].prev_time = cur_time;
10717: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 10718: }
1.1.1.8 root 10719: return(1);
1.1 root 10720: }
1.1.1.8 root 10721: return(0);
1.1 root 10722: }
10723:
10724: void pit_latch_count(int ch)
10725: {
1.1.1.8 root 10726: UINT32 cur_time = timeGetTime();
10727:
10728: if(pit[ch].expired_time != 0) {
10729: pit_run(ch, cur_time);
10730: UINT32 tmp = (pit[ch].count * (pit[ch].expired_time - cur_time)) / (pit[ch].expired_time - pit[ch].prev_time);
10731: pit[ch].latch = (tmp != 0) ? (UINT16)tmp : 1;
10732: } else {
10733: pit[ch].latch = (UINT16)pit[ch].count;
1.1 root 10734: }
10735: pit[ch].count_latched = 1;
10736: if((pit[ch].ctrl_reg & 0x30) == 0x10) {
10737: // lower byte
10738: pit[ch].low_read = 1;
10739: pit[ch].high_read = 0;
10740: } else if((pit[ch].ctrl_reg & 0x30) == 0x20) {
10741: // upper byte
10742: pit[ch].low_read = 0;
10743: pit[ch].high_read = 1;
10744: } else {
10745: // lower -> upper
1.1.1.14 root 10746: pit[ch].low_read = pit[ch].high_read = 1;
1.1 root 10747: }
10748: }
10749:
1.1.1.8 root 10750: int pit_get_expired_time(int ch)
1.1 root 10751: {
1.1.1.22 root 10752: pit[ch].accum += 1024ULL * 1000ULL * (UINT64)pit[ch].count / PIT_FREQ;
10753: UINT64 val = pit[ch].accum >> 10;
10754: pit[ch].accum -= val << 10;
10755: return((val != 0) ? val : 1);
1.1.1.8 root 10756: }
10757:
10758: // cmos
10759:
10760: void cmos_init()
10761: {
10762: memset(cmos, 0, sizeof(cmos));
10763: cmos_addr = 0;
1.1 root 10764:
1.1.1.8 root 10765: // from DOSBox
10766: cmos_write(0x0a, 0x26);
10767: cmos_write(0x0b, 0x02);
10768: cmos_write(0x0d, 0x80);
1.1 root 10769: }
10770:
1.1.1.8 root 10771: void cmos_write(int addr, UINT8 val)
1.1 root 10772: {
1.1.1.8 root 10773: cmos[addr & 0x7f] = val;
10774: }
10775:
10776: #define CMOS_GET_TIME() { \
10777: UINT32 cur_sec = timeGetTime() / 1000 ; \
10778: if(prev_sec != cur_sec) { \
10779: GetLocalTime(&time); \
10780: prev_sec = cur_sec; \
10781: } \
1.1 root 10782: }
1.1.1.8 root 10783: #define CMOS_BCD(v) ((cmos[0x0b] & 4) ? (v) : to_bcd(v))
1.1 root 10784:
1.1.1.8 root 10785: UINT8 cmos_read(int addr)
1.1 root 10786: {
1.1.1.8 root 10787: static SYSTEMTIME time;
10788: static UINT32 prev_sec = 0;
1.1 root 10789:
1.1.1.8 root 10790: switch(addr & 0x7f) {
10791: case 0x00: CMOS_GET_TIME(); return(CMOS_BCD(time.wSecond));
10792: case 0x02: CMOS_GET_TIME(); return(CMOS_BCD(time.wMinute));
10793: case 0x04: CMOS_GET_TIME(); return(CMOS_BCD(time.wHour));
10794: case 0x06: CMOS_GET_TIME(); return(time.wDayOfWeek + 1);
10795: case 0x07: CMOS_GET_TIME(); return(CMOS_BCD(time.wDay));
10796: case 0x08: CMOS_GET_TIME(); return(CMOS_BCD(time.wMonth));
10797: case 0x09: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear));
10798: // case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 2 ? 0x80 : 0)); // 2msec
10799: case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 20 ? 0x80 : 0)); // precision of timeGetTime() may not be 1msec
10800: case 0x15: return((MEMORY_END >> 10) & 0xff);
10801: case 0x16: return((MEMORY_END >> 18) & 0xff);
10802: case 0x17: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
10803: case 0x18: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
10804: case 0x30: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
10805: case 0x31: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
10806: case 0x32: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear / 100));
1.1 root 10807: }
1.1.1.8 root 10808: return(cmos[addr & 0x7f]);
1.1 root 10809: }
10810:
1.1.1.7 root 10811: // kbd (a20)
10812:
10813: void kbd_init()
10814: {
1.1.1.8 root 10815: kbd_data = kbd_command = 0;
1.1.1.7 root 10816: kbd_status = 0x18;
10817: }
10818:
10819: UINT8 kbd_read_data()
10820: {
1.1.1.8 root 10821: kbd_status &= ~1;
1.1.1.7 root 10822: return(kbd_data);
10823: }
10824:
10825: void kbd_write_data(UINT8 val)
10826: {
10827: switch(kbd_command) {
10828: case 0xd1:
10829: i386_set_a20_line((val >> 1) & 1);
10830: break;
10831: }
10832: kbd_command = 0;
1.1.1.8 root 10833: kbd_status &= ~8;
1.1.1.7 root 10834: }
10835:
10836: UINT8 kbd_read_status()
10837: {
10838: return(kbd_status);
10839: }
10840:
10841: void kbd_write_command(UINT8 val)
10842: {
10843: switch(val) {
10844: case 0xd0:
10845: kbd_data = ((m_a20_mask >> 19) & 2) | 1;
1.1.1.8 root 10846: kbd_status |= 1;
1.1.1.7 root 10847: break;
10848: case 0xdd:
10849: i386_set_a20_line(0);
10850: break;
10851: case 0xdf:
10852: i386_set_a20_line(1);
10853: break;
10854: case 0xf0:
10855: case 0xf1:
10856: case 0xf2:
10857: case 0xf3:
10858: case 0xf4:
10859: case 0xf5:
10860: case 0xf6:
10861: case 0xf7:
10862: case 0xf8:
10863: case 0xf9:
10864: case 0xfa:
10865: case 0xfb:
10866: case 0xfc:
10867: case 0xfd:
10868: case 0xfe:
10869: case 0xff:
10870: if(!(val & 1)) {
1.1.1.8 root 10871: if((cmos[0x0f] & 0x7f) == 5) {
1.1.1.7 root 10872: // reset pic
10873: pic_init();
10874: pic[0].irr = pic[1].irr = 0x00;
10875: pic[0].imr = pic[1].imr = 0xff;
10876: }
10877: CPU_RESET_CALL(CPU_MODEL);
10878: i386_jmp_far(0x40, 0x67);
10879: }
10880: i386_set_a20_line((val >> 1) & 1);
10881: break;
10882: }
10883: kbd_command = val;
1.1.1.8 root 10884: kbd_status |= 8;
1.1.1.7 root 10885: }
10886:
1.1.1.9 root 10887: // vga
10888:
10889: UINT8 vga_read_status()
10890: {
10891: // 60hz
10892: static const int period[3] = {16, 17, 17};
10893: static int index = 0;
10894: UINT32 time = timeGetTime() % period[index];
10895:
10896: index = (index + 1) % 3;
1.1.1.14 root 10897: return((time < 4 ? 0x08 : 0) | (time == 0 ? 0 : 0x01));
1.1.1.9 root 10898: }
10899:
1.1 root 10900: // i/o bus
10901:
10902: UINT8 read_io_byte(offs_t addr)
10903: {
10904: switch(addr) {
10905: case 0x20:
10906: case 0x21:
10907: return(pic_read(0, addr));
10908: case 0x40:
10909: case 0x41:
10910: case 0x42:
10911: case 0x43:
10912: return(pit_read(addr & 0x03));
1.1.1.7 root 10913: case 0x60:
10914: return(kbd_read_data());
1.1.1.9 root 10915: case 0x61:
10916: return(system_port);
1.1.1.7 root 10917: case 0x64:
10918: return(kbd_read_status());
1.1 root 10919: case 0x71:
1.1.1.8 root 10920: return(cmos_read(cmos_addr));
1.1 root 10921: case 0x92:
1.1.1.3 root 10922: return((m_a20_mask >> 19) & 2);
1.1 root 10923: case 0xa0:
10924: case 0xa1:
10925: return(pic_read(1, addr));
1.1.1.9 root 10926: case 0x3ba:
10927: case 0x3da:
10928: return(vga_read_status());
1.1 root 10929: default:
10930: // error("inb %4x\n", addr);
10931: break;
10932: }
10933: return(0xff);
10934: }
10935:
10936: UINT16 read_io_word(offs_t addr)
10937: {
10938: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8));
10939: }
10940:
10941: UINT32 read_io_dword(offs_t addr)
10942: {
10943: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8) | (read_io_byte(addr + 2) << 16) | (read_io_byte(addr + 3) << 24));
10944: }
10945:
10946: void write_io_byte(offs_t addr, UINT8 val)
10947: {
10948: switch(addr) {
10949: case 0x20:
10950: case 0x21:
10951: pic_write(0, addr, val);
10952: break;
10953: case 0x40:
10954: case 0x41:
10955: case 0x42:
10956: case 0x43:
10957: pit_write(addr & 0x03, val);
10958: break;
1.1.1.7 root 10959: case 0x60:
10960: kbd_write_data(val);
10961: break;
1.1.1.9 root 10962: case 0x61:
10963: if((system_port & 3) != 3 && (val & 3) == 3) {
10964: // beep on
10965: // MessageBeep(-1);
10966: } else if((system_port & 3) == 3 && (val & 3) != 3) {
10967: // beep off
10968: }
10969: system_port = val;
10970: break;
1.1 root 10971: case 0x64:
1.1.1.7 root 10972: kbd_write_command(val);
1.1 root 10973: break;
10974: case 0x70:
10975: cmos_addr = val;
10976: break;
10977: case 0x71:
1.1.1.8 root 10978: cmos_write(cmos_addr, val);
1.1 root 10979: break;
10980: case 0x92:
1.1.1.7 root 10981: i386_set_a20_line((val >> 1) & 1);
1.1 root 10982: break;
10983: case 0xa0:
10984: case 0xa1:
10985: pic_write(1, addr, val);
10986: break;
10987: default:
10988: // error("outb %4x,%2x\n", addr, val);
10989: break;
10990: }
10991: }
10992:
10993: void write_io_word(offs_t addr, UINT16 val)
10994: {
10995: write_io_byte(addr + 0, (val >> 0) & 0xff);
10996: write_io_byte(addr + 1, (val >> 8) & 0xff);
10997: }
10998:
10999: void write_io_dword(offs_t addr, UINT32 val)
11000: {
11001: write_io_byte(addr + 0, (val >> 0) & 0xff);
11002: write_io_byte(addr + 1, (val >> 8) & 0xff);
11003: write_io_byte(addr + 2, (val >> 16) & 0xff);
11004: write_io_byte(addr + 3, (val >> 24) & 0xff);
11005: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.