|
|
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
1.1.1.25 root 23: #define ENABLE_DEBUG_IOPORT
1.1.1.22 root 24:
25: #ifdef EXPORT_DEBUG_TO_FILE
26: FILE* fdebug = NULL;
27: #else
28: #define fdebug stderr
29: #endif
30: #ifdef ENABLE_DEBUG_UNIMPLEMENTED
31: #define unimplemented_10h fatalerror
1.1.1.25 root 32: #define unimplemented_14h fatalerror
1.1.1.22 root 33: #define unimplemented_15h fatalerror
34: #define unimplemented_16h fatalerror
35: #define unimplemented_1ah fatalerror
36: #define unimplemented_21h fatalerror
37: #define unimplemented_2fh fatalerror
1.1.1.24 root 38: #define unimplemented_33h fatalerror
1.1.1.22 root 39: #define unimplemented_67h fatalerror
40: #define unimplemented_xms fatalerror
41: #endif
42: #endif
43: #ifndef unimplemented_10h
44: #define unimplemented_10h nolog
45: #endif
1.1.1.25 root 46: #ifndef unimplemented_14h
47: #define unimplemented_14h nolog
48: #endif
1.1.1.22 root 49: #ifndef unimplemented_15h
50: #define unimplemented_15h nolog
51: #endif
52: #ifndef unimplemented_16h
53: #define unimplemented_16h nolog
54: #endif
55: #ifndef unimplemented_1ah
56: #define unimplemented_1ah nolog
57: #endif
58: #ifndef unimplemented_21h
59: #define unimplemented_21h nolog
60: #endif
61: #ifndef unimplemented_2fh
62: #define unimplemented_2fh nolog
63: #endif
1.1.1.24 root 64: #ifndef unimplemented_33h
65: #define unimplemented_33h nolog
66: #endif
1.1.1.22 root 67: #ifndef unimplemented_67h
68: #define unimplemented_67h nolog
69: #endif
70: #ifndef unimplemented_xms
71: #define unimplemented_xms nolog
72: #endif
73:
74: #define my_strchr(str, chr) (char *)_mbschr((unsigned char *)(str), (unsigned int)(chr))
75: #define my_strtok(tok, del) (char *)_mbstok((unsigned char *)(tok), (const unsigned char *)(del))
76: #define my_strupr(str) (char *)_mbsupr((unsigned char *)(str))
1.1 root 77:
1.1.1.12 root 78: #if defined(__MINGW32__)
79: extern "C" int _CRT_glob = 0;
80: #endif
81:
82: /*
83: kludge for "more-standardized" C++
84: */
85: #if !defined(_MSC_VER)
86: inline int kludge_min(int a, int b) { return (a<b ? a:b); }
87: inline int kludge_max(int a, int b) { return (a>b ? a:b); }
88: #define min(a,b) kludge_min(a,b)
89: #define max(a,b) kludge_max(a,b)
1.1.1.14 root 90: #elif _MSC_VER >= 1400
91: void ignore_invalid_parameters(const wchar_t *, const wchar_t *, const wchar_t *, unsigned int, uintptr_t)
92: {
93: }
94: #endif
95:
96: #define USE_THREAD
97:
98: #ifdef USE_THREAD
99: static CRITICAL_SECTION vram_crit_sect;
100: #else
101: #define EnterCriticalSection(x)
102: #define LeaveCriticalSection(x)
103: #define vram_flush()
1.1.1.12 root 104: #endif
105:
1.1.1.14 root 106: #define VIDEO_REGEN *(UINT16 *)(mem + 0x44c)
107: #define SCR_BUF(y,x) scr_buf[(y) * scr_buf_size.X + (x)]
108:
109: void change_console_size(int width, int height);
110: void clear_scr_buffer(WORD attr);
111:
112: static UINT32 vram_length_char = 0, vram_length_attr = 0;
113: static UINT32 vram_last_length_char = 0, vram_last_length_attr = 0;
114: static COORD vram_coord_char, vram_coord_attr;
115:
116: bool ignore_illegal_insn = false;
117: bool limit_max_memory = false;
118: bool no_windows = false;
119: //bool ctrl_break = false;
120: bool stay_busy = false;
121: UINT32 iops = 0;
1.1.1.19 root 122: bool support_ems = false;
123: #ifdef SUPPORT_XMS
124: bool support_xms = false;
125: #endif
1.1.1.26 root 126: int sio_port_number[2] = {0, 0};
1.1.1.14 root 127:
128: BOOL is_vista_or_later;
129:
130: inline void maybe_idle()
131: {
132: // if it appears to be in a tight loop, assume waiting for input
133: // allow for one updated video character, for a spinning cursor
134: if(!stay_busy && iops < 1000 && vram_length_char <= 1 && vram_length_attr <= 1) {
135: Sleep(10);
136: }
137: iops = 0;
138: }
1.1.1.12 root 139:
1.1 root 140: /* ----------------------------------------------------------------------------
1.1.1.3 root 141: MAME i86/i386
1.1 root 142: ---------------------------------------------------------------------------- */
143:
1.1.1.10 root 144: #ifndef __BIG_ENDIAN__
1.1 root 145: #define LSB_FIRST
1.1.1.10 root 146: #endif
1.1 root 147:
148: #ifndef INLINE
149: #define INLINE inline
150: #endif
151: #define U64(v) UINT64(v)
152:
153: //#define logerror(...) fprintf(stderr, __VA_ARGS__)
154: #define logerror(...)
155: //#define popmessage(...) fprintf(stderr, __VA_ARGS__)
156: #define popmessage(...)
157:
158: /*****************************************************************************/
1.1.1.10 root 159: /* src/emu/devcpu.h */
160:
161: // CPU interface functions
162: #define CPU_INIT_NAME(name) cpu_init_##name
163: #define CPU_INIT(name) void CPU_INIT_NAME(name)()
164: #define CPU_INIT_CALL(name) CPU_INIT_NAME(name)()
165:
166: #define CPU_RESET_NAME(name) cpu_reset_##name
167: #define CPU_RESET(name) void CPU_RESET_NAME(name)()
168: #define CPU_RESET_CALL(name) CPU_RESET_NAME(name)()
169:
170: #define CPU_EXECUTE_NAME(name) cpu_execute_##name
171: #define CPU_EXECUTE(name) void CPU_EXECUTE_NAME(name)()
172: #define CPU_EXECUTE_CALL(name) CPU_EXECUTE_NAME(name)()
173:
174: #define CPU_TRANSLATE_NAME(name) cpu_translate_##name
175: #define CPU_TRANSLATE(name) int CPU_TRANSLATE_NAME(name)(address_spacenum space, int intention, offs_t *address)
176: #define CPU_TRANSLATE_CALL(name) CPU_TRANSLATE_NAME(name)(space, intention, address)
177:
178: #define CPU_DISASSEMBLE_NAME(name) cpu_disassemble_##name
179: #define CPU_DISASSEMBLE(name) int CPU_DISASSEMBLE_NAME(name)(char *buffer, offs_t eip, const UINT8 *oprom)
180: #define CPU_DISASSEMBLE_CALL(name) CPU_DISASSEMBLE_NAME(name)(buffer, eip, oprom)
181:
1.1.1.14 root 182: #define CPU_MODEL_STR(name) #name
183: #define CPU_MODEL_NAME(name) CPU_MODEL_STR(name)
184:
1.1.1.10 root 185: /*****************************************************************************/
186: /* src/emu/didisasm.h */
187:
188: // Disassembler constants
189: const UINT32 DASMFLAG_SUPPORTED = 0x80000000; // are disassembly flags supported?
190: const UINT32 DASMFLAG_STEP_OUT = 0x40000000; // this instruction should be the end of a step out sequence
191: const UINT32 DASMFLAG_STEP_OVER = 0x20000000; // this instruction should be stepped over by setting a breakpoint afterwards
192: const UINT32 DASMFLAG_OVERINSTMASK = 0x18000000; // number of extra instructions to skip when stepping over
193: const UINT32 DASMFLAG_OVERINSTSHIFT = 27; // bits to shift after masking to get the value
194: const UINT32 DASMFLAG_LENGTHMASK = 0x0000ffff; // the low 16-bits contain the actual length
195:
196: /*****************************************************************************/
1.1 root 197: /* src/emu/diexec.h */
198:
199: // I/O line states
200: enum line_state
201: {
202: CLEAR_LINE = 0, // clear (a fired or held) line
203: ASSERT_LINE, // assert an interrupt immediately
204: HOLD_LINE, // hold interrupt line until acknowledged
205: PULSE_LINE // pulse interrupt line instantaneously (only for NMI, RESET)
206: };
207:
208: // I/O line definitions
209: enum
210: {
211: INPUT_LINE_IRQ = 0,
212: INPUT_LINE_NMI
213: };
214:
215: /*****************************************************************************/
1.1.1.10 root 216: /* src/emu/dimemory.h */
1.1 root 217:
1.1.1.10 root 218: // Translation intentions
219: const int TRANSLATE_TYPE_MASK = 0x03; // read write or fetch
220: const int TRANSLATE_USER_MASK = 0x04; // user mode or fully privileged
221: const int TRANSLATE_DEBUG_MASK = 0x08; // debug mode (no side effects)
222:
223: const int TRANSLATE_READ = 0; // translate for read
224: const int TRANSLATE_WRITE = 1; // translate for write
225: const int TRANSLATE_FETCH = 2; // translate for instruction fetch
226: const int TRANSLATE_READ_USER = (TRANSLATE_READ | TRANSLATE_USER_MASK);
227: const int TRANSLATE_WRITE_USER = (TRANSLATE_WRITE | TRANSLATE_USER_MASK);
228: const int TRANSLATE_FETCH_USER = (TRANSLATE_FETCH | TRANSLATE_USER_MASK);
229: const int TRANSLATE_READ_DEBUG = (TRANSLATE_READ | TRANSLATE_DEBUG_MASK);
230: const int TRANSLATE_WRITE_DEBUG = (TRANSLATE_WRITE | TRANSLATE_DEBUG_MASK);
231: const int TRANSLATE_FETCH_DEBUG = (TRANSLATE_FETCH | TRANSLATE_DEBUG_MASK);
1.1 root 232:
1.1.1.10 root 233: /*****************************************************************************/
234: /* src/emu/emucore.h */
1.1 root 235:
1.1.1.10 root 236: // constants for expression endianness
237: enum endianness_t
238: {
239: ENDIANNESS_LITTLE,
240: ENDIANNESS_BIG
241: };
1.1 root 242:
1.1.1.10 root 243: // declare native endianness to be one or the other
244: #ifdef LSB_FIRST
245: const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_LITTLE;
246: #else
247: const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_BIG;
248: #endif
249:
250: // endian-based value: first value is if 'endian' is little-endian, second is if 'endian' is big-endian
251: #define ENDIAN_VALUE_LE_BE(endian,leval,beval) (((endian) == ENDIANNESS_LITTLE) ? (leval) : (beval))
252:
253: // endian-based value: first value is if native endianness is little-endian, second is if native is big-endian
254: #define NATIVE_ENDIAN_VALUE_LE_BE(leval,beval) ENDIAN_VALUE_LE_BE(ENDIANNESS_NATIVE, leval, beval)
255:
256: // endian-based value: first value is if 'endian' matches native, second is if 'endian' doesn't match native
257: #define ENDIAN_VALUE_NE_NNE(endian,leval,beval) (((endian) == ENDIANNESS_NATIVE) ? (neval) : (nneval))
1.1 root 258:
259: /*****************************************************************************/
260: /* src/emu/memory.h */
261:
1.1.1.10 root 262: // address spaces
263: enum address_spacenum
264: {
265: AS_0, // first address space
266: AS_1, // second address space
267: AS_2, // third address space
268: AS_3, // fourth address space
269: ADDRESS_SPACES, // maximum number of address spaces
270:
271: // alternate address space names for common use
272: AS_PROGRAM = AS_0, // program address space
273: AS_DATA = AS_1, // data address space
274: AS_IO = AS_2 // I/O address space
275: };
276:
1.1 root 277: // offsets and addresses are 32-bit (for now...)
278: typedef UINT32 offs_t;
279:
280: // read accessors
281: UINT8 read_byte(offs_t byteaddress)
282: {
1.1.1.4 root 283: #if defined(HAS_I386)
1.1 root 284: if(byteaddress < MAX_MEM) {
285: return mem[byteaddress];
1.1.1.3 root 286: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
287: // return read_byte(byteaddress & 0xfffff);
1.1 root 288: }
289: return 0;
1.1.1.4 root 290: #else
291: return mem[byteaddress];
292: #endif
1.1 root 293: }
294:
295: UINT16 read_word(offs_t byteaddress)
296: {
1.1.1.14 root 297: if(byteaddress == 0x41c) {
298: // pointer to first free slot in keyboard buffer
299: // XXX: the buffer itself doesn't actually exist in DOS memory
300: if(key_buf_char->count() == 0) {
301: maybe_idle();
302: }
303: return (UINT16)key_buf_char->count();
304: }
1.1.1.4 root 305: #if defined(HAS_I386)
1.1 root 306: if(byteaddress < MAX_MEM - 1) {
307: return *(UINT16 *)(mem + byteaddress);
1.1.1.3 root 308: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
309: // return read_word(byteaddress & 0xfffff);
1.1 root 310: }
311: return 0;
1.1.1.4 root 312: #else
313: return *(UINT16 *)(mem + byteaddress);
314: #endif
1.1 root 315: }
316:
317: UINT32 read_dword(offs_t byteaddress)
318: {
1.1.1.4 root 319: #if defined(HAS_I386)
1.1 root 320: if(byteaddress < MAX_MEM - 3) {
321: return *(UINT32 *)(mem + byteaddress);
1.1.1.3 root 322: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
323: // return read_dword(byteaddress & 0xfffff);
1.1 root 324: }
325: return 0;
1.1.1.4 root 326: #else
327: return *(UINT32 *)(mem + byteaddress);
328: #endif
1.1 root 329: }
330:
331: // write accessors
1.1.1.14 root 332: #ifdef USE_THREAD
333: void vram_flush_char()
334: {
335: if(vram_length_char != 0) {
336: DWORD num;
1.1.1.23 root 337: WriteConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), scr_char, vram_length_char, vram_coord_char, &num);
1.1.1.14 root 338: vram_length_char = vram_last_length_char = 0;
339: }
340: }
341:
342: void vram_flush_attr()
343: {
344: if(vram_length_attr != 0) {
345: DWORD num;
1.1.1.23 root 346: WriteConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE), scr_attr, vram_length_attr, vram_coord_attr, &num);
1.1.1.14 root 347: vram_length_attr = vram_last_length_attr = 0;
348: }
349: }
350:
351: void vram_flush()
352: {
353: if(vram_length_char != 0 || vram_length_attr != 0) {
354: EnterCriticalSection(&vram_crit_sect);
355: vram_flush_char();
356: vram_flush_attr();
357: LeaveCriticalSection(&vram_crit_sect);
358: }
359: }
360: #endif
361:
362: void write_text_vram_char(offs_t offset, UINT8 data)
1.1.1.8 root 363: {
1.1.1.14 root 364: #ifdef USE_THREAD
365: static offs_t first_offset_char, last_offset_char;
366:
367: if(vram_length_char != 0) {
368: if(offset <= last_offset_char && offset >= first_offset_char) {
369: scr_char[(offset - first_offset_char) >> 1] = data;
370: return;
371: }
372: if(offset != last_offset_char + 2) {
373: vram_flush_char();
374: }
375: }
376: if(vram_length_char == 0) {
377: first_offset_char = offset;
378: vram_coord_char.X = (offset >> 1) % scr_width;
379: vram_coord_char.Y = (offset >> 1) / scr_width + scr_top;
380: }
381: scr_char[vram_length_char++] = data;
382: last_offset_char = offset;
383: #else
1.1.1.8 root 384: COORD co;
385: DWORD num;
386:
1.1.1.14 root 387: co.X = (offset >> 1) % scr_width;
388: co.Y = (offset >> 1) / scr_width;
389: scr_char[0] = data;
1.1.1.23 root 390: WriteConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), scr_char, 1, co, &num);
1.1.1.14 root 391: #endif
392: }
393:
394: void write_text_vram_attr(offs_t offset, UINT8 data)
395: {
396: #ifdef USE_THREAD
397: static offs_t first_offset_attr, last_offset_attr;
398:
399: if(vram_length_attr != 0) {
400: if(offset <= last_offset_attr && offset >= first_offset_attr) {
401: scr_attr[(offset - first_offset_attr) >> 1] = data;
402: return;
403: }
404: if(offset != last_offset_attr + 2) {
405: vram_flush_attr();
406: }
407: }
408: if(vram_length_attr == 0) {
409: first_offset_attr = offset;
410: vram_coord_attr.X = (offset >> 1) % scr_width;
411: vram_coord_attr.Y = (offset >> 1) / scr_width + scr_top;
412: }
413: scr_attr[vram_length_attr++] = data;
414: last_offset_attr = offset;
415: #else
416: COORD co;
417: DWORD num;
1.1.1.8 root 418:
1.1.1.14 root 419: co.X = (offset >> 1) % scr_width;
420: co.Y = (offset >> 1) / scr_width;
421: scr_attr[0] = data;
1.1.1.23 root 422: WriteConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE), scr_attr, 1, co, &num);
1.1.1.14 root 423: #endif
424: }
425:
426: void write_text_vram_byte(offs_t offset, UINT8 data)
427: {
428: EnterCriticalSection(&vram_crit_sect);
1.1.1.8 root 429: if(offset & 1) {
1.1.1.14 root 430: write_text_vram_attr(offset, data);
1.1.1.8 root 431: } else {
1.1.1.14 root 432: write_text_vram_char(offset, data);
1.1.1.8 root 433: }
1.1.1.14 root 434: LeaveCriticalSection(&vram_crit_sect);
1.1.1.8 root 435: }
436:
437: void write_text_vram_word(offs_t offset, UINT16 data)
438: {
1.1.1.14 root 439: EnterCriticalSection(&vram_crit_sect);
1.1.1.8 root 440: if(offset & 1) {
1.1.1.14 root 441: write_text_vram_attr(offset , (data ) & 0xff);
442: write_text_vram_char(offset + 1, (data >> 8) & 0xff);
1.1.1.8 root 443: } else {
1.1.1.14 root 444: write_text_vram_char(offset , (data ) & 0xff);
445: write_text_vram_attr(offset + 1, (data >> 8) & 0xff);
1.1.1.8 root 446: }
1.1.1.14 root 447: LeaveCriticalSection(&vram_crit_sect);
1.1.1.8 root 448: }
449:
450: void write_text_vram_dword(offs_t offset, UINT32 data)
451: {
1.1.1.14 root 452: EnterCriticalSection(&vram_crit_sect);
1.1.1.8 root 453: if(offset & 1) {
1.1.1.14 root 454: write_text_vram_attr(offset , (data ) & 0xff);
455: write_text_vram_char(offset + 1, (data >> 8) & 0xff);
456: write_text_vram_attr(offset + 2, (data >> 16) & 0xff);
457: write_text_vram_char(offset + 3, (data >> 24) & 0xff);
458: } else {
459: write_text_vram_char(offset , (data ) & 0xff);
460: write_text_vram_attr(offset + 1, (data >> 8) & 0xff);
461: write_text_vram_char(offset + 2, (data >> 16) & 0xff);
462: write_text_vram_attr(offset + 3, (data >> 24) & 0xff);
1.1.1.8 root 463: }
1.1.1.14 root 464: LeaveCriticalSection(&vram_crit_sect);
1.1.1.8 root 465: }
466:
1.1 root 467: void write_byte(offs_t byteaddress, UINT8 data)
468: {
1.1.1.8 root 469: if(byteaddress < MEMORY_END) {
1.1.1.3 root 470: mem[byteaddress] = data;
1.1.1.8 root 471: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 472: if(!restore_console_on_exit) {
473: change_console_size(scr_width, scr_height);
1.1.1.12 root 474: }
1.1.1.8 root 475: write_text_vram_byte(byteaddress - text_vram_top_address, data);
476: mem[byteaddress] = data;
477: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
478: if(int_10h_feh_called && !int_10h_ffh_called) {
479: write_text_vram_byte(byteaddress - shadow_buffer_top_address, data);
1.1 root 480: }
481: mem[byteaddress] = data;
1.1.1.4 root 482: #if defined(HAS_I386)
1.1.1.3 root 483: } else if(byteaddress < MAX_MEM) {
1.1.1.4 root 484: #else
485: } else {
486: #endif
1.1.1.3 root 487: mem[byteaddress] = data;
1.1 root 488: }
489: }
490:
491: void write_word(offs_t byteaddress, UINT16 data)
492: {
1.1.1.8 root 493: if(byteaddress < MEMORY_END) {
1.1.1.14 root 494: if(byteaddress == 0x450 + mem[0x462] * 2) {
495: COORD co;
496: co.X = data & 0xff;
497: co.Y = (data >> 8) + scr_top;
1.1.1.23 root 498: SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), co);
1.1.1.14 root 499: }
1.1.1.3 root 500: *(UINT16 *)(mem + byteaddress) = data;
1.1.1.8 root 501: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 502: if(!restore_console_on_exit) {
503: change_console_size(scr_width, scr_height);
1.1.1.12 root 504: }
1.1.1.8 root 505: write_text_vram_word(byteaddress - text_vram_top_address, data);
506: *(UINT16 *)(mem + byteaddress) = data;
507: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
508: if(int_10h_feh_called && !int_10h_ffh_called) {
509: write_text_vram_word(byteaddress - shadow_buffer_top_address, data);
1.1 root 510: }
511: *(UINT16 *)(mem + byteaddress) = data;
1.1.1.4 root 512: #if defined(HAS_I386)
1.1.1.3 root 513: } else if(byteaddress < MAX_MEM - 1) {
1.1.1.4 root 514: #else
515: } else {
516: #endif
1.1.1.3 root 517: *(UINT16 *)(mem + byteaddress) = data;
1.1 root 518: }
519: }
520:
521: void write_dword(offs_t byteaddress, UINT32 data)
522: {
1.1.1.8 root 523: if(byteaddress < MEMORY_END) {
1.1.1.3 root 524: *(UINT32 *)(mem + byteaddress) = data;
1.1.1.8 root 525: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 526: if(!restore_console_on_exit) {
527: change_console_size(scr_width, scr_height);
1.1.1.12 root 528: }
1.1.1.8 root 529: write_text_vram_dword(byteaddress - text_vram_top_address, data);
530: *(UINT32 *)(mem + byteaddress) = data;
531: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
532: if(int_10h_feh_called && !int_10h_ffh_called) {
533: write_text_vram_dword(byteaddress - shadow_buffer_top_address, data);
1.1 root 534: }
535: *(UINT32 *)(mem + byteaddress) = data;
1.1.1.4 root 536: #if defined(HAS_I386)
1.1.1.3 root 537: } else if(byteaddress < MAX_MEM - 3) {
1.1.1.4 root 538: #else
539: } else {
540: #endif
1.1.1.3 root 541: *(UINT32 *)(mem + byteaddress) = data;
1.1 root 542: }
543: }
544:
545: #define read_decrypted_byte read_byte
546: #define read_decrypted_word read_word
547: #define read_decrypted_dword read_dword
548:
1.1.1.3 root 549: #define read_raw_byte read_byte
550: #define write_raw_byte write_byte
551:
552: #define read_word_unaligned read_word
553: #define write_word_unaligned write_word
554:
555: #define read_io_word_unaligned read_io_word
556: #define write_io_word_unaligned write_io_word
557:
1.1 root 558: UINT8 read_io_byte(offs_t byteaddress);
559: UINT16 read_io_word(offs_t byteaddress);
560: UINT32 read_io_dword(offs_t byteaddress);
561:
562: void write_io_byte(offs_t byteaddress, UINT8 data);
563: void write_io_word(offs_t byteaddress, UINT16 data);
564: void write_io_dword(offs_t byteaddress, UINT32 data);
565:
566: /*****************************************************************************/
567: /* src/osd/osdcomm.h */
568:
569: /* Highly useful macro for compile-time knowledge of an array size */
570: #define ARRAY_LENGTH(x) (sizeof(x) / sizeof(x[0]))
571:
1.1.1.3 root 572: #if defined(HAS_I386)
1.1.1.10 root 573: static CPU_TRANSLATE(i386);
574: #include "mame/lib/softfloat/softfloat.c"
575: #include "mame/emu/cpu/i386/i386.c"
1.1.1.12 root 576: #include "mame/emu/cpu/vtlb.c"
1.1.1.3 root 577: #elif defined(HAS_I286)
1.1.1.10 root 578: #include "mame/emu/cpu/i86/i286.c"
1.1.1.3 root 579: #else
1.1.1.10 root 580: #include "mame/emu/cpu/i86/i86.c"
1.1.1.3 root 581: #endif
1.1.1.22 root 582: #ifdef ENABLE_DEBUG_DASM
1.1.1.10 root 583: #include "mame/emu/cpu/i386/i386dasm.c"
1.1.1.22 root 584: int dasm = 0;
1.1 root 585: #endif
586:
1.1.1.3 root 587: #if defined(HAS_I386)
588: #define SREG(x) m_sreg[x].selector
589: #define SREG_BASE(x) m_sreg[x].base
590:
591: int cpu_type, cpu_step;
592: #else
593: #define REG8(x) m_regs.b[x]
594: #define REG16(x) m_regs.w[x]
595: #define SREG(x) m_sregs[x]
596: #define SREG_BASE(x) m_base[x]
597: #define m_CF m_CarryVal
598: #define m_a20_mask AMASK
599: #define i386_load_segment_descriptor(x) m_base[x] = SegBase(x)
600: #if defined(HAS_I286)
601: #define i386_set_a20_line(x) i80286_set_a20_line(x)
602: #else
603: #define i386_set_a20_line(x)
604: #endif
605: #define i386_set_irq_line(x, y) set_irq_line(x, y)
606: #endif
1.1 root 607:
608: void i386_jmp_far(UINT16 selector, UINT32 address)
609: {
1.1.1.3 root 610: #if defined(HAS_I386)
1.1 root 611: if(PROTECTED_MODE && !V8086_MODE) {
1.1.1.3 root 612: i386_protected_mode_jump(selector, address, 1, m_operand_size);
1.1 root 613: } else {
1.1.1.3 root 614: SREG(CS) = selector;
615: m_performed_intersegment_jump = 1;
616: i386_load_segment_descriptor(CS);
617: m_eip = address;
618: CHANGE_PC(m_eip);
1.1 root 619: }
1.1.1.3 root 620: #elif defined(HAS_I286)
621: i80286_code_descriptor(selector, address, 1);
622: #else
623: SREG(CS) = selector;
624: i386_load_segment_descriptor(CS);
625: m_pc = (SREG_BASE(CS) + address) & m_a20_mask;
626: #endif
1.1 root 627: }
628:
1.1.1.24 root 629: /*
630: void i386_call_far(UINT16 selector, UINT32 address)
631: {
632: #if defined(HAS_I386)
633: if(PROTECTED_MODE && !V8086_MODE) {
634: i386_protected_mode_call(selector, address, 1, m_operand_size);
635: } else {
636: PUSH16(SREG(CS));
637: PUSH16(m_eip);
638: SREG(CS) = selector;
639: m_performed_intersegment_jump = 1;
640: i386_load_segment_descriptor(CS);
641: m_eip = address;
642: CHANGE_PC(m_eip);
643: }
644: #else
645: UINT16 ip = m_pc - SREG_BASE(CS);
646: UINT16 cs = SREG(CS);
647: #if defined(HAS_I286)
648: i80286_code_descriptor(selector, address, 2);
649: #else
650: SREG(CS) = selector;
651: i386_load_segment_descriptor(CS);
652: m_pc = (SREG_BASE(CS) + address) & m_a20_mask;
653: #endif
654: PUSH(cs);
655: PUSH(ip);
656: CHANGE_PC(m_pc);
657: #endif
658: }
659: */
660:
1.1 root 661: /* ----------------------------------------------------------------------------
662: main
663: ---------------------------------------------------------------------------- */
664:
1.1.1.10 root 665: bool is_started_from_command_prompt()
666: {
1.1.1.18 root 667: bool ret = false;
668:
669: HMODULE hLibrary = LoadLibrary(_T("Kernel32.dll"));
670: if(hLibrary) {
671: typedef DWORD (WINAPI *GetConsoleProcessListFunction)(__out LPDWORD lpdwProcessList, __in DWORD dwProcessCount);
672: GetConsoleProcessListFunction lpfnGetConsoleProcessList;
673: lpfnGetConsoleProcessList = reinterpret_cast<GetConsoleProcessListFunction>(::GetProcAddress(hLibrary, "GetConsoleProcessList"));
674: if(lpfnGetConsoleProcessList) {
675: DWORD pl;
676: ret = (lpfnGetConsoleProcessList(&pl, 1) > 1);
677: FreeLibrary(hLibrary);
678: return(ret);
679: }
680: FreeLibrary(hLibrary);
681: }
682:
683: HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
684: if(hSnapshot != INVALID_HANDLE_VALUE) {
685: DWORD dwParentProcessID = 0;
686: PROCESSENTRY32 pe32;
687: pe32.dwSize = sizeof(PROCESSENTRY32);
688: if(Process32First(hSnapshot, &pe32)) {
689: do {
690: if(pe32.th32ProcessID == GetCurrentProcessId()) {
691: dwParentProcessID = pe32.th32ParentProcessID;
692: break;
693: }
694: } while(Process32Next(hSnapshot, &pe32));
695: }
696: CloseHandle(hSnapshot);
697: if(dwParentProcessID != 0) {
698: HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwParentProcessID);
699: if(hProcess != NULL) {
700: HMODULE hMod;
701: DWORD cbNeeded;
702: if(EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) {
703: char module_name[MAX_PATH];
704: if(GetModuleBaseName(hProcess, hMod, module_name, sizeof(module_name))) {
705: ret = (_strnicmp(module_name, "cmd.exe", 7) == 0);
706: }
707: }
708: CloseHandle(hProcess);
709: }
710: }
711: }
712: return(ret);
1.1.1.14 root 713: }
714:
715: BOOL is_greater_windows_version(DWORD dwMajorVersion, DWORD dwMinorVersion, WORD wServicePackMajor, WORD wServicePackMinor)
716: {
1.1.1.24 root 717: // https://msdn.microsoft.com/en-us/library/windows/desktop/ms725491(v=vs.85).aspx
1.1.1.14 root 718: OSVERSIONINFOEX osvi;
719: DWORDLONG dwlConditionMask = 0;
720: int op = VER_GREATER_EQUAL;
721:
722: // Initialize the OSVERSIONINFOEX structure.
723: ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
724: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
725: osvi.dwMajorVersion = dwMajorVersion;
726: osvi.dwMinorVersion = dwMinorVersion;
727: osvi.wServicePackMajor = wServicePackMajor;
728: osvi.wServicePackMinor = wServicePackMinor;
729:
730: // Initialize the condition mask.
731: VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, op );
732: VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, op );
733: VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMAJOR, op );
734: VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMINOR, op );
735:
736: // Perform the test.
737: return VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, dwlConditionMask);
738: }
739:
740: BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
741: {
1.1.1.26 root 742: if(dwCtrlType == CTRL_BREAK_EVENT) {
743: m_halted = true;
1.1.1.14 root 744: return TRUE;
1.1.1.26 root 745: } else if(dwCtrlType == CTRL_C_EVENT) {
746: ctrl_c_pressed = true;
747: return TRUE;
748: #ifdef EXPORT_DEBUG_TO_FILE
749: } else if(dwCtrlType == CTRL_CLOSE_EVENT) {
750: if(fdebug) {
751: fclose(fdebug);
752: fdebug = NULL;
753: }
754: #endif
1.1.1.14 root 755: }
756: return FALSE;
757: }
758:
759: #ifdef USE_THREAD
760: DWORD WINAPI vram_thread(LPVOID)
761: {
762: while(!m_halted) {
763: EnterCriticalSection(&vram_crit_sect);
764: if(vram_length_char != 0 && vram_length_char == vram_last_length_char) {
765: vram_flush_char();
766: }
767: if(vram_length_attr != 0 && vram_length_attr == vram_last_length_attr) {
768: vram_flush_attr();
769: }
770: vram_last_length_char = vram_length_char;
771: vram_last_length_attr = vram_length_attr;
772: LeaveCriticalSection(&vram_crit_sect);
773: // this is about half the maximum keyboard repeat rate - any
774: // lower tends to be jerky, any higher misses updates
775: Sleep(15);
1.1.1.10 root 776: }
1.1.1.14 root 777: return 0;
1.1.1.10 root 778: }
1.1.1.14 root 779: #endif
1.1.1.10 root 780:
1.1.1.9 root 781: #define IS_NUMERIC(c) ((c) >= '0' && (c) <= '9')
782:
1.1.1.27! root 783: #if defined(_MSC_VER) && (_MSC_VER >= 1400)
! 784: #define SUPPORT_EMBED
! 785: #endif
! 786:
! 787: #ifdef SUPPORT_EMBED
! 788: bool is_padding(UINT8 *buffer)
! 789: {
! 790: return (memcmp(buffer, "XPADDING", 8) == 0 && memcmp(buffer + 8, "PADDINGX", 8) == 0) ||
! 791: (memcmp(buffer, "PADDINGP", 8) == 0 && memcmp(buffer + 8, "ADDINGXX", 8) == 0) ||
! 792: (memcmp(buffer, "ADDINGPA", 8) == 0 && memcmp(buffer + 8, "DDINGXXP", 8) == 0) ||
! 793: (memcmp(buffer, "DDINGPAD", 8) == 0 && memcmp(buffer + 8, "DINGXXPA", 8) == 0) ||
! 794: (memcmp(buffer, "DINGPADD", 8) == 0 && memcmp(buffer + 8, "INGXXPAD", 8) == 0) ||
! 795: (memcmp(buffer, "INGPADDI", 8) == 0 && memcmp(buffer + 8, "NGXXPADD", 8) == 0) ||
! 796: (memcmp(buffer, "NGPADDIN", 8) == 0 && memcmp(buffer + 8, "GXXPADDI", 8) == 0) ||
! 797: (memcmp(buffer, "GPADDING", 8) == 0 && memcmp(buffer + 8, "XXPADDIN", 8) == 0) ||
! 798: (memcmp(buffer, "PADDINGX", 8) == 0 && memcmp(buffer + 8, "XPADDING", 8) == 0) ||
! 799: (memcmp(buffer, "ADDINGXX", 8) == 0 && memcmp(buffer + 8, "PADDINGP", 8) == 0) ||
! 800: (memcmp(buffer, "DDINGXXP", 8) == 0 && memcmp(buffer + 8, "ADDINGPA", 8) == 0) ||
! 801: (memcmp(buffer, "DINGXXPA", 8) == 0 && memcmp(buffer + 8, "DDINGPAD", 8) == 0) ||
! 802: (memcmp(buffer, "INGXXPAD", 8) == 0 && memcmp(buffer + 8, "DINGPADD", 8) == 0) ||
! 803: (memcmp(buffer, "NGXXPADD", 8) == 0 && memcmp(buffer + 8, "INGPADDI", 8) == 0) ||
! 804: (memcmp(buffer, "GXXPADDI", 8) == 0 && memcmp(buffer + 8, "NGPADDIN", 8) == 0) ||
! 805: (memcmp(buffer, "XXPADDIN", 8) == 0 && memcmp(buffer + 8, "GPADDING", 8) == 0);
! 806: };
! 807: #endif
! 808:
! 809: void get_sio_port_numbers()
! 810: {
! 811: SP_DEVINFO_DATA DeviceInfoData = {sizeof(SP_DEVINFO_DATA)};
! 812: HDEVINFO hDevInfo = 0;
! 813: HKEY hKey = 0;
! 814: if((hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_COMPORT, NULL, NULL, (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE))) != 0) {
! 815: for(int i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData); i++) {
! 816: if((hKey = SetupDiOpenDevRegKey(hDevInfo, &DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE)) != INVALID_HANDLE_VALUE) {
! 817: char chData[256];
! 818: DWORD dwType = 0;
! 819: DWORD dwSize = sizeof(chData);
! 820: int port_number = 0;
! 821:
! 822: if(RegQueryValueEx(hKey, _T("PortName"), NULL, &dwType, (BYTE *)chData, &dwSize) == ERROR_SUCCESS) {
! 823: if(_strnicmp(chData, "COM", 3) == 0) {
! 824: port_number = atoi(chData + 3);
! 825: }
! 826: }
! 827: RegCloseKey(hKey);
! 828:
! 829: if(sio_port_number[0] == port_number || sio_port_number[1] == port_number) {
! 830: continue;
! 831: }
! 832: if(sio_port_number[0] == 0) {
! 833: sio_port_number[0] = port_number;
! 834: } else if(sio_port_number[1] == 0) {
! 835: sio_port_number[1] = port_number;
! 836: }
! 837: if(sio_port_number[0] != 0 && sio_port_number[1] != 0) {
! 838: break;
! 839: }
! 840: }
! 841: }
! 842: }
! 843: }
! 844:
1.1 root 845: int main(int argc, char *argv[], char *envp[])
846: {
1.1.1.9 root 847: int arg_offset = 0;
848: int standard_env = 0;
1.1.1.14 root 849: int buf_width = 0, buf_height = 0;
1.1.1.15 root 850: BOOL bSuccess, bChangeScreenSize = FALSE;
1.1 root 851:
1.1.1.27! root 852: #ifdef SUPPORT_EMBED
! 853: // FIXME: it is invited that this program is built with VC++2005 or later,
! 854: // and "XPADDINGPADDINGX" is stored at the end of this execution file
! 855: char dummy_argv_0[] = "msdos.exe";
! 856: char dummy_argv_1[MAX_PATH];
! 857: char *dummy_argv[256] = {dummy_argv_0, dummy_argv_1, 0};
! 858: char new_exec_file[MAX_PATH];
! 859: bool convert_cmd_file = false;
! 860:
! 861: _TCHAR path[MAX_PATH], full[MAX_PATH], *name = NULL;
! 862: GetModuleFileName(NULL, path, MAX_PATH);
! 863: GetFullPathName(path, MAX_PATH, full, &name);
! 864:
! 865: if(name != NULL && stricmp(name, "msdos.exe") != 0) {
! 866: // run embedded command file
! 867: FILE* fp = fopen(full, "rb");
! 868: fseek(fp, 0, SEEK_END);
! 869: UINT32 size = ftell(fp), pos = 0;
! 870: fseek(fp, 0, SEEK_SET);
! 871: bool prev_padding = false;
! 872:
! 873: while(pos < size) {
! 874: UINT8 buffer[16];
! 875: fread(buffer, 16, 1, fp);
! 876:
! 877: if(prev_padding && memcmp(buffer, "OPTS:", 5) == 0) {
! 878: // restore flags
! 879: stay_busy = ((buffer[5] & 0x01) != 0);
! 880: no_windows = ((buffer[5] & 0x02) != 0);
! 881: standard_env = ((buffer[5] & 0x04) != 0);
! 882: ignore_illegal_insn = ((buffer[5] & 0x08) != 0);
! 883: limit_max_memory = ((buffer[5] & 0x10) != 0);
! 884: if((buffer[5] & 0x20) != 0) {
! 885: get_sio_port_numbers();
! 886: }
! 887: if((buffer[5] & 0x40) != 0) {
! 888: UMB_TOP = EMS_TOP + EMS_SIZE;
! 889: support_ems = true;
! 890: #ifdef SUPPORT_XMS
! 891: support_xms = true;
! 892: #endif
! 893: }
! 894: if(buffer[6] != 0 && buffer[7] != 0) {
! 895: buf_width = buffer[6];
! 896: buf_height = buffer[7];
! 897: }
! 898: if(buffer[8] != 0) {
! 899: major_version = buffer[8];
! 900: minor_version = buffer[9];
! 901: }
! 902: if(buffer[10] != 0 || buffer[11] != 0) {
! 903: int code_page = buffer[10] + buffer[11] * 256;
! 904: SetConsoleCP(code_page);
! 905: SetConsoleOutputCP(code_page);
! 906: }
! 907: fread(buffer, 16, 1, fp);
! 908: fseek(fp, -16, SEEK_CUR);
! 909:
! 910: // restore command file
! 911: if(memcmp(buffer, "MZ", 2) == 0) {
! 912: sprintf(dummy_argv_1, "%s\\MSDOSPLA.EXE", getenv("TEMP"));
! 913: } else {
! 914: sprintf(dummy_argv_1, "%s\\MSDOSPLA.COM", getenv("TEMP"));
! 915: }
! 916: FILE* fo = fopen(dummy_argv_1, "wb");
! 917: for(; pos < size; pos++) {
! 918: fputc(fgetc(fp), fo);
! 919: }
! 920: fclose(fo);
! 921:
! 922: // adjust argc/argv
! 923: for(int i = 1; i < argc && (i + 1) < 256; i++) {
! 924: dummy_argv[i + 1] = argv[i];
! 925: }
! 926: argc++;
! 927: argv = dummy_argv;
! 928: break;
! 929: }
! 930: prev_padding = is_padding(buffer);
! 931: pos += 16;
! 932: }
! 933: fclose(fp);
! 934: }
! 935: #endif
1.1.1.9 root 936: for(int i = 1; i < argc; i++) {
1.1.1.25 root 937: if(_strnicmp(argv[i], "-b", 2) == 0) {
938: stay_busy = true;
939: arg_offset++;
1.1.1.27! root 940: #ifdef SUPPORT_EMBED
! 941: } else if(_strnicmp(argv[i], "-c", 2) == 0) {
! 942: if(argv[i][2] != '\0') {
! 943: strcpy(new_exec_file, &argv[i][2]);
! 944: } else {
! 945: strcpy(new_exec_file, "new_exec_file.exe");
! 946: }
! 947: convert_cmd_file = true;
! 948: arg_offset++;
! 949: #endif
1.1.1.25 root 950: } else if(_strnicmp(argv[i], "-d", 2) == 0) {
951: no_windows = true;
952: arg_offset++;
953: } else if(_strnicmp(argv[i], "-e", 2) == 0) {
1.1.1.9 root 954: standard_env = 1;
955: arg_offset++;
1.1.1.14 root 956: } else if(_strnicmp(argv[i], "-i", 2) == 0) {
957: ignore_illegal_insn = true;
958: arg_offset++;
959: } else if(_strnicmp(argv[i], "-m", 2) == 0) {
960: limit_max_memory = true;
961: arg_offset++;
962: } else if(_strnicmp(argv[i], "-n", 2) == 0) {
1.1.1.17 root 963: if(sscanf(argv[1] + 2, "%d,%d", &buf_height, &buf_width) != 2) {
964: buf_width = buf_height = 0;
965: }
966: if(buf_width <= 0 || buf_width > 0x7fff) {
967: buf_width = 80;
968: }
969: if(buf_height <= 0 || buf_height > 0x7fff) {
970: buf_height = 25;
971: }
1.1.1.14 root 972: arg_offset++;
1.1.1.25 root 973: } else if(_strnicmp(argv[i], "-s", 2) == 0) {
974: if(strlen(argv[i]) > 2) {
975: char *p1 = &argv[i][2], *p2;
976: if((p2 = strchr(p1, ',')) != NULL) {
1.1.1.26 root 977: sio_port_number[1] = atoi(p2 + 1);
1.1.1.25 root 978: }
1.1.1.26 root 979: sio_port_number[0] = atoi(p1);
1.1.1.25 root 980: }
1.1.1.26 root 981: if(sio_port_number[0] == 0 || sio_port_number[1] == 0) {
1.1.1.27! root 982: get_sio_port_numbers();
1.1.1.25 root 983: }
984: arg_offset++;
1.1.1.9 root 985: } else if(_strnicmp(argv[i], "-v", 2) == 0) {
1.1.1.17 root 986: 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 987: major_version = argv[i][2] - '0';
1.1.1.17 root 988: minor_version = (argv[i][4] - '0') * 10 + (argv[i][5] ? (argv[i][5] - '0') : 0);
1.1.1.9 root 989: }
990: arg_offset++;
1.1.1.25 root 991: } else if(_strnicmp(argv[i], "-x", 2) == 0) {
992: UMB_TOP = EMS_TOP + EMS_SIZE;
993: support_ems = true;
994: #ifdef SUPPORT_XMS
995: support_xms = true;
996: #endif
997: arg_offset++;
1.1.1.9 root 998: } else {
999: break;
1000: }
1001: }
1002: if(argc < 2 + arg_offset) {
1.1 root 1003: #ifdef _WIN64
1.1.1.14 root 1004: fprintf(stderr, "MS-DOS Player (" CPU_MODEL_NAME(CPU_MODEL) ") for Win32-x64 console\n\n");
1.1 root 1005: #else
1.1.1.14 root 1006: fprintf(stderr, "MS-DOS Player (" CPU_MODEL_NAME(CPU_MODEL) ") for Win32 console\n\n");
1.1 root 1007: #endif
1.1.1.25 root 1008: fprintf(stderr,
1.1.1.27! root 1009: "Usage: MSDOS [-b] "
! 1010: #ifdef SUPPORT_EMBED
! 1011: "[-c[(new exec file)]] "
! 1012: #endif
! 1013: "[-d] [-e] [-i] [-m] [-n[L[,C]]] [-s[P1[,P2]]] [-vX.XX] [-x] (command file) [options]\n"
1.1.1.25 root 1014: "\n"
1015: "\t-b\tstay busy during keyboard polling\n"
1.1.1.27! root 1016: #ifdef SUPPORT_EMBED
! 1017: #ifdef _WIN64
! 1018: "\t-c\tconvert command file to 64bit execution file\n"
! 1019: #else
! 1020: "\t-c\tconvert command file to 32bit execution file\n"
! 1021: #endif
! 1022: #endif
1.1.1.25 root 1023: "\t-d\tpretend running under straight DOS, not Windows\n"
1024: "\t-e\tuse a reduced environment block\n"
1025: "\t-i\tignore invalid instructions\n"
1026: "\t-m\trestrict free memory to 0x7FFF paragraphs\n"
1027: "\t-n\tcreate a new buffer (25 lines, 80 columns by default)\n"
1028: "\t-s\tenable serial I/O and set host's COM port numbers\n"
1029: "\t-v\tset the DOS version\n"
1.1.1.19 root 1030: #ifdef SUPPORT_XMS
1.1.1.25 root 1031: "\t-x\tenable XMS/EMS\n"
1.1.1.19 root 1032: #else
1.1.1.25 root 1033: "\t-x\tenable EMS\n"
1.1.1.19 root 1034: #endif
1035: );
1.1.1.10 root 1036:
1037: if(!is_started_from_command_prompt()) {
1038: fprintf(stderr, "\nStart this program from a command prompt!\n\nHit any key to quit...");
1039: while(!_kbhit()) {
1040: Sleep(10);
1041: }
1042: }
1.1.1.20 root 1043: #ifdef _DEBUG
1044: _CrtDumpMemoryLeaks();
1045: #endif
1.1 root 1046: return(EXIT_FAILURE);
1047: }
1.1.1.27! root 1048: #ifdef SUPPORT_EMBED
! 1049: if(convert_cmd_file) {
! 1050: retval = EXIT_FAILURE;
! 1051: if(name != NULL && stricmp(name, "msdos.exe") == 0) {
! 1052: FILE *fp = NULL, *fs = NULL, *fo = NULL;
! 1053: int data = 0;
! 1054:
! 1055: if((fp = fopen(full, "rb")) == NULL) {
! 1056: fprintf(stderr, "Cant't open '%s'\n", name);
! 1057: } else if((fs = fopen(argv[arg_offset + 1], "rb")) == NULL) {
! 1058: if(strchr(argv[arg_offset + 1], ',') != NULL) {
! 1059: fprintf(stderr, "Cant't open '%s'\n", argv[arg_offset + 1]);
! 1060: } else {
! 1061: fprintf(stderr, "Cant't open '%s', please specify command file with extenstion\n", argv[arg_offset + 1]);
! 1062: }
! 1063: } else if((fo = fopen(new_exec_file, "wb")) == NULL) {
! 1064: fprintf(stderr, "Cant't open '%s'\n", new_exec_file);
! 1065: } else {
! 1066: // store msdos.exe
! 1067: while((data = fgetc(fp)) != EOF) {
! 1068: fputc(data, fo);
! 1069: }
! 1070:
! 1071: // store options
! 1072: UINT8 flags = 0;
! 1073: if(stay_busy) {
! 1074: flags |= 0x01;
! 1075: }
! 1076: if(no_windows) {
! 1077: flags |= 0x02;
! 1078: }
! 1079: if(standard_env) {
! 1080: flags |= 0x04;
! 1081: }
! 1082: if(ignore_illegal_insn) {
! 1083: flags |= 0x08;
! 1084: }
! 1085: if(limit_max_memory) {
! 1086: flags |= 0x10;
! 1087: }
! 1088: if(sio_port_number[0] != 0 || sio_port_number[1] != 0) {
! 1089: flags |= 0x20;
! 1090: }
! 1091: if(support_ems) {
! 1092: flags |= 0x40;
! 1093: }
! 1094: int code_page = GetConsoleCP();
! 1095:
! 1096: fwrite("OPTS:", 5, 1, fo);
! 1097: fputc(flags, fo);
! 1098: fputc(buf_width, fo);
! 1099: fputc(buf_height, fo);
! 1100: fputc(major_version, fo);
! 1101: fputc(minor_version, fo);
! 1102: fputc((code_page >> 0) & 0xff, fo);
! 1103: fputc((code_page >> 8) & 0xff, fo);
! 1104: fputc(0, fo);
! 1105: fputc(0, fo);
! 1106: fputc(0, fo);
! 1107: fputc(0, fo);
! 1108:
! 1109: // store command file
! 1110: while((data = fgetc(fs)) != EOF) {
! 1111: fputc(data, fo);
! 1112: }
! 1113: fprintf(stderr, "'%s' is successfully created\n", new_exec_file);
! 1114: retval = EXIT_SUCCESS;
! 1115: }
! 1116: if(fp != NULL) {
! 1117: fclose(fp);
! 1118: }
! 1119: if(fs != NULL) {
! 1120: fclose(fs);
! 1121: }
! 1122: if(fo != NULL) {
! 1123: fclose(fo);
! 1124: }
! 1125: }
! 1126: #ifdef _DEBUG
! 1127: _CrtDumpMemoryLeaks();
! 1128: #endif
! 1129: return(retval);
! 1130: }
! 1131: #endif
1.1 root 1132:
1.1.1.14 root 1133: is_vista_or_later = is_greater_windows_version(6, 0, 0, 0);
1134:
1.1.1.23 root 1135: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 1136: CONSOLE_SCREEN_BUFFER_INFO csbi;
1.1.1.14 root 1137: CONSOLE_CURSOR_INFO ci;
1.1.1.23 root 1138:
1.1.1.12 root 1139: bSuccess = GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 1140: GetConsoleCursorInfo(hStdout, &ci);
1.1.1.24 root 1141: GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &dwConsoleMode);
1.1 root 1142:
1.1.1.14 root 1143: for(int y = 0; y < SCR_BUF_WIDTH; y++) {
1144: for(int x = 0; x < SCR_BUF_HEIGHT; x++) {
1145: SCR_BUF(y,x).Char.AsciiChar = ' ';
1146: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
1.1 root 1147: }
1148: }
1.1.1.12 root 1149: if(bSuccess) {
1150: scr_width = csbi.dwSize.X;
1.1.1.14 root 1151: scr_height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
1152:
1153: // v-text shadow buffer size is 0x7ff0
1154: if((scr_width > SCR_BUF_WIDTH) || (scr_height > SCR_BUF_HEIGHT) || (scr_width * scr_height * 2 > 0x7ff0) ||
1155: (buf_width != 0 && buf_width != scr_width) || (buf_height != 0 && buf_height != scr_height)) {
1156: scr_width = min(buf_width != 0 ? buf_width : scr_width, SCR_BUF_WIDTH);
1157: scr_height = min(buf_height != 0 ? buf_height : scr_height, SCR_BUF_HEIGHT);
1158: if(scr_width * scr_height * 2 > 0x7ff0) {
1159: scr_width = 80;
1160: scr_height = 25;
1161: }
1.1.1.15 root 1162: bChangeScreenSize = TRUE;
1.1.1.14 root 1163: }
1.1.1.12 root 1164: } else {
1165: // for a proof (not a console)
1166: scr_width = 80;
1167: scr_height = 25;
1168: }
1.1.1.14 root 1169: scr_buf_size.X = scr_width;
1170: scr_buf_size.Y = scr_height;
1171: scr_buf_pos.X = scr_buf_pos.Y = 0;
1172: scr_top = csbi.srWindow.Top;
1.1 root 1173: cursor_moved = false;
1174:
1.1.1.25 root 1175: key_buf_char = new FIFO(256);
1176: key_buf_scan = new FIFO(256);
1.1 root 1177:
1178: hardware_init();
1179:
1.1.1.9 root 1180: if(msdos_init(argc - (arg_offset + 1), argv + (arg_offset + 1), envp, standard_env)) {
1.1 root 1181: retval = EXIT_FAILURE;
1182: } else {
1.1.1.27! root 1183: #if defined(_MSC_VER) && (_MSC_VER >= 1400)
1.1.1.14 root 1184: _set_invalid_parameter_handler((_invalid_parameter_handler)ignore_invalid_parameters);
1185: #endif
1186: SetConsoleCtrlHandler(ctrl_handler, TRUE);
1187:
1.1.1.24 root 1188: if(bChangeScreenSize) {
1189: change_console_size(scr_width, scr_height);
1190: }
1.1.1.8 root 1191: TIMECAPS caps;
1192: timeGetDevCaps(&caps, sizeof(TIMECAPS));
1193: timeBeginPeriod(caps.wPeriodMin);
1.1.1.14 root 1194: #ifdef USE_THREAD
1195: InitializeCriticalSection(&vram_crit_sect);
1196: CloseHandle(CreateThread(NULL, 4096, vram_thread, NULL, 0, NULL));
1197: #endif
1.1 root 1198: hardware_run();
1.1.1.14 root 1199: #ifdef USE_THREAD
1200: vram_flush();
1201: DeleteCriticalSection(&vram_crit_sect);
1202: #endif
1.1.1.24 root 1203: timeEndPeriod(caps.wPeriodMin);
1.1.1.14 root 1204:
1.1.1.24 root 1205: // hStdin/hStdout (and all handles) will be closed in msdos_finish()...
1.1.1.12 root 1206: if(bSuccess) {
1.1.1.23 root 1207: hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.12 root 1208: if(restore_console_on_exit) {
1.1.1.14 root 1209: // window can't be bigger than buffer,
1210: // buffer can't be smaller than window,
1211: // so make a tiny window,
1212: // set the required buffer,
1213: // then set the required window
1214: SMALL_RECT rect;
1215: SET_RECT(rect, 0, csbi.srWindow.Top, 0, csbi.srWindow.Top);
1216: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1.1.1.12 root 1217: SetConsoleScreenBufferSize(hStdout, csbi.dwSize);
1.1.1.14 root 1218: SET_RECT(rect, 0, 0, csbi.srWindow.Right - csbi.srWindow.Left, csbi.srWindow.Bottom - csbi.srWindow.Top);
1.1.1.12 root 1219: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1220: }
1.1.1.14 root 1221: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
1222: SetConsoleCursorInfo(hStdout, &ci);
1.1.1.12 root 1223: }
1.1.1.24 root 1224: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode);
1225:
1.1 root 1226: msdos_finish();
1.1.1.14 root 1227:
1228: SetConsoleCtrlHandler(ctrl_handler, FALSE);
1.1 root 1229: }
1230:
1.1.1.10 root 1231: hardware_finish();
1232:
1.1.1.25 root 1233: key_buf_char->release();
1.1 root 1234: delete key_buf_char;
1.1.1.25 root 1235: key_buf_scan->release();
1.1 root 1236: delete key_buf_scan;
1237:
1.1.1.12 root 1238: // SetConsoleTextAttribute(hStdout, csbi.wAttributes);
1.1 root 1239:
1.1.1.27! root 1240: #if defined(_MSC_VER) && (_MSC_VER >= 1400)
! 1241: if(argv == dummy_argv) {
! 1242: DeleteFile(dummy_argv_1);
! 1243: }
! 1244: #endif
1.1.1.20 root 1245: #ifdef _DEBUG
1246: _CrtDumpMemoryLeaks();
1247: #endif
1.1 root 1248: return(retval);
1249: }
1250:
1.1.1.20 root 1251: /* ----------------------------------------------------------------------------
1252: console
1253: ---------------------------------------------------------------------------- */
1254:
1.1.1.14 root 1255: void change_console_size(int width, int height)
1.1.1.12 root 1256: {
1.1.1.23 root 1257: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.12 root 1258: CONSOLE_SCREEN_BUFFER_INFO csbi;
1259: SMALL_RECT rect;
1260: COORD co;
1261:
1262: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 1263: if(csbi.srWindow.Top != 0 || csbi.dwCursorPosition.Y > height - 1) {
1264: if(csbi.srWindow.Right - csbi.srWindow.Left + 1 == width && csbi.srWindow.Bottom - csbi.srWindow.Top + 1 == height) {
1265: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &csbi.srWindow);
1266: SET_RECT(rect, 0, 0, width - 1, height - 1);
1267: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1268: } else if(csbi.dwCursorPosition.Y > height - 1) {
1269: SET_RECT(rect, 0, csbi.dwCursorPosition.Y - (height - 1), width - 1, csbi.dwCursorPosition.Y);
1270: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1271: SET_RECT(rect, 0, 0, width - 1, height - 1);
1272: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1.1.12 root 1273: }
1274: }
1.1.1.14 root 1275: if(csbi.dwCursorPosition.Y > height - 1) {
1.1.1.12 root 1276: co.X = csbi.dwCursorPosition.X;
1.1.1.14 root 1277: co.Y = min(height - 1, csbi.dwCursorPosition.Y - csbi.srWindow.Top);
1.1.1.12 root 1278: SetConsoleCursorPosition(hStdout, co);
1279: cursor_moved = true;
1280: }
1.1.1.14 root 1281:
1282: // window can't be bigger than buffer,
1283: // buffer can't be smaller than window,
1284: // so make a tiny window,
1285: // set the required buffer,
1286: // then set the required window
1287: SET_RECT(rect, 0, csbi.srWindow.Top, 0, csbi.srWindow.Top);
1.1.1.12 root 1288: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1.1.1.14 root 1289: co.X = width;
1290: co.Y = height;
1.1.1.12 root 1291: SetConsoleScreenBufferSize(hStdout, co);
1.1.1.14 root 1292: SET_RECT(rect, 0, 0, width - 1, height - 1);
1293: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1294:
1295: scr_width = scr_buf_size.X = width;
1296: scr_height = scr_buf_size.Y = height;
1297: scr_top = 0;
1298:
1299: clear_scr_buffer(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
1300:
1301: int regen = min(scr_width * scr_height * 2, 0x8000);
1.1.1.15 root 1302: text_vram_end_address = text_vram_top_address + regen;
1303: shadow_buffer_end_address = shadow_buffer_top_address + regen;
1304:
1.1.1.14 root 1305: if(regen > 0x4000) {
1306: regen = 0x8000;
1307: vram_pages = 1;
1308: } else if(regen > 0x2000) {
1309: regen = 0x4000;
1310: vram_pages = 2;
1311: } else if(regen > 0x1000) {
1312: regen = 0x2000;
1313: vram_pages = 4;
1314: } else {
1315: regen = 0x1000;
1316: vram_pages = 8;
1317: }
1.1.1.15 root 1318: *(UINT16 *)(mem + 0x44a) = scr_width;
1319: *(UINT16 *)(mem + 0x44c) = regen;
1320: *(UINT8 *)(mem + 0x484) = scr_height - 1;
1321:
1.1.1.24 root 1322: mouse.min_position.x = 0;
1323: mouse.min_position.y = 0;
1324: mouse.max_position.x = 8 * scr_width - 1;
1325: mouse.max_position.y = 8 * scr_height - 1;
1326:
1.1.1.15 root 1327: restore_console_on_exit = true;
1.1.1.14 root 1328: }
1329:
1330: void clear_scr_buffer(WORD attr)
1331: {
1332: for(int y = 0; y < scr_height; y++) {
1333: for(int x = 0; x < scr_width; x++) {
1334: SCR_BUF(y,x).Char.AsciiChar = ' ';
1335: SCR_BUF(y,x).Attributes = attr;
1336: }
1337: }
1.1.1.12 root 1338: }
1339:
1.1.1.24 root 1340: bool update_console_input()
1.1 root 1341: {
1.1.1.23 root 1342: HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
1.1.1.8 root 1343: DWORD dwNumberOfEvents = 0;
1.1 root 1344: DWORD dwRead;
1345: INPUT_RECORD ir[16];
1.1.1.24 root 1346: CONSOLE_SCREEN_BUFFER_INFO csbi = {0};
1347: bool result = false;
1.1 root 1348:
1.1.1.8 root 1349: if(GetNumberOfConsoleInputEvents(hStdin, &dwNumberOfEvents) && dwNumberOfEvents != 0) {
1350: if(ReadConsoleInputA(hStdin, ir, 16, &dwRead)) {
1351: for(int i = 0; i < dwRead; i++) {
1.1.1.24 root 1352: if(ir[i].EventType & MOUSE_EVENT) {
1353: if(mouse.active) {
1354: if(ir[i].Event.MouseEvent.dwEventFlags == 0) {
1355: for(int i = 0; i < MAX_MOUSE_BUTTONS; i++) {
1356: static const DWORD bits[] = {
1357: FROM_LEFT_1ST_BUTTON_PRESSED, // left
1358: RIGHTMOST_BUTTON_PRESSED, // right
1359: FROM_LEFT_2ND_BUTTON_PRESSED, // middle
1.1.1.14 root 1360: };
1.1.1.24 root 1361: bool prev_status = mouse.buttons[i].status;
1362: mouse.buttons[i].status = ((ir[i].Event.MouseEvent.dwButtonState & bits[i]) != 0);
1363:
1364: if(!prev_status && mouse.buttons[i].status) {
1365: mouse.buttons[i].pressed_times++;
1366: mouse.buttons[i].pressed_position.x = mouse.position.x;
1367: mouse.buttons[i].pressed_position.y = mouse.position.y;
1368: mouse.status |= 2 << (i * 2);
1369: } else if(prev_status && !mouse.buttons[i].status) {
1370: mouse.buttons[i].released_times++;
1371: mouse.buttons[i].released_position.x = mouse.position.x;
1372: mouse.buttons[i].released_position.y = mouse.position.y;
1373: mouse.status |= 4 << (i * 2);
1374: }
1.1.1.14 root 1375: }
1.1.1.24 root 1376: } else if(ir[i].Event.MouseEvent.dwEventFlags & MOUSE_MOVED) {
1377: // NOTE: if restore_console_on_exit, console is not scrolled
1378: if(!restore_console_on_exit && csbi.srWindow.Bottom == 0) {
1379: GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
1.1.1.14 root 1380: }
1.1.1.24 root 1381: // FIXME: character is always 8x8 ???
1382: int x = 8 * (ir[i].Event.MouseEvent.dwMousePosition.X);
1383: int y = 8 * (ir[i].Event.MouseEvent.dwMousePosition.Y - csbi.srWindow.Top);
1384: if(mouse.position.x != x || mouse.position.y != y) {
1385: mouse.position.x = x;
1386: mouse.position.y = y;
1387: mouse.status |= 1;
1.1.1.14 root 1388: }
1389: }
1390: }
1.1.1.24 root 1391: } else if(ir[i].EventType & KEY_EVENT) {
1392: kbd_data = ir[i].Event.KeyEvent.wVirtualScanCode;
1.1.1.14 root 1393: if(!ir[i].Event.KeyEvent.bKeyDown) {
1394: kbd_data |= 0x80;
1.1.1.24 root 1395: } else {
1396: kbd_data &= 0x7f;
1397:
1398: // update dos key buffer
1399: UINT8 chr = ir[i].Event.KeyEvent.uChar.AsciiChar;
1400: UINT8 scn = ir[i].Event.KeyEvent.wVirtualScanCode & 0xff;
1401:
1402: if(chr == 0) {
1403: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
1404: if(scn >= 0x3b && scn <= 0x44) {
1405: scn += 0x68 - 0x3b; // F1 to F10
1406: } else if(scn == 0x57 || scn == 0x58) {
1407: scn += 0x8b - 0x57; // F11 & F12
1408: } else if(scn >= 0x47 && scn <= 0x53) {
1409: scn += 0x97 - 0x47; // edit/arrow clusters
1410: } else if(scn == 0x35) {
1411: scn = 0xa4; // keypad /
1412: }
1413: } else if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
1414: if(scn == 0x07) {
1415: chr = 0x1e; // Ctrl+^
1416: } else if(scn == 0x0c) {
1417: chr = 0x1f; // Ctrl+_
1418: } else if(scn >= 0x35 && scn <= 0x58) {
1419: static const UINT8 ctrl_map[] = {
1420: 0x95, // keypad /
1421: 0,
1422: 0x96, // keypad *
1423: 0, 0, 0,
1424: 0x5e, // F1
1425: 0x5f, // F2
1426: 0x60, // F3
1427: 0x61, // F4
1428: 0x62, // F5
1429: 0x63, // F6
1430: 0x64, // F7
1431: 0x65, // F8
1432: 0x66, // F9
1433: 0x67, // F10
1434: 0,
1435: 0,
1436: 0x77, // Home
1437: 0x8d, // Up
1438: 0x84, // PgUp
1439: 0x8e, // keypad -
1440: 0x73, // Left
1441: 0x8f, // keypad center
1442: 0x74, // Right
1443: 0x90, // keyapd +
1444: 0x75, // End
1445: 0x91, // Down
1446: 0x76, // PgDn
1447: 0x92, // Insert
1448: 0x93, // Delete
1449: 0, 0, 0,
1450: 0x89, // F11
1451: 0x8a, // F12
1452: };
1453: scn = ctrl_map[scn - 0x35];
1454: }
1455: } else if(ir[i].Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
1456: if(scn >= 0x3b && scn <= 0x44) {
1457: scn += 0x54 - 0x3b; // F1 to F10
1458: } else if(scn == 0x57 || scn == 0x58) {
1459: scn += 0x87 - 0x57; // F11 & F12
1460: }
1461: } else if(scn == 0x57 || scn == 0x58) {
1462: scn += 0x85 - 0x57;
1463: }
1464: // ignore shift, ctrl, alt, win and menu keys
1465: if(scn != 0x1d && scn != 0x2a && scn != 0x36 && scn != 0x38 && (scn < 0x5b || scn > 0x5e)) {
1466: if(chr == 0) {
1467: key_buf_char->write(0x00);
1468: key_buf_scan->write(ir[i].Event.KeyEvent.dwControlKeyState & ENHANCED_KEY ? 0xe0 : 0x00);
1469: }
1470: key_buf_char->write(chr);
1471: key_buf_scan->write(scn);
1472: }
1473: } else {
1474: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
1475: chr = 0;
1476: if(scn >= 0x02 && scn <= 0x0e) {
1477: scn += 0x78 - 0x02; // 1 to 0 - =
1478: }
1479: }
1480: key_buf_char->write(chr);
1481: key_buf_scan->write(scn);
1482: }
1.1 root 1483: }
1.1.1.24 root 1484: result = key_changed = true;
1.1 root 1485: }
1486: }
1487: }
1488: }
1.1.1.24 root 1489: return(result);
1.1.1.8 root 1490: }
1491:
1.1.1.14 root 1492: bool update_key_buffer()
1.1.1.8 root 1493: {
1.1.1.24 root 1494: return(update_console_input() || key_buf_char->count() != 0);
1.1.1.8 root 1495: }
1496:
1.1.1.20 root 1497: /* ----------------------------------------------------------------------------
1498: MS-DOS virtual machine
1499: ---------------------------------------------------------------------------- */
1500:
1501: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg);
1502: int msdos_psp_get_file_table(int fd, int psp_seg);
1503: void msdos_putch(UINT8 data);
1504:
1.1 root 1505: // process info
1506:
1507: process_t *msdos_process_info_create(UINT16 psp_seg)
1508: {
1509: for(int i = 0; i < MAX_PROCESS; i++) {
1510: if(process[i].psp == 0 || process[i].psp == psp_seg) {
1511: memset(&process[i], 0, sizeof(process_t));
1512: process[i].psp = psp_seg;
1513: return(&process[i]);
1514: }
1515: }
1516: fatalerror("too many processes\n");
1517: return(NULL);
1518: }
1519:
1520: process_t *msdos_process_info_get(UINT16 psp_seg)
1521: {
1522: for(int i = 0; i < MAX_PROCESS; i++) {
1523: if(process[i].psp == psp_seg) {
1524: return(&process[i]);
1525: }
1526: }
1527: fatalerror("invalid psp address\n");
1528: return(NULL);
1529: }
1530:
1.1.1.23 root 1531: void msdos_sda_update(int psp_seg)
1532: {
1533: sda_t *sda = (sda_t *)(mem + SDA_TOP);
1534:
1535: for(int i = 0; i < MAX_PROCESS; i++) {
1536: if(process[i].psp == psp_seg) {
1537: sda->switchar = process[i].switchar;
1538: sda->current_dta.w.l = process[i].dta.w.l;
1539: sda->current_dta.w.h = process[i].dta.w.h;
1540: sda->current_psp = process[i].psp;
1541: break;
1542: }
1543: }
1544: sda->malloc_strategy = malloc_strategy;
1545: sda->return_code = retval;
1546: sda->current_drive = _getdrive();
1547: }
1548:
1.1.1.13 root 1549: // dta info
1550:
1551: void msdos_dta_info_init()
1552: {
1.1.1.14 root 1553: for(int i = 0; i < MAX_DTAINFO; i++) {
1.1.1.13 root 1554: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
1555: }
1556: }
1557:
1558: dtainfo_t *msdos_dta_info_get(UINT16 psp_seg, UINT32 dta_laddr)
1559: {
1560: dtainfo_t *free_dta = NULL;
1.1.1.14 root 1561: for(int i = 0; i < MAX_DTAINFO; i++) {
1562: if(dtalist[i].find_handle == INVALID_HANDLE_VALUE) {
1563: if(free_dta == NULL) {
1.1.1.13 root 1564: free_dta = &dtalist[i];
1565: }
1.1.1.14 root 1566: } else if(dta_laddr < LFN_DTA_LADDR && dtalist[i].dta == dta_laddr) {
1.1.1.13 root 1567: return(&dtalist[i]);
1568: }
1569: }
1.1.1.14 root 1570: if(free_dta) {
1.1.1.13 root 1571: free_dta->psp = psp_seg;
1572: free_dta->dta = dta_laddr;
1573: return(free_dta);
1574: }
1575: fatalerror("too many dta\n");
1576: return(NULL);
1577: }
1578:
1579: void msdos_dta_info_free(UINT16 psp_seg)
1580: {
1.1.1.14 root 1581: for(int i = 0; i < MAX_DTAINFO; i++) {
1582: if(dtalist[i].psp == psp_seg && dtalist[i].find_handle != INVALID_HANDLE_VALUE) {
1.1.1.13 root 1583: FindClose(dtalist[i].find_handle);
1584: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
1585: }
1586: }
1587: }
1588:
1.1 root 1589: void msdos_cds_update(int drv)
1590: {
1591: cds_t *cds = (cds_t *)(mem + CDS_TOP);
1592:
1593: memset(mem + CDS_TOP, 0, CDS_SIZE);
1594: sprintf(cds->path_name, "%c:\\", 'A' + drv);
1595: cds->drive_attrib = 0x4000; // physical drive
1596: cds->physical_drive_number = drv;
1597: }
1598:
1.1.1.17 root 1599: // nls information tables
1600:
1601: // uppercase table (func 6502h)
1602: void msdos_upper_table_update()
1603: {
1604: *(UINT16 *)(mem + UPPERTABLE_TOP) = 0x80;
1.1.1.22 root 1605: for(unsigned i = 0; i < 0x80; ++i) {
1.1.1.17 root 1606: UINT8 c[4];
1607: *(UINT32 *)c = 0; // reset internal conversion state
1608: CharUpperBuffA((LPSTR)c, 4); // (workaround for MBCS codepage)
1609: c[0] = 0x80 + i;
1610: DWORD rc = CharUpperBuffA((LPSTR)c, 1);
1611: mem[UPPERTABLE_TOP + 2 + i] = (rc == 1 && c[0]) ? c[0] : 0x80 + i;
1612: }
1613: }
1614:
1.1.1.23 root 1615: // lowercase table (func 6503h)
1616: void msdos_lower_table_update()
1617: {
1618: *(UINT16 *)(mem + LOWERTABLE_TOP) = 0x80;
1619: for(unsigned i = 0; i < 0x80; ++i) {
1620: UINT8 c[4];
1621: *(UINT32 *)c = 0; // reset internal conversion state
1622: CharLowerBuffA((LPSTR)c, 4); // (workaround for MBCS codepage)
1623: c[0] = 0x80 + i;
1624: DWORD rc = CharLowerBuffA((LPSTR)c, 1);
1625: mem[LOWERTABLE_TOP + 2 + i] = (rc == 1 && c[0]) ? c[0] : 0x80 + i;
1626: }
1627: }
1628:
1.1.1.17 root 1629: // filename uppercase table (func 6504h)
1630: void msdos_filename_upper_table_init()
1631: {
1632: // depended on (file)system, not on active codepage
1633: // temporary solution: just filling data
1634: *(UINT16 *)(mem + FILENAME_UPPERTABLE_TOP) = 0x80;
1.1.1.22 root 1635: for(unsigned i = 0; i < 0x80; ++i) {
1.1.1.17 root 1636: mem[FILENAME_UPPERTABLE_TOP + 2 + i] = 0x80 + i;
1637: }
1638: }
1639:
1640: // filaname terminator table (func 6505h)
1641: void msdos_filename_terminator_table_init()
1642: {
1643: const char illegal_chars[] = ".\"/\\[]:|<>+=;,"; // for standard MS-DOS fs.
1644: UINT8 *data = mem + FILENAME_TERMINATOR_TOP;
1645:
1646: data[2] = 1; // marker? (permissible character value)
1647: data[3] = 0x00; // 00h...FFh
1648: data[4] = 0xff;
1649: data[5] = 0; // marker? (excluded character)
1650: data[6] = 0x00; // 00h...20h
1651: data[7] = 0x20;
1652: data[8] = 2; // marker? (illegal characters for filename)
1653: data[9] = (UINT8)strlen(illegal_chars);
1654: memcpy(data + 10, illegal_chars, data[9]);
1655:
1656: // total length
1657: *(UINT16 *)data = (10 - 2) + data[9];
1658: }
1659:
1660: // collating table (func 6506h)
1661: void msdos_collating_table_update()
1662: {
1663: // temporary solution: just filling data
1664: *(UINT16 *)(mem + COLLATING_TABLE_TOP) = 0x100;
1.1.1.22 root 1665: for(unsigned i = 0; i < 256; ++i) {
1.1.1.17 root 1666: mem[COLLATING_TABLE_TOP + 2 + i] = i;
1667: }
1668: }
1669:
1.1 root 1670: // dbcs
1671:
1672: void msdos_dbcs_table_update()
1673: {
1674: UINT8 dbcs_data[DBCS_SIZE];
1675: memset(dbcs_data, 0, sizeof(dbcs_data));
1676:
1677: CPINFO info;
1678: GetCPInfo(active_code_page, &info);
1679:
1680: if(info.MaxCharSize != 1) {
1681: for(int i = 0;; i += 2) {
1682: UINT8 lo = info.LeadByte[i + 0];
1683: UINT8 hi = info.LeadByte[i + 1];
1684: dbcs_data[2 + i + 0] = lo;
1685: dbcs_data[2 + i + 1] = hi;
1686: if(lo == 0 && hi == 0) {
1687: dbcs_data[0] = i + 2;
1688: break;
1689: }
1690: }
1691: } else {
1692: dbcs_data[0] = 2; // ???
1693: }
1694: memcpy(mem + DBCS_TOP, dbcs_data, sizeof(dbcs_data));
1695: }
1696:
1.1.1.17 root 1697: void msdos_dbcs_table_finish()
1698: {
1699: if(active_code_page != system_code_page) {
1700: _setmbcp(system_code_page);
1701: }
1702: }
1703:
1704: void msdos_nls_tables_init()
1.1 root 1705: {
1706: system_code_page = active_code_page = _getmbcp();
1.1.1.17 root 1707: msdos_upper_table_update();
1.1.1.23 root 1708: msdos_lower_table_update();
1.1.1.17 root 1709: msdos_filename_terminator_table_init();
1710: msdos_filename_upper_table_init();
1711: msdos_collating_table_update();
1.1 root 1712: msdos_dbcs_table_update();
1713: }
1714:
1.1.1.17 root 1715: void msdos_nls_tables_update()
1.1 root 1716: {
1.1.1.17 root 1717: msdos_dbcs_table_update();
1718: msdos_upper_table_update();
1.1.1.23 root 1719: msdos_lower_table_update();
1720: // msdos_collating_table_update();
1.1 root 1721: }
1722:
1723: int msdos_lead_byte_check(UINT8 code)
1724: {
1725: UINT8 *dbcs_table = mem + DBCS_TABLE;
1726:
1727: for(int i = 0;; i += 2) {
1728: UINT8 lo = dbcs_table[i + 0];
1729: UINT8 hi = dbcs_table[i + 1];
1730: if(lo == 0 && hi == 0) {
1731: break;
1732: }
1733: if(lo <= code && code <= hi) {
1734: return(1);
1735: }
1736: }
1737: return(0);
1738: }
1739:
1.1.1.20 root 1740: int msdos_ctrl_code_check(UINT8 code)
1741: {
1.1.1.22 root 1742: return (code >= 0x01 && code <= 0x1a && code != 0x07 && code != 0x08 && code != 0x09 && code != 0x0a && code != 0x0d);
1.1.1.20 root 1743: }
1744:
1.1 root 1745: // file control
1746:
1.1.1.14 root 1747: char *msdos_remove_double_quote(char *path)
1748: {
1749: static char tmp[MAX_PATH];
1750:
1751: memset(tmp, 0, sizeof(tmp));
1752: if(strlen(path) >= 2 && path[0] == '"' && path[strlen(path) - 1] == '"') {
1753: memcpy(tmp, path + 1, strlen(path) - 2);
1754: } else {
1755: strcpy(tmp, path);
1756: }
1757: return(tmp);
1758: }
1759:
1760: char *msdos_combine_path(char *dir, const char *file)
1761: {
1762: static char tmp[MAX_PATH];
1763: char *tmp_dir = msdos_remove_double_quote(dir);
1764:
1765: if(strlen(tmp_dir) == 0) {
1766: strcpy(tmp, file);
1767: } else if(tmp_dir[strlen(tmp_dir) - 1] == '\\') {
1768: sprintf(tmp, "%s%s", tmp_dir, file);
1769: } else {
1770: sprintf(tmp, "%s\\%s", tmp_dir, file);
1771: }
1772: return(tmp);
1773: }
1774:
1.1 root 1775: char *msdos_trimmed_path(char *path, int lfn)
1776: {
1777: static char tmp[MAX_PATH];
1778:
1779: if(lfn) {
1780: strcpy(tmp, path);
1781: } else {
1782: // remove space in the path
1783: char *src = path, *dst = tmp;
1784:
1785: while(*src != '\0') {
1786: if(msdos_lead_byte_check(*src)) {
1787: *dst++ = *src++;
1788: *dst++ = *src++;
1789: } else if(*src != ' ') {
1790: *dst++ = *src++;
1791: } else {
1792: src++; // skip space
1793: }
1794: }
1795: *dst = '\0';
1796: }
1.1.1.14 root 1797: if(_stricmp(tmp, "C:\\COMMAND.COM") == 0) {
1798: // redirect C:\COMMAND.COM to comspec_path
1799: strcpy(tmp, comspec_path);
1800: } else if(is_vista_or_later && _access(tmp, 0) != 0) {
1801: // redirect new files (without wildcards) in C:\ to %TEMP%, since C:\ is not usually writable
1802: static int root_drive_protected = -1;
1803: char temp[MAX_PATH], name[MAX_PATH], *name_temp = NULL;
1804: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
1805:
1806: if(GetFullPathName(tmp, MAX_PATH, temp, &name_temp) != 0 &&
1807: name_temp != NULL && strstr(name_temp, "?") == NULL && strstr(name_temp, "*") == NULL) {
1808: strcpy(name, name_temp);
1809: name_temp[0] = '\0';
1810:
1811: if((temp[0] == 'A' + dos_info->boot_drive - 1 || temp[0] == 'a' + dos_info->boot_drive - 1) &&
1812: (temp[1] == ':') && (temp[2] == '\\' || temp[2] == '/') && (temp[3] == '\0')) {
1813: if(root_drive_protected == -1) {
1814: FILE *fp = NULL;
1815:
1816: sprintf(temp, "%c:\\MS-DOS_Player.$$$", 'A' + dos_info->boot_drive - 1);
1817: root_drive_protected = 1;
1818: try {
1819: if((fp = fopen(temp, "w")) != NULL) {
1820: if(fprintf(fp, "TEST") == 4) {
1821: root_drive_protected = 0;
1822: }
1823: }
1824: } catch(...) {
1825: }
1826: if(fp != NULL) {
1827: fclose(fp);
1828: }
1829: if(_access(temp, 0) == 0) {
1830: remove(temp);
1831: }
1832: }
1833: if(root_drive_protected == 1) {
1834: if(GetEnvironmentVariable("TEMP", temp, MAX_PATH) != 0 ||
1835: GetEnvironmentVariable("TMP", temp, MAX_PATH) != 0) {
1836: strcpy(tmp, msdos_combine_path(temp, name));
1837: }
1838: }
1839: }
1840: }
1841: }
1.1 root 1842: return(tmp);
1843: }
1844:
1845: bool match(char *text, char *pattern)
1846: {
1.1.1.24 root 1847: // http://www.prefield.com/algorithm/string/wildcard.html
1.1.1.14 root 1848: switch(*pattern) {
1.1 root 1849: case '\0':
1850: return !*text;
1851: case '*':
1.1.1.14 root 1852: return match(text, pattern + 1) || (*text && match(text + 1, pattern));
1.1 root 1853: case '?':
1854: return *text && match(text + 1, pattern + 1);
1855: default:
1856: return (*text == *pattern) && match(text + 1, pattern + 1);
1857: }
1858: }
1859:
1860: bool msdos_match_volume_label(char *path, char *volume)
1861: {
1862: char *p;
1863:
1.1.1.14 root 1864: if(!*volume) {
1865: return false;
1866: } else if((p = my_strchr(path, ':')) != NULL) {
1.1 root 1867: return msdos_match_volume_label(p + 1, volume);
1868: } else if((p = my_strchr(path, '\\')) != NULL) {
1869: return msdos_match_volume_label(p + 1, volume);
1870: } else if((p = my_strchr(path, '.')) != NULL) {
1.1.1.14 root 1871: char tmp[MAX_PATH];
1872: sprintf(tmp, "%.*s%s", (int)(p - path), path, p + 1);
1873: return match(volume, tmp);
1.1 root 1874: } else {
1875: return match(volume, path);
1876: }
1877: }
1878:
1879: char *msdos_fcb_path(fcb_t *fcb)
1880: {
1881: static char tmp[MAX_PATH];
1882: char name[9], ext[4];
1883:
1884: memset(name, 0, sizeof(name));
1885: memcpy(name, fcb->file_name, 8);
1886: strcpy(name, msdos_trimmed_path(name, 0));
1887:
1888: memset(ext, 0, sizeof(ext));
1889: memcpy(ext, fcb->file_name + 8, 3);
1890: strcpy(ext, msdos_trimmed_path(ext, 0));
1891:
1892: if(name[0] == '\0' || strcmp(name, "????????") == 0) {
1893: strcpy(name, "*");
1894: }
1895: if(ext[0] == '\0') {
1896: strcpy(tmp, name);
1897: } else {
1898: if(strcmp(ext, "???") == 0) {
1899: strcpy(ext, "*");
1900: }
1901: sprintf(tmp, "%s.%s", name, ext);
1902: }
1903: return(tmp);
1904: }
1905:
1906: void msdos_set_fcb_path(fcb_t *fcb, char *path)
1907: {
1908: char *ext = my_strchr(path, '.');
1909:
1910: memset(fcb->file_name, 0x20, 8 + 3);
1911: if(ext != NULL && path[0] != '.') {
1912: *ext = '\0';
1913: memcpy(fcb->file_name + 8, ext + 1, strlen(ext + 1));
1914: }
1915: memcpy(fcb->file_name, path, strlen(path));
1916: }
1917:
1918: char *msdos_short_path(char *path)
1919: {
1920: static char tmp[MAX_PATH];
1921:
1.1.1.24 root 1922: if(GetShortPathName(path, tmp, MAX_PATH) == 0) {
1923: strcpy(tmp, path);
1924: }
1.1 root 1925: my_strupr(tmp);
1926: return(tmp);
1927: }
1928:
1.1.1.13 root 1929: char *msdos_short_name(WIN32_FIND_DATA *fd)
1930: {
1931: static char tmp[MAX_PATH];
1932:
1.1.1.14 root 1933: if(fd->cAlternateFileName[0]) {
1.1.1.13 root 1934: strcpy(tmp, fd->cAlternateFileName);
1935: } else {
1936: strcpy(tmp, fd->cFileName);
1937: }
1938: my_strupr(tmp);
1939: return(tmp);
1940: }
1941:
1.1 root 1942: char *msdos_short_full_path(char *path)
1943: {
1944: static char tmp[MAX_PATH];
1945: char full[MAX_PATH], *name;
1946:
1.1.1.14 root 1947: // Full works with non-existent files, but Short does not
1.1 root 1948: GetFullPathName(path, MAX_PATH, full, &name);
1.1.1.14 root 1949: *tmp = '\0';
1950: if(GetShortPathName(full, tmp, MAX_PATH) == 0 && name > path) {
1951: name[-1] = '\0';
1952: DWORD len = GetShortPathName(full, tmp, MAX_PATH);
1953: if(len == 0) {
1954: strcpy(tmp, full);
1955: } else {
1956: tmp[len++] = '\\';
1957: strcpy(tmp + len, name);
1958: }
1959: }
1.1 root 1960: my_strupr(tmp);
1961: return(tmp);
1962: }
1963:
1964: char *msdos_short_full_dir(char *path)
1965: {
1966: static char tmp[MAX_PATH];
1967: char full[MAX_PATH], *name;
1968:
1969: GetFullPathName(path, MAX_PATH, full, &name);
1970: name[-1] = '\0';
1.1.1.24 root 1971: if(GetShortPathName(full, tmp, MAX_PATH) == 0) {
1972: strcpy(tmp, full);
1973: }
1.1 root 1974: my_strupr(tmp);
1975: return(tmp);
1976: }
1977:
1978: char *msdos_local_file_path(char *path, int lfn)
1979: {
1980: char *trimmed = msdos_trimmed_path(path, lfn);
1.1.1.14 root 1981: #if 0
1982: // I have forgotten the reason of this routine... :-(
1.1 root 1983: if(_access(trimmed, 0) != 0) {
1984: process_t *process = msdos_process_info_get(current_psp);
1985: static char tmp[MAX_PATH];
1986:
1987: sprintf(tmp, "%s\\%s", process->module_dir, trimmed);
1988: if(_access(tmp, 0) == 0) {
1989: return(tmp);
1990: }
1991: }
1.1.1.14 root 1992: #endif
1.1 root 1993: return(trimmed);
1994: }
1995:
1.1.1.11 root 1996: bool msdos_is_con_path(char *path)
1997: {
1998: char full[MAX_PATH], *name;
1999:
1.1.1.24 root 2000: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
2001: return(_stricmp(full, "\\\\.\\CON") == 0);
2002: }
2003: return(false);
1.1.1.11 root 2004: }
2005:
1.1.1.14 root 2006: bool msdos_is_nul_path(char *path)
1.1.1.8 root 2007: {
1.1.1.14 root 2008: char full[MAX_PATH], *name;
1.1.1.8 root 2009:
1.1.1.24 root 2010: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
2011: return(_stricmp(full, "\\\\.\\NUL") == 0);
2012: }
2013: return(false);
2014: }
2015:
2016: bool msdos_is_driver_name(char *path)
2017: {
2018: char full[MAX_PATH], *name;
2019:
2020: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
2021: if(_stricmp(name, "EMMXXXX0") == 0) {
2022: return(true);
2023: }
2024: }
2025: return(false);
2026: }
2027:
2028: bool msdos_is_existing_file(char *path)
2029: {
2030: // http://d.hatena.ne.jp/yu-hr/20100317/1268826458
2031: WIN32_FIND_DATA FindData;
2032: HANDLE hFind;
2033:
2034: if((hFind = FindFirstFile(path, &FindData)) != INVALID_HANDLE_VALUE) {
2035: FindClose(hFind);
2036: return(!(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY));
2037: }
2038: return(false);
1.1.1.8 root 2039: }
2040:
1.1.1.9 root 2041: char *msdos_search_command_com(char *command_path, char *env_path)
2042: {
2043: static char tmp[MAX_PATH];
2044: char path[MAX_PATH], *file_name;
2045:
2046: if(GetFullPathName(command_path, MAX_PATH, tmp, &file_name) != 0) {
2047: sprintf(file_name, "COMMAND.COM");
2048: if(_access(tmp, 0) == 0) {
2049: return(tmp);
2050: }
2051: }
2052: if(GetModuleFileName(NULL, path, MAX_PATH) != 0 && GetFullPathName(path, MAX_PATH, tmp, &file_name) != 0) {
2053: sprintf(file_name, "COMMAND.COM");
2054: if(_access(tmp, 0) == 0) {
2055: return(tmp);
2056: }
2057: }
2058: if(GetFullPathName("COMMAND.COM", MAX_PATH, tmp, &file_name) != 0) {
2059: if(_access(tmp, 0) == 0) {
2060: return(tmp);
2061: }
2062: }
2063: char *token = my_strtok(env_path, ";");
2064: while(token != NULL) {
1.1.1.14 root 2065: if(strlen(token) != 0 && token[0] != '%') {
1.1.1.9 root 2066: strcpy(tmp, msdos_combine_path(token, "COMMAND.COM"));
2067: if(_access(tmp, 0) == 0) {
2068: return(tmp);
2069: }
2070: }
2071: token = my_strtok(NULL, ";");
2072: }
2073: return(NULL);
2074: }
2075:
1.1.1.14 root 2076: int msdos_drive_number(const char *path)
1.1 root 2077: {
2078: char tmp[MAX_PATH], *name;
2079:
2080: GetFullPathName(path, MAX_PATH, tmp, &name);
2081: if(tmp[0] >= 'a' && tmp[0] <= 'z') {
2082: return(tmp[0] - 'a');
2083: } else {
2084: return(tmp[0] - 'A');
2085: }
2086: }
2087:
2088: char *msdos_volume_label(char *path)
2089: {
2090: static char tmp[MAX_PATH];
2091: char volume[] = "A:\\";
2092:
2093: if(path[1] == ':') {
2094: volume[0] = path[0];
2095: } else {
2096: volume[0] = 'A' + _getdrive() - 1;
2097: }
2098: if(!GetVolumeInformation(volume, tmp, MAX_PATH, NULL, NULL, NULL, NULL, 0)) {
2099: memset(tmp, 0, sizeof(tmp));
2100: }
2101: return(tmp);
2102: }
2103:
2104: char *msdos_short_volume_label(char *label)
2105: {
2106: static char tmp[(8 + 1 + 3) + 1];
2107: char *src = label;
2108: int remain = strlen(label);
2109: char *dst_n = tmp;
2110: char *dst_e = tmp + 9;
2111:
2112: strcpy(tmp, " . ");
2113: for(int i = 0; i < 8 && remain > 0; i++) {
2114: if(msdos_lead_byte_check(*src)) {
2115: if(++i == 8) {
2116: break;
2117: }
2118: *dst_n++ = *src++;
2119: remain--;
2120: }
2121: *dst_n++ = *src++;
2122: remain--;
2123: }
2124: if(remain > 0) {
2125: for(int i = 0; i < 3 && remain > 0; i++) {
2126: if(msdos_lead_byte_check(*src)) {
2127: if(++i == 3) {
2128: break;
2129: }
2130: *dst_e++ = *src++;
2131: remain--;
2132: }
2133: *dst_e++ = *src++;
2134: remain--;
2135: }
2136: *dst_e = '\0';
2137: } else {
2138: *dst_n = '\0';
2139: }
2140: my_strupr(tmp);
2141: return(tmp);
2142: }
2143:
1.1.1.13 root 2144: errno_t msdos_maperr(unsigned long oserrno)
2145: {
2146: _doserrno = oserrno;
1.1.1.14 root 2147: switch(oserrno) {
1.1.1.13 root 2148: case ERROR_FILE_NOT_FOUND: // 2
2149: case ERROR_PATH_NOT_FOUND: // 3
2150: case ERROR_INVALID_DRIVE: // 15
2151: case ERROR_NO_MORE_FILES: // 18
2152: case ERROR_BAD_NETPATH: // 53
2153: case ERROR_BAD_NET_NAME: // 67
2154: case ERROR_BAD_PATHNAME: // 161
2155: case ERROR_FILENAME_EXCED_RANGE: // 206
2156: return ENOENT;
2157: case ERROR_TOO_MANY_OPEN_FILES: // 4
2158: return EMFILE;
2159: case ERROR_ACCESS_DENIED: // 5
2160: case ERROR_CURRENT_DIRECTORY: // 16
2161: case ERROR_NETWORK_ACCESS_DENIED: // 65
2162: case ERROR_CANNOT_MAKE: // 82
2163: case ERROR_FAIL_I24: // 83
2164: case ERROR_DRIVE_LOCKED: // 108
2165: case ERROR_SEEK_ON_DEVICE: // 132
2166: case ERROR_NOT_LOCKED: // 158
2167: case ERROR_LOCK_FAILED: // 167
2168: return EACCES;
2169: case ERROR_INVALID_HANDLE: // 6
2170: case ERROR_INVALID_TARGET_HANDLE: // 114
2171: case ERROR_DIRECT_ACCESS_HANDLE: // 130
2172: return EBADF;
2173: case ERROR_ARENA_TRASHED: // 7
2174: case ERROR_NOT_ENOUGH_MEMORY: // 8
2175: case ERROR_INVALID_BLOCK: // 9
2176: case ERROR_NOT_ENOUGH_QUOTA: // 1816
2177: return ENOMEM;
2178: case ERROR_BAD_ENVIRONMENT: // 10
2179: return E2BIG;
2180: case ERROR_BAD_FORMAT: // 11
2181: return ENOEXEC;
2182: case ERROR_NOT_SAME_DEVICE: // 17
2183: return EXDEV;
2184: case ERROR_FILE_EXISTS: // 80
2185: case ERROR_ALREADY_EXISTS: // 183
2186: return EEXIST;
2187: case ERROR_NO_PROC_SLOTS: // 89
2188: case ERROR_MAX_THRDS_REACHED: // 164
2189: case ERROR_NESTING_NOT_ALLOWED: // 215
2190: return EAGAIN;
2191: case ERROR_BROKEN_PIPE: // 109
2192: return EPIPE;
2193: case ERROR_DISK_FULL: // 112
2194: return ENOSPC;
2195: case ERROR_WAIT_NO_CHILDREN: // 128
2196: case ERROR_CHILD_NOT_COMPLETE: // 129
2197: return ECHILD;
2198: case ERROR_DIR_NOT_EMPTY: // 145
2199: return ENOTEMPTY;
2200: }
1.1.1.14 root 2201: if(oserrno >= ERROR_WRITE_PROTECT /* 19 */ &&
1.1.1.13 root 2202: oserrno <= ERROR_SHARING_BUFFER_EXCEEDED /* 36 */) {
2203: return EACCES;
2204: }
1.1.1.14 root 2205: if(oserrno >= ERROR_INVALID_STARTING_CODESEG /* 188 */ &&
1.1.1.13 root 2206: oserrno <= ERROR_INFLOOP_IN_RELOC_CHAIN /* 202 */) {
2207: return ENOEXEC;
2208: }
2209: return EINVAL;
2210: }
2211:
2212: int msdos_open(const char *filename, int oflag)
2213: {
1.1.1.14 root 2214: if((oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) != _O_RDONLY) {
1.1.1.13 root 2215: return _open(filename, oflag);
2216: }
1.1.1.14 root 2217:
2218: SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, !(oflag & _O_NOINHERIT) };
1.1.1.13 root 2219: DWORD disposition;
1.1.1.14 root 2220: switch(oflag & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
2221: default:
1.1.1.13 root 2222: case _O_EXCL:
2223: disposition = OPEN_EXISTING;
2224: break;
2225: case _O_CREAT:
2226: disposition = OPEN_ALWAYS;
2227: break;
2228: case _O_CREAT | _O_EXCL:
2229: case _O_CREAT | _O_TRUNC | _O_EXCL:
2230: disposition = CREATE_NEW;
2231: break;
2232: case _O_TRUNC:
2233: case _O_TRUNC | _O_EXCL:
2234: disposition = TRUNCATE_EXISTING;
2235: break;
2236: case _O_CREAT | _O_TRUNC:
2237: disposition = CREATE_ALWAYS;
2238: break;
2239: }
1.1.1.14 root 2240:
1.1.1.13 root 2241: HANDLE h = CreateFile(filename, GENERIC_READ | FILE_WRITE_ATTRIBUTES,
2242: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
2243: FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.14 root 2244: if(h == INVALID_HANDLE_VALUE) {
1.1.1.13 root 2245: // FILE_WRITE_ATTRIBUTES may not be granted for standard users.
2246: // Retry without FILE_WRITE_ATTRIBUTES.
2247: h = CreateFile(filename, GENERIC_READ,
2248: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
2249: FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.14 root 2250: if(h == INVALID_HANDLE_VALUE) {
1.1.1.13 root 2251: errno = msdos_maperr(GetLastError());
2252: return -1;
2253: }
2254: }
1.1.1.14 root 2255:
1.1.1.13 root 2256: int fd = _open_osfhandle((intptr_t) h, oflag);
1.1.1.14 root 2257: if(fd == -1) {
1.1.1.13 root 2258: CloseHandle(h);
2259: }
2260: return fd;
2261: }
2262:
1.1.1.14 root 2263: void msdos_file_handler_open(int fd, const char *path, int atty, int mode, UINT16 info, UINT16 psp_seg)
1.1 root 2264: {
2265: static int id = 0;
2266: char full[MAX_PATH], *name;
2267:
2268: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
2269: strcpy(file_handler[fd].path, full);
2270: } else {
2271: strcpy(file_handler[fd].path, path);
2272: }
1.1.1.14 root 2273: // isatty makes no distinction between CON & NUL
2274: // GetFileSize fails on CON, succeeds on NUL
2275: if(atty && (info != 0x80d3 || GetFileSize((HANDLE)_get_osfhandle(fd), NULL) == 0)) {
2276: info = 0x8084;
2277: atty = 0;
2278: } else if(!atty && info == 0x80d3) {
2279: info = msdos_drive_number(".");
2280: }
1.1 root 2281: file_handler[fd].valid = 1;
2282: file_handler[fd].id = id++; // dummy id for int 21h ax=71a6h
2283: file_handler[fd].atty = atty;
2284: file_handler[fd].mode = mode;
2285: file_handler[fd].info = info;
2286: file_handler[fd].psp = psp_seg;
1.1.1.21 root 2287:
2288: // init system file table
2289: if(fd < 20) {
2290: UINT8 *sft = mem + SFT_TOP + 6 + 0x3b * fd;
2291:
2292: memset(sft, 0, 0x3b);
2293:
2294: *(UINT16 *)(sft + 0x00) = 1;
2295: *(UINT16 *)(sft + 0x02) = file_handler[fd].mode;
2296: *(UINT8 *)(sft + 0x04) = GetFileAttributes(file_handler[fd].path) & 0xff;
2297: *(UINT16 *)(sft + 0x05) = file_handler[fd].info & 0xff;
2298:
2299: if(!(file_handler[fd].info & 0x80)) {
2300: *(UINT16 *)(sft + 0x07) = sizeof(dpb_t) * (file_handler[fd].info & 0x1f);
2301: *(UINT16 *)(sft + 0x09) = DPB_TOP >> 4;
2302:
2303: FILETIME time, local;
2304: HANDLE hHandle;
2305: WORD dos_date = 0, dos_time = 0;
2306: DWORD file_size = 0;
2307: if((hHandle = (HANDLE)_get_osfhandle(fd)) != INVALID_HANDLE_VALUE) {
2308: if(GetFileTime(hHandle, NULL, NULL, &time)) {
2309: FileTimeToLocalFileTime(&time, &local);
2310: FileTimeToDosDateTime(&local, &dos_date, &dos_time);
2311: }
2312: file_size = GetFileSize(hHandle, NULL);
2313: }
2314: *(UINT16 *)(sft + 0x0d) = dos_time;
2315: *(UINT16 *)(sft + 0x0f) = dos_date;
2316: *(UINT32 *)(sft + 0x11) = file_size;
2317: }
2318:
2319: char fname[MAX_PATH] = {0}, ext[MAX_PATH] = {0};
2320: _splitpath(file_handler[fd].path, NULL, NULL, fname, ext);
2321: my_strupr(fname);
2322: my_strupr(ext);
2323: memset(sft + 0x20, 0x20, 11);
2324: memcpy(sft + 0x20, fname, min(strlen(fname), 8));
2325: memcpy(sft + 0x28, ext + 1, min(strlen(ext + 1), 3));
2326:
2327: *(UINT16 *)(sft + 0x31) = psp_seg;
2328: }
1.1 root 2329: }
2330:
2331: void msdos_file_handler_dup(int dst, int src, UINT16 psp_seg)
2332: {
2333: strcpy(file_handler[dst].path, file_handler[src].path);
2334: file_handler[dst].valid = 1;
2335: file_handler[dst].id = file_handler[src].id;
2336: file_handler[dst].atty = file_handler[src].atty;
2337: file_handler[dst].mode = file_handler[src].mode;
2338: file_handler[dst].info = file_handler[src].info;
2339: file_handler[dst].psp = psp_seg;
2340: }
2341:
1.1.1.20 root 2342: void msdos_file_handler_close(int fd)
1.1 root 2343: {
2344: file_handler[fd].valid = 0;
1.1.1.21 root 2345:
2346: if(fd < 20) {
2347: memset(mem + SFT_TOP + 6 + 0x3b * fd, 0, 0x3b);
2348: }
1.1 root 2349: }
2350:
1.1.1.14 root 2351: inline int msdos_file_attribute_create(UINT16 new_attr)
1.1 root 2352: {
1.1.1.14 root 2353: return(new_attr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
2354: FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE |
2355: FILE_ATTRIBUTE_DIRECTORY));
1.1 root 2356: }
2357:
2358: // find file
2359:
2360: int msdos_find_file_check_attribute(int attribute, int allowed_mask, int required_mask)
2361: {
2362: if((allowed_mask & 0x08) && !(attribute & FILE_ATTRIBUTE_DIRECTORY)) {
2363: return(0); // search directory only !!!
2364: } else if(!(allowed_mask & 0x02) && (attribute & FILE_ATTRIBUTE_HIDDEN)) {
2365: return(0);
2366: } else if(!(allowed_mask & 0x04) && (attribute & FILE_ATTRIBUTE_SYSTEM)) {
2367: return(0);
2368: } else if(!(allowed_mask & 0x10) && (attribute & FILE_ATTRIBUTE_DIRECTORY)) {
2369: return(0);
2370: } else if((attribute & required_mask) != required_mask) {
2371: return(0);
2372: } else {
2373: return(1);
2374: }
2375: }
2376:
1.1.1.13 root 2377: int msdos_find_file_has_8dot3name(WIN32_FIND_DATA *fd)
2378: {
1.1.1.14 root 2379: if(fd->cAlternateFileName[0]) {
1.1.1.13 root 2380: return 1;
2381: }
2382: size_t len = strlen(fd->cFileName);
1.1.1.14 root 2383: if(len > 12) {
1.1.1.13 root 2384: return 0;
2385: }
2386: const char *ext = strrchr(fd->cFileName, '.');
1.1.1.14 root 2387: if((ext ? ext - fd->cFileName : len) > 8) {
1.1.1.13 root 2388: return 0;
2389: }
2390: return 1;
2391: }
2392:
1.1 root 2393: void msdos_find_file_conv_local_time(WIN32_FIND_DATA *fd)
2394: {
2395: FILETIME local;
2396:
2397: FileTimeToLocalFileTime(&fd->ftCreationTime, &local);
2398: fd->ftCreationTime.dwLowDateTime = local.dwLowDateTime;
2399: fd->ftCreationTime.dwHighDateTime = local.dwHighDateTime;
2400:
2401: FileTimeToLocalFileTime(&fd->ftLastAccessTime, &local);
2402: fd->ftLastAccessTime.dwLowDateTime = local.dwLowDateTime;
2403: fd->ftLastAccessTime.dwHighDateTime = local.dwHighDateTime;
2404:
2405: FileTimeToLocalFileTime(&fd->ftLastWriteTime, &local);
2406: fd->ftLastWriteTime.dwLowDateTime = local.dwLowDateTime;
2407: fd->ftLastWriteTime.dwHighDateTime = local.dwHighDateTime;
2408: }
2409:
2410: // i/o
2411:
2412: void msdos_stdio_reopen()
2413: {
2414: if(!file_handler[0].valid) {
2415: _dup2(DUP_STDIN, 0);
2416: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
2417: }
2418: if(!file_handler[1].valid) {
2419: _dup2(DUP_STDOUT, 1);
2420: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
2421: }
2422: if(!file_handler[2].valid) {
2423: _dup2(DUP_STDERR, 2);
2424: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
2425: }
1.1.1.21 root 2426: if(!file_handler[3].valid) {
2427: _dup2(DUP_STDAUX, 3);
2428: msdos_file_handler_open(3, "STDAUX", 0, 2, 0x80c0, 0);
2429: }
2430: if(!file_handler[4].valid) {
2431: _dup2(DUP_STDPRN, 4);
2432: msdos_file_handler_open(4, "STDPRN", 0, 1, 0xa8c0, 0);
2433: }
2434: for(int i = 0; i < 5; i++) {
2435: if(msdos_psp_get_file_table(i, current_psp) == 0xff) {
2436: msdos_psp_set_file_table(i, i, current_psp);
2437: }
2438: }
1.1 root 2439: }
2440:
2441: int msdos_kbhit()
2442: {
2443: msdos_stdio_reopen();
2444:
1.1.1.20 root 2445: process_t *process = msdos_process_info_get(current_psp);
2446: int fd = msdos_psp_get_file_table(0, current_psp);
2447:
2448: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 2449: // stdin is redirected to file
1.1.1.20 root 2450: return(eof(fd) == 0);
1.1 root 2451: }
2452:
2453: // check keyboard status
1.1.1.5 root 2454: if(key_buf_char->count() != 0 || key_code != 0) {
1.1 root 2455: return(1);
2456: } else {
2457: return(_kbhit());
2458: }
2459: }
2460:
2461: int msdos_getch_ex(int echo)
2462: {
2463: static char prev = 0;
2464:
2465: msdos_stdio_reopen();
2466:
1.1.1.20 root 2467: process_t *process = msdos_process_info_get(current_psp);
2468: int fd = msdos_psp_get_file_table(0, current_psp);
2469:
2470: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 2471: // stdin is redirected to file
2472: retry:
2473: char data;
1.1.1.20 root 2474: if(_read(fd, &data, 1) == 1) {
1.1 root 2475: char tmp = data;
2476: if(data == 0x0a) {
2477: if(prev == 0x0d) {
2478: goto retry; // CRLF -> skip LF
2479: } else {
2480: data = 0x0d; // LF only -> CR
2481: }
2482: }
2483: prev = tmp;
2484: return(data);
2485: }
2486: return(EOF);
2487: }
2488:
2489: // input from console
1.1.1.5 root 2490: int key_char, key_scan;
2491: if(key_code != 0) {
2492: key_char = (key_code >> 0) & 0xff;
2493: key_scan = (key_code >> 8) & 0xff;
2494: key_code >>= 16;
2495: } else {
1.1.1.26 root 2496: while(key_buf_char->count() == 0 && !m_halted && !ctrl_c_pressed) {
1.1.1.23 root 2497: if(!(fd < process->max_files && file_handler[fd].valid && file_handler[fd].atty && file_mode[file_handler[fd].mode].in)) {
2498: // NOTE: stdin is redirected to stderr when we do "type (file) | more" on freedos's command.com
2499: if(_kbhit()) {
2500: key_buf_char->write(_getch());
2501: key_buf_scan->write(0);
2502: } else {
2503: Sleep(10);
2504: }
2505: } else {
2506: if(!update_key_buffer()) {
2507: Sleep(10);
2508: }
1.1.1.14 root 2509: }
2510: }
2511: if(m_halted) {
1.1.1.26 root 2512: // ctrl-break pressed - insert CR to terminate input loops
1.1.1.14 root 2513: key_char = 0x0d;
2514: key_scan = 0;
1.1.1.26 root 2515: } else if(ctrl_c_pressed) {
2516: // ctrl-c pressed
2517: key_char = 0x03;
2518: key_scan = 0;
1.1.1.14 root 2519: } else {
2520: key_char = key_buf_char->read();
2521: key_scan = key_buf_scan->read();
1.1.1.5 root 2522: }
1.1 root 2523: }
2524: if(echo && key_char) {
2525: msdos_putch(key_char);
2526: }
2527: return key_char ? key_char : (key_scan != 0xe0) ? key_scan : 0;
2528: }
2529:
2530: inline int msdos_getch()
2531: {
2532: return(msdos_getch_ex(0));
2533: }
2534:
2535: inline int msdos_getche()
2536: {
2537: return(msdos_getch_ex(1));
2538: }
2539:
2540: int msdos_write(int fd, const void *buffer, unsigned int count)
2541: {
2542: static int is_cr = 0;
2543:
2544: if(fd == 1 && !file_handler[1].atty) {
2545: // CR+LF -> LF
2546: UINT8 *buf = (UINT8 *)buffer;
2547: for(unsigned int i = 0; i < count; i++) {
2548: UINT8 data = buf[i];
2549: if(is_cr) {
2550: if(data != 0x0a) {
2551: UINT8 tmp = 0x0d;
2552: _write(1, &tmp, 1);
2553: }
2554: _write(1, &data, 1);
2555: is_cr = 0;
2556: } else if(data == 0x0d) {
2557: is_cr = 1;
2558: } else {
2559: _write(1, &data, 1);
2560: }
2561: }
2562: return(count);
2563: }
1.1.1.14 root 2564: vram_flush();
1.1 root 2565: return(_write(fd, buffer, count));
2566: }
2567:
2568: void msdos_putch(UINT8 data)
2569: {
2570: static int p = 0;
2571: static int is_kanji = 0;
2572: static int is_esc = 0;
2573: static int stored_x;
2574: static int stored_y;
2575: static WORD stored_a;
1.1.1.20 root 2576: static char tmp[64], out[64];
1.1 root 2577:
2578: msdos_stdio_reopen();
2579:
1.1.1.20 root 2580: process_t *process = msdos_process_info_get(current_psp);
2581: int fd = msdos_psp_get_file_table(1, current_psp);
2582:
2583: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 2584: // stdout is redirected to file
1.1.1.20 root 2585: msdos_write(fd, &data, 1);
1.1 root 2586: return;
2587: }
1.1.1.23 root 2588: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 2589:
2590: // output to console
2591: tmp[p++] = data;
2592:
1.1.1.14 root 2593: vram_flush();
2594:
1.1 root 2595: if(is_kanji) {
2596: // kanji character
2597: is_kanji = 0;
2598: } else if(is_esc) {
2599: // escape sequense
2600: if((tmp[1] == ')' || tmp[1] == '(') && p == 3) {
2601: p = is_esc = 0;
2602: } else if(tmp[1] == '=' && p == 4) {
2603: COORD co;
2604: co.X = tmp[3] - 0x20;
1.1.1.14 root 2605: co.Y = tmp[2] - 0x20 + scr_top;
1.1 root 2606: SetConsoleCursorPosition(hStdout, co);
2607: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14 root 2608: mem[0x451 + mem[0x462] * 2] = co.Y - scr_top;
1.1 root 2609: cursor_moved = false;
2610: p = is_esc = 0;
2611: } else if((data >= 'a' && data <= 'z') || (data >= 'A' && data <= 'Z') || data == '*') {
2612: CONSOLE_SCREEN_BUFFER_INFO csbi;
2613: COORD co;
2614: GetConsoleScreenBufferInfo(hStdout, &csbi);
2615: co.X = csbi.dwCursorPosition.X;
2616: co.Y = csbi.dwCursorPosition.Y;
2617: WORD wAttributes = csbi.wAttributes;
2618:
2619: if(tmp[1] == 'D') {
2620: co.Y++;
2621: } else if(tmp[1] == 'E') {
2622: co.X = 0;
2623: co.Y++;
2624: } else if(tmp[1] == 'M') {
2625: co.Y--;
2626: } else if(tmp[1] == '*') {
2627: SMALL_RECT rect;
1.1.1.14 root 2628: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2629: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2630: co.X = 0;
2631: co.Y = csbi.srWindow.Top;
1.1 root 2632: } else if(tmp[1] == '[') {
2633: int param[256], params = 0;
2634: memset(param, 0, sizeof(param));
2635: for(int i = 2; i < p; i++) {
2636: if(tmp[i] >= '0' && tmp[i] <= '9') {
2637: param[params] *= 10;
2638: param[params] += tmp[i] - '0';
2639: } else {
2640: params++;
2641: }
2642: }
2643: if(data == 'A') {
1.1.1.14 root 2644: co.Y -= (params == 0) ? 1 : param[0];
1.1 root 2645: } else if(data == 'B') {
1.1.1.14 root 2646: co.Y += (params == 0) ? 1 : param[0];
1.1 root 2647: } else if(data == 'C') {
1.1.1.14 root 2648: co.X += (params == 0) ? 1 : param[0];
1.1 root 2649: } else if(data == 'D') {
1.1.1.14 root 2650: co.X -= (params == 0) ? 1 : param[0];
1.1 root 2651: } else if(data == 'H' || data == 'f') {
1.1.1.14 root 2652: co.X = (param[1] == 0 ? 1 : param[1]) - 1;
2653: co.Y = (param[0] == 0 ? 1 : param[0]) - 1 + csbi.srWindow.Top;
1.1 root 2654: } else if(data == 'J') {
2655: SMALL_RECT rect;
1.1.1.14 root 2656: clear_scr_buffer(csbi.wAttributes);
1.1 root 2657: if(param[0] == 0) {
2658: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 2659: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2660: if(co.Y < csbi.srWindow.Bottom) {
2661: SET_RECT(rect, 0, co.Y + 1, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2662: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2663: }
2664: } else if(param[0] == 1) {
1.1.1.14 root 2665: if(co.Y > csbi.srWindow.Top) {
2666: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, co.Y - 1);
2667: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2668: }
2669: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14 root 2670: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2671: } else if(param[0] == 2) {
1.1.1.14 root 2672: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2673: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2674: co.X = co.Y = 0;
2675: }
2676: } else if(data == 'K') {
2677: SMALL_RECT rect;
1.1.1.14 root 2678: clear_scr_buffer(csbi.wAttributes);
1.1 root 2679: if(param[0] == 0) {
2680: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 2681: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2682: } else if(param[0] == 1) {
2683: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14 root 2684: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2685: } else if(param[0] == 2) {
2686: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 2687: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2688: }
2689: } else if(data == 'L') {
2690: SMALL_RECT rect;
1.1.1.14 root 2691: if(params == 0) {
2692: param[0] = 1;
1.1 root 2693: }
1.1.1.14 root 2694: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2695: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2696: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2697: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2698: clear_scr_buffer(csbi.wAttributes);
1.1 root 2699: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y + param[0] - 1);
1.1.1.14 root 2700: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2701: co.X = 0;
2702: } else if(data == 'M') {
2703: SMALL_RECT rect;
1.1.1.14 root 2704: if(params == 0) {
2705: param[0] = 1;
2706: }
2707: if(co.Y + param[0] > csbi.srWindow.Bottom) {
2708: clear_scr_buffer(csbi.wAttributes);
2709: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2710: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2711: } else {
1.1.1.14 root 2712: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2713: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2714: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2715: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2716: clear_scr_buffer(csbi.wAttributes);
1.1 root 2717: }
2718: co.X = 0;
2719: } else if(data == 'h') {
2720: if(tmp[2] == '>' && tmp[3] == '5') {
2721: CONSOLE_CURSOR_INFO cur;
2722: GetConsoleCursorInfo(hStdout, &cur);
2723: if(cur.bVisible) {
2724: cur.bVisible = FALSE;
1.1.1.14 root 2725: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 2726: }
2727: }
2728: } else if(data == 'l') {
2729: if(tmp[2] == '>' && tmp[3] == '5') {
2730: CONSOLE_CURSOR_INFO cur;
2731: GetConsoleCursorInfo(hStdout, &cur);
2732: if(!cur.bVisible) {
2733: cur.bVisible = TRUE;
1.1.1.14 root 2734: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 2735: }
2736: }
2737: } else if(data == 'm') {
2738: wAttributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
2739: int reverse = 0, hidden = 0;
2740: for(int i = 0; i < params; i++) {
2741: if(param[i] == 1) {
2742: wAttributes |= FOREGROUND_INTENSITY;
2743: } else if(param[i] == 4) {
2744: wAttributes |= COMMON_LVB_UNDERSCORE;
2745: } else if(param[i] == 7) {
2746: reverse = 1;
2747: } else if(param[i] == 8 || param[i] == 16) {
2748: hidden = 1;
2749: } else if((param[i] >= 17 && param[i] <= 23) || (param[i] >= 30 && param[i] <= 37)) {
2750: wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
2751: if(param[i] >= 17 && param[i] <= 23) {
2752: param[i] -= 16;
2753: } else {
2754: param[i] -= 30;
2755: }
2756: if(param[i] & 1) {
2757: wAttributes |= FOREGROUND_RED;
2758: }
2759: if(param[i] & 2) {
2760: wAttributes |= FOREGROUND_GREEN;
2761: }
2762: if(param[i] & 4) {
2763: wAttributes |= FOREGROUND_BLUE;
2764: }
2765: } else if(param[i] >= 40 && param[i] <= 47) {
2766: wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
2767: if((param[i] - 40) & 1) {
2768: wAttributes |= BACKGROUND_RED;
2769: }
2770: if((param[i] - 40) & 2) {
2771: wAttributes |= BACKGROUND_GREEN;
2772: }
2773: if((param[i] - 40) & 4) {
2774: wAttributes |= BACKGROUND_BLUE;
2775: }
2776: }
2777: }
2778: if(reverse) {
2779: wAttributes &= ~0xff;
2780: wAttributes |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
2781: }
2782: if(hidden) {
2783: wAttributes &= ~0x0f;
2784: wAttributes |= (wAttributes >> 4) & 0x0f;
2785: }
2786: } else if(data == 'n') {
2787: if(param[0] == 6) {
2788: char tmp[16];
2789: sprintf(tmp, "\x1b[%d;%dR", co.Y + 1, co.X + 1);
2790: int len = strlen(tmp);
2791: for(int i = 0; i < len; i++) {
2792: key_buf_char->write(tmp[i]);
2793: key_buf_scan->write(0x00);
2794: }
2795: }
2796: } else if(data == 's') {
2797: stored_x = co.X;
2798: stored_y = co.Y;
2799: stored_a = wAttributes;
2800: } else if(data == 'u') {
2801: co.X = stored_x;
2802: co.Y = stored_y;
2803: wAttributes = stored_a;
2804: }
2805: }
2806: if(co.X < 0) {
2807: co.X = 0;
2808: } else if(co.X >= csbi.dwSize.X) {
2809: co.X = csbi.dwSize.X - 1;
2810: }
1.1.1.14 root 2811: if(co.Y < csbi.srWindow.Top) {
2812: co.Y = csbi.srWindow.Top;
2813: } else if(co.Y > csbi.srWindow.Bottom) {
2814: co.Y = csbi.srWindow.Bottom;
1.1 root 2815: }
2816: if(co.X != csbi.dwCursorPosition.X || co.Y != csbi.dwCursorPosition.Y) {
2817: SetConsoleCursorPosition(hStdout, co);
2818: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14 root 2819: mem[0x451 + mem[0x462] * 2] = co.Y - csbi.srWindow.Top;
1.1 root 2820: cursor_moved = false;
2821: }
2822: if(wAttributes != csbi.wAttributes) {
2823: SetConsoleTextAttribute(hStdout, wAttributes);
2824: }
2825: p = is_esc = 0;
2826: }
2827: return;
2828: } else {
2829: if(msdos_lead_byte_check(data)) {
2830: is_kanji = 1;
2831: return;
2832: } else if(data == 0x1b) {
2833: is_esc = 1;
2834: return;
2835: }
2836: }
1.1.1.20 root 2837:
2838: DWORD q = 0, num;
2839: is_kanji = 0;
2840: for(int i = 0; i < p; i++) {
2841: UINT8 c = tmp[i];
2842: if(is_kanji) {
2843: is_kanji = 0;
2844: } else if(msdos_lead_byte_check(data)) {
2845: is_kanji = 1;
2846: } else if(msdos_ctrl_code_check(data)) {
2847: out[q++] = '^';
2848: c += 'A' - 1;
2849: }
2850: out[q++] = c;
2851: }
2852: WriteConsole(hStdout, out, q, &num, NULL);
1.1 root 2853: p = 0;
1.1.1.14 root 2854:
1.1.1.15 root 2855: if(!restore_console_on_exit) {
2856: CONSOLE_SCREEN_BUFFER_INFO csbi;
2857: GetConsoleScreenBufferInfo(hStdout, &csbi);
2858: scr_top = csbi.srWindow.Top;
2859: }
1.1 root 2860: cursor_moved = true;
2861: }
2862:
2863: int msdos_aux_in()
2864: {
1.1.1.21 root 2865: msdos_stdio_reopen();
2866:
1.1.1.20 root 2867: process_t *process = msdos_process_info_get(current_psp);
2868: int fd = msdos_psp_get_file_table(3, current_psp);
2869:
2870: if(fd < process->max_files && file_handler[fd].valid && !eof(fd)) {
1.1 root 2871: char data = 0;
1.1.1.20 root 2872: _read(fd, &data, 1);
1.1 root 2873: return(data);
2874: } else {
2875: return(EOF);
2876: }
2877: }
2878:
2879: void msdos_aux_out(char data)
2880: {
1.1.1.21 root 2881: msdos_stdio_reopen();
2882:
1.1.1.20 root 2883: process_t *process = msdos_process_info_get(current_psp);
2884: int fd = msdos_psp_get_file_table(3, current_psp);
2885:
2886: if(fd < process->max_files && file_handler[fd].valid) {
2887: msdos_write(fd, &data, 1);
1.1 root 2888: }
2889: }
2890:
2891: void msdos_prn_out(char data)
2892: {
1.1.1.21 root 2893: msdos_stdio_reopen();
2894:
1.1.1.20 root 2895: process_t *process = msdos_process_info_get(current_psp);
2896: int fd = msdos_psp_get_file_table(4, current_psp);
2897:
2898: if(fd < process->max_files && file_handler[fd].valid) {
2899: msdos_write(fd, &data, 1);
1.1 root 2900: }
2901: }
2902:
2903: // memory control
2904:
1.1.1.19 root 2905: mcb_t *msdos_mcb_create(int mcb_seg, UINT8 mz, UINT16 psp, int paragraphs)
1.1 root 2906: {
2907: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2908:
2909: mcb->mz = mz;
2910: mcb->psp = psp;
1.1.1.19 root 2911: mcb->paragraphs32 = paragraphs;
1.1 root 2912: return(mcb);
2913: }
2914:
2915: void msdos_mcb_check(mcb_t *mcb)
2916: {
2917: if(!(mcb->mz == 'M' || mcb->mz == 'Z')) {
2918: fatalerror("broken mcb\n");
2919: }
2920: }
2921:
2922: int msdos_mem_split(int seg, int paragraphs)
2923: {
2924: int mcb_seg = seg - 1;
2925: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2926: msdos_mcb_check(mcb);
2927:
1.1.1.19 root 2928: if(mcb->paragraphs() > paragraphs) {
1.1 root 2929: int new_seg = mcb_seg + 1 + paragraphs;
1.1.1.19 root 2930: int new_paragraphs = mcb->paragraphs() - paragraphs - 1;
1.1 root 2931:
2932: msdos_mcb_create(new_seg, mcb->mz, 0, new_paragraphs);
2933: mcb->mz = 'M';
1.1.1.19 root 2934: mcb->paragraphs32 = paragraphs;
1.1 root 2935: return(0);
2936: }
2937: return(-1);
2938: }
2939:
2940: void msdos_mem_merge(int seg)
2941: {
2942: int mcb_seg = seg - 1;
2943: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2944: msdos_mcb_check(mcb);
2945:
2946: while(1) {
2947: if(mcb->mz == 'Z') {
2948: break;
2949: }
1.1.1.19 root 2950: int next_seg = mcb_seg + 1 + mcb->paragraphs();
1.1 root 2951: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
2952: msdos_mcb_check(next_mcb);
2953:
2954: if(next_mcb->psp != 0) {
2955: break;
2956: }
2957: mcb->mz = next_mcb->mz;
1.1.1.19 root 2958: mcb->paragraphs32 = mcb->paragraphs() + 1 + next_mcb->paragraphs();
1.1 root 2959: }
2960: }
2961:
1.1.1.8 root 2962: int msdos_mem_alloc(int mcb_seg, int paragraphs, int new_process)
1.1 root 2963: {
2964: while(1) {
2965: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2966:
1.1.1.14 root 2967: if(mcb->psp == 0) {
2968: msdos_mem_merge(mcb_seg + 1);
2969: } else {
2970: msdos_mcb_check(mcb);
2971: }
1.1.1.8 root 2972: if(!(new_process && mcb->mz != 'Z')) {
1.1.1.19 root 2973: if(mcb->psp == 0 && mcb->paragraphs() >= paragraphs) {
1.1 root 2974: msdos_mem_split(mcb_seg + 1, paragraphs);
2975: mcb->psp = current_psp;
2976: return(mcb_seg + 1);
2977: }
2978: }
2979: if(mcb->mz == 'Z') {
2980: break;
2981: }
1.1.1.19 root 2982: mcb_seg += 1 + mcb->paragraphs();
1.1 root 2983: }
2984: return(-1);
2985: }
2986:
2987: int msdos_mem_realloc(int seg, int paragraphs, int *max_paragraphs)
2988: {
2989: int mcb_seg = seg - 1;
2990: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2991: msdos_mcb_check(mcb);
1.1.1.19 root 2992: int current_paragraphs = mcb->paragraphs();
1.1 root 2993:
2994: msdos_mem_merge(seg);
1.1.1.19 root 2995: if(paragraphs > mcb->paragraphs()) {
1.1.1.14 root 2996: if(max_paragraphs) {
1.1.1.19 root 2997: *max_paragraphs = mcb->paragraphs();
1.1.1.14 root 2998: }
1.1 root 2999: msdos_mem_split(seg, current_paragraphs);
3000: return(-1);
3001: }
3002: msdos_mem_split(seg, paragraphs);
3003: return(0);
3004: }
3005:
3006: void msdos_mem_free(int seg)
3007: {
3008: int mcb_seg = seg - 1;
3009: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
3010: msdos_mcb_check(mcb);
3011:
3012: mcb->psp = 0;
3013: msdos_mem_merge(seg);
3014: }
3015:
1.1.1.8 root 3016: int msdos_mem_get_free(int mcb_seg, int new_process)
1.1 root 3017: {
3018: int max_paragraphs = 0;
3019:
3020: while(1) {
3021: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
3022: msdos_mcb_check(mcb);
3023:
1.1.1.8 root 3024: if(!(new_process && mcb->mz != 'Z')) {
1.1.1.19 root 3025: if(mcb->psp == 0 && mcb->paragraphs() > max_paragraphs) {
3026: max_paragraphs = mcb->paragraphs();
1.1 root 3027: }
3028: }
3029: if(mcb->mz == 'Z') {
3030: break;
3031: }
1.1.1.19 root 3032: mcb_seg += 1 + mcb->paragraphs();
1.1 root 3033: }
1.1.1.14 root 3034: return(max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs);
1.1 root 3035: }
3036:
1.1.1.8 root 3037: int msdos_mem_get_last_mcb(int mcb_seg, UINT16 psp)
3038: {
3039: int last_seg = -1;
3040:
3041: while(1) {
3042: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
3043: msdos_mcb_check(mcb);
3044:
1.1.1.14 root 3045: if(mcb->psp == psp) {
1.1.1.8 root 3046: last_seg = mcb_seg;
3047: }
1.1.1.14 root 3048: if(mcb->mz == 'Z') {
3049: break;
3050: }
1.1.1.19 root 3051: mcb_seg += 1 + mcb->paragraphs();
1.1.1.8 root 3052: }
3053: return(last_seg);
3054: }
3055:
1.1.1.19 root 3056: int msdos_mem_get_umb_linked()
3057: {
3058: int mcb_seg = first_mcb;
3059:
3060: while(1) {
3061: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
3062: msdos_mcb_check(mcb);
3063:
3064: if(mcb->mz == 'Z') {
3065: if(mcb_seg >= (UMB_TOP >> 4)) {
3066: return(-1);
3067: }
3068: break;
3069: }
3070: mcb_seg += 1 + mcb->paragraphs();
3071: }
3072: return(0);
3073: }
3074:
3075: int msdos_mem_link_umb()
3076: {
3077: int mcb_seg = first_mcb;
3078:
3079: while(1) {
3080: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
3081: msdos_mcb_check(mcb);
3082: mcb_seg += 1 + mcb->paragraphs();
3083:
3084: if(mcb->mz == 'Z') {
3085: if(mcb_seg == (MEMORY_END >> 4) - 1) {
3086: mcb->mz = 'M';
1.1.1.20 root 3087: ((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked |= 0x01;
1.1.1.19 root 3088: return(-1);
3089: }
3090: break;
3091: }
3092: }
3093: return(0);
3094: }
3095:
3096: int msdos_mem_unlink_umb()
3097: {
3098: int mcb_seg = first_mcb;
3099:
3100: while(1) {
3101: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
3102: msdos_mcb_check(mcb);
3103: mcb_seg += 1 + mcb->paragraphs();
3104:
3105: if(mcb->mz == 'Z') {
3106: break;
3107: } else {
3108: if(mcb_seg == (MEMORY_END >> 4) - 1) {
3109: mcb->mz = 'Z';
1.1.1.20 root 3110: ((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked &= ~0x01;
1.1.1.19 root 3111: return(-1);
3112: }
3113: }
3114: }
3115: return(0);
3116: }
3117:
1.1 root 3118: // environment
3119:
3120: void msdos_env_set_argv(int env_seg, char *argv)
3121: {
3122: char *dst = (char *)(mem + (env_seg << 4));
3123:
3124: while(1) {
3125: if(dst[0] == 0) {
3126: break;
3127: }
3128: dst += strlen(dst) + 1;
3129: }
3130: *dst++ = 0; // end of environment
3131: *dst++ = 1; // top of argv[0]
3132: *dst++ = 0;
3133: memcpy(dst, argv, strlen(argv));
3134: dst += strlen(argv);
3135: *dst++ = 0;
3136: *dst++ = 0;
3137: }
3138:
3139: char *msdos_env_get_argv(int env_seg)
3140: {
3141: static char env[ENV_SIZE];
3142: char *src = env;
3143:
3144: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
3145: while(1) {
3146: if(src[0] == 0) {
3147: if(src[1] == 1) {
3148: return(src + 3);
3149: }
3150: break;
3151: }
3152: src += strlen(src) + 1;
3153: }
3154: return(NULL);
3155: }
3156:
3157: char *msdos_env_get(int env_seg, const char *name)
3158: {
3159: static char env[ENV_SIZE];
3160: char *src = env;
3161:
3162: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
3163: while(1) {
3164: if(src[0] == 0) {
3165: break;
3166: }
3167: int len = strlen(src);
3168: char *n = my_strtok(src, "=");
3169: char *v = src + strlen(n) + 1;
3170:
3171: if(_stricmp(name, n) == 0) {
3172: return(v);
3173: }
3174: src += len + 1;
3175: }
3176: return(NULL);
3177: }
3178:
3179: void msdos_env_set(int env_seg, char *name, char *value)
3180: {
3181: char env[ENV_SIZE];
3182: char *src = env;
3183: char *dst = (char *)(mem + (env_seg << 4));
3184: char *argv = msdos_env_get_argv(env_seg);
3185: int done = 0;
3186:
3187: memcpy(src, dst, ENV_SIZE);
3188: memset(dst, 0, ENV_SIZE);
3189: while(1) {
3190: if(src[0] == 0) {
3191: break;
3192: }
3193: int len = strlen(src);
3194: char *n = my_strtok(src, "=");
3195: char *v = src + strlen(n) + 1;
3196: char tmp[1024];
3197:
3198: if(_stricmp(name, n) == 0) {
3199: sprintf(tmp, "%s=%s", n, value);
3200: done = 1;
3201: } else {
3202: sprintf(tmp, "%s=%s", n, v);
3203: }
3204: memcpy(dst, tmp, strlen(tmp));
3205: dst += strlen(tmp) + 1;
3206: src += len + 1;
3207: }
3208: if(!done) {
3209: char tmp[1024];
3210:
3211: sprintf(tmp, "%s=%s", name, value);
3212: memcpy(dst, tmp, strlen(tmp));
3213: dst += strlen(tmp) + 1;
3214: }
3215: if(argv) {
3216: *dst++ = 0; // end of environment
3217: *dst++ = 1; // top of argv[0]
3218: *dst++ = 0;
3219: memcpy(dst, argv, strlen(argv));
3220: dst += strlen(argv);
3221: *dst++ = 0;
3222: *dst++ = 0;
3223: }
3224: }
3225:
3226: // process
3227:
1.1.1.8 root 3228: psp_t *msdos_psp_create(int psp_seg, UINT16 mcb_seg, UINT16 parent_psp, UINT16 env_seg)
1.1 root 3229: {
3230: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
3231:
3232: memset(psp, 0, PSP_SIZE);
3233: psp->exit[0] = 0xcd;
3234: psp->exit[1] = 0x20;
1.1.1.8 root 3235: psp->first_mcb = mcb_seg;
1.1 root 3236: psp->far_call = 0xea;
3237: psp->cpm_entry.w.l = 0xfff1; // int 21h, retf
3238: psp->cpm_entry.w.h = 0xf000;
3239: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
3240: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
3241: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
3242: psp->parent_psp = parent_psp;
1.1.1.20 root 3243: if(parent_psp == (UINT16)-1) {
3244: for(int i = 0; i < 20; i++) {
3245: if(file_handler[i].valid) {
3246: psp->file_table[i] = i;
3247: } else {
3248: psp->file_table[i] = 0xff;
3249: }
1.1 root 3250: }
1.1.1.20 root 3251: } else {
3252: memcpy(psp->file_table, ((psp_t *)(mem + (parent_psp << 4)))->file_table, 20);
1.1 root 3253: }
3254: psp->env_seg = env_seg;
3255: psp->stack.w.l = REG16(SP);
1.1.1.3 root 3256: psp->stack.w.h = SREG(SS);
1.1.1.14 root 3257: psp->file_table_size = 20;
3258: psp->file_table_ptr.w.l = 0x18;
3259: psp->file_table_ptr.w.h = psp_seg;
1.1 root 3260: psp->service[0] = 0xcd;
3261: psp->service[1] = 0x21;
3262: psp->service[2] = 0xcb;
3263: return(psp);
3264: }
3265:
1.1.1.20 root 3266: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg)
3267: {
3268: if(psp_seg && fd < 20) {
3269: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
3270: psp->file_table[fd] = value;
3271: }
3272: }
3273:
3274: int msdos_psp_get_file_table(int fd, int psp_seg)
3275: {
3276: if(psp_seg && fd < 20) {
3277: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
3278: fd = psp->file_table[fd];
3279: }
3280: return fd;
3281: }
3282:
1.1 root 3283: int msdos_process_exec(char *cmd, param_block_t *param, UINT8 al)
3284: {
3285: // load command file
3286: int fd = -1;
3287: int dos_command = 0;
1.1.1.24 root 3288: char command[MAX_PATH], path[MAX_PATH], opt[MAX_PATH], *name = NULL, name_tmp[MAX_PATH];
1.1 root 3289:
3290: int opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
3291: int opt_len = mem[opt_ofs];
3292: memset(opt, 0, sizeof(opt));
3293: memcpy(opt, mem + opt_ofs + 1, opt_len);
3294:
1.1.1.14 root 3295: if(strlen(cmd) >= 5 && _stricmp(&cmd[strlen(cmd) - 4], ".BAT") == 0) {
3296: // this is a batch file, run command.com
3297: char tmp[MAX_PATH];
3298: if(opt_len != 0) {
3299: sprintf(tmp, "/C %s %s", cmd, opt);
3300: } else {
3301: sprintf(tmp, "/C %s", cmd);
3302: }
3303: strcpy(opt, tmp);
3304: opt_len = strlen(opt);
3305: mem[opt_ofs] = opt_len;
3306: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
3307: strcpy(command, comspec_path);
3308: strcpy(name_tmp, "COMMAND.COM");
3309: } else {
3310: if(_stricmp(cmd, "C:\\COMMAND.COM") == 0) {
3311: // redirect C:\COMMAND.COM to comspec_path
3312: strcpy(command, comspec_path);
3313: } else {
3314: strcpy(command, cmd);
3315: }
1.1.1.24 root 3316: if(GetFullPathName(command, MAX_PATH, path, &name) == 0) {
3317: return(-1);
3318: }
1.1.1.14 root 3319: memset(name_tmp, 0, sizeof(name_tmp));
3320: strcpy(name_tmp, name);
3321:
3322: // check command.com
3323: if(_stricmp(name, "COMMAND.COM") == 0 || _stricmp(name, "COMMAND") == 0) {
3324: if(opt_len == 0) {
3325: // process_t *current_process = msdos_process_info_get(current_psp);
3326: process_t *current_process = NULL;
3327: for(int i = 0; i < MAX_PROCESS; i++) {
3328: if(process[i].psp == current_psp) {
3329: current_process = &process[i];
3330: break;
3331: }
3332: }
3333: if(current_process != NULL) {
3334: param->cmd_line.dw = current_process->dta.dw;
3335: opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
3336: opt_len = mem[opt_ofs];
3337: memset(opt, 0, sizeof(opt));
3338: memcpy(opt, mem + opt_ofs + 1, opt_len);
3339: }
3340: }
3341: for(int i = 0; i < opt_len; i++) {
3342: if(opt[i] == ' ') {
3343: continue;
3344: }
3345: if(opt[i] == '/' && (opt[i + 1] == 'c' || opt[i + 1] == 'C') && opt[i + 2] == ' ') {
3346: for(int j = i + 3; j < opt_len; j++) {
3347: if(opt[j] == ' ') {
3348: continue;
3349: }
3350: char *token = my_strtok(opt + j, " ");
3351:
3352: if(strlen(token) >= 5 && _stricmp(&token[strlen(token) - 4], ".BAT") == 0) {
3353: // this is a batch file, okay to run command.com
3354: } else {
3355: // run program directly without command.com
3356: strcpy(command, token);
3357: char tmp[MAX_PATH];
3358: strcpy(tmp, token + strlen(token) + 1);
3359: strcpy(opt, tmp);
3360: opt_len = strlen(opt);
3361: mem[opt_ofs] = opt_len;
3362: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
3363: dos_command = 1;
3364: }
3365: break;
1.1 root 3366: }
3367: }
1.1.1.14 root 3368: break;
1.1 root 3369: }
3370: }
3371: }
3372:
3373: // load command file
3374: strcpy(path, command);
3375: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
3376: sprintf(path, "%s.COM", command);
3377: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
3378: sprintf(path, "%s.EXE", command);
3379: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
1.1.1.14 root 3380: sprintf(path, "%s.BAT", command);
3381: if(_access(path, 0) == 0) {
3382: // this is a batch file, run command.com
3383: char tmp[MAX_PATH];
3384: if(opt_len != 0) {
3385: sprintf(tmp, "/C %s %s", path, opt);
3386: } else {
3387: sprintf(tmp, "/C %s", path);
3388: }
3389: strcpy(opt, tmp);
3390: opt_len = strlen(opt);
3391: mem[opt_ofs] = opt_len;
3392: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
3393: strcpy(path, comspec_path);
3394: strcpy(name_tmp, "COMMAND.COM");
3395: fd = _open(path, _O_RDONLY | _O_BINARY);
3396: } else {
3397: // search path in parent environments
3398: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
3399: char *env = msdos_env_get(parent_psp->env_seg, "PATH");
3400: if(env != NULL) {
3401: char env_path[4096];
3402: strcpy(env_path, env);
3403: char *token = my_strtok(env_path, ";");
3404:
3405: while(token != NULL) {
3406: if(strlen(token) != 0) {
3407: sprintf(path, "%s", msdos_combine_path(token, command));
3408: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
3409: break;
3410: }
3411: sprintf(path, "%s.COM", msdos_combine_path(token, command));
3412: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
3413: break;
3414: }
3415: sprintf(path, "%s.EXE", msdos_combine_path(token, command));
3416: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
3417: break;
3418: }
3419: sprintf(path, "%s.BAT", msdos_combine_path(token, command));
3420: if(_access(path, 0) == 0) {
3421: // this is a batch file, run command.com
3422: char tmp[MAX_PATH];
3423: if(opt_len != 0) {
3424: sprintf(tmp, "/C %s %s", path, opt);
3425: } else {
3426: sprintf(tmp, "/C %s", path);
3427: }
3428: strcpy(opt, tmp);
3429: opt_len = strlen(opt);
3430: mem[opt_ofs] = opt_len;
3431: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
3432: strcpy(path, comspec_path);
3433: strcpy(name_tmp, "COMMAND.COM");
3434: fd = _open(path, _O_RDONLY | _O_BINARY);
3435: break;
3436: }
1.1.1.8 root 3437: }
1.1.1.14 root 3438: token = my_strtok(NULL, ";");
1.1 root 3439: }
3440: }
3441: }
3442: }
3443: }
3444: }
3445: if(fd == -1) {
3446: if(dos_command) {
3447: // may be dos command
3448: char tmp[MAX_PATH];
3449: sprintf(tmp, "%s %s", command, opt);
3450: system(tmp);
3451: return(0);
3452: } else {
3453: return(-1);
3454: }
3455: }
3456: _read(fd, file_buffer, sizeof(file_buffer));
3457: _close(fd);
3458:
3459: // copy environment
3460: int env_seg, psp_seg;
3461:
1.1.1.8 root 3462: if((env_seg = msdos_mem_alloc(first_mcb, ENV_SIZE >> 4, 1)) == -1) {
1.1 root 3463: return(-1);
3464: }
3465: if(param->env_seg == 0) {
3466: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
3467: memcpy(mem + (env_seg << 4), mem + (parent_psp->env_seg << 4), ENV_SIZE);
3468: } else {
3469: memcpy(mem + (env_seg << 4), mem + (param->env_seg << 4), ENV_SIZE);
3470: }
3471: msdos_env_set_argv(env_seg, msdos_short_full_path(path));
3472:
3473: // check exe header
3474: exe_header_t *header = (exe_header_t *)file_buffer;
1.1.1.8 root 3475: int paragraphs, free_paragraphs = msdos_mem_get_free(first_mcb, 1);
1.1 root 3476: UINT16 cs, ss, ip, sp;
3477:
3478: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
3479: // memory allocation
3480: int header_size = header->header_size * 16;
3481: int load_size = header->pages * 512 - header_size;
3482: if(header_size + load_size < 512) {
3483: load_size = 512 - header_size;
3484: }
3485: paragraphs = (PSP_SIZE + load_size) >> 4;
3486: if(paragraphs + header->min_alloc > free_paragraphs) {
3487: msdos_mem_free(env_seg);
3488: return(-1);
3489: }
3490: paragraphs += header->max_alloc ? header->max_alloc : header->min_alloc;
3491: if(paragraphs > free_paragraphs) {
3492: paragraphs = free_paragraphs;
3493: }
1.1.1.8 root 3494: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1 root 3495: msdos_mem_free(env_seg);
3496: return(-1);
3497: }
3498: // relocation
3499: int start_seg = psp_seg + (PSP_SIZE >> 4);
3500: for(int i = 0; i < header->relocations; i++) {
3501: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
3502: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
3503: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
3504: }
3505: memcpy(mem + (start_seg << 4), file_buffer + header_size, load_size);
3506: // segments
3507: cs = header->init_cs + start_seg;
3508: ss = header->init_ss + start_seg;
3509: ip = header->init_ip;
3510: sp = header->init_sp - 2; // for symdeb
3511: } else {
3512: // memory allocation
3513: paragraphs = free_paragraphs;
1.1.1.8 root 3514: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1 root 3515: msdos_mem_free(env_seg);
3516: return(-1);
3517: }
3518: int start_seg = psp_seg + (PSP_SIZE >> 4);
3519: memcpy(mem + (start_seg << 4), file_buffer, 0x10000 - PSP_SIZE);
3520: // segments
3521: cs = ss = psp_seg;
3522: ip = 0x100;
3523: sp = 0xfffe;
3524: }
3525:
3526: // create psp
1.1.1.3 root 3527: #if defined(HAS_I386)
3528: *(UINT16 *)(mem + 4 * 0x22 + 0) = m_eip;
3529: #else
3530: *(UINT16 *)(mem + 4 * 0x22 + 0) = m_pc - SREG_BASE(CS);
3531: #endif
3532: *(UINT16 *)(mem + 4 * 0x22 + 2) = SREG(CS);
1.1 root 3533: psp_t *psp = msdos_psp_create(psp_seg, psp_seg + paragraphs, current_psp, env_seg);
3534: memcpy(psp->fcb1, mem + (param->fcb1.w.h << 4) + param->fcb1.w.l, sizeof(psp->fcb1));
3535: memcpy(psp->fcb2, mem + (param->fcb2.w.h << 4) + param->fcb2.w.l, sizeof(psp->fcb2));
3536: memcpy(psp->buffer, mem + (param->cmd_line.w.h << 4) + param->cmd_line.w.l, sizeof(psp->buffer));
3537:
3538: mcb_t *mcb_env = (mcb_t *)(mem + ((env_seg - 1) << 4));
3539: mcb_t *mcb_psp = (mcb_t *)(mem + ((psp_seg - 1) << 4));
3540: mcb_psp->psp = mcb_env->psp = psp_seg;
3541:
1.1.1.4 root 3542: for(int i = 0; i < 8; i++) {
3543: if(name_tmp[i] == '.') {
3544: mcb_psp->prog_name[i] = '\0';
3545: break;
3546: } else if(i < 7 && msdos_lead_byte_check(name_tmp[i])) {
3547: mcb_psp->prog_name[i] = name_tmp[i];
3548: i++;
3549: mcb_psp->prog_name[i] = name_tmp[i];
3550: } else if(name_tmp[i] >= 'a' && name_tmp[i] <= 'z') {
3551: mcb_psp->prog_name[i] = name_tmp[i] - 'a' + 'A';
3552: } else {
3553: mcb_psp->prog_name[i] = name_tmp[i];
3554: }
3555: }
3556:
1.1 root 3557: // process info
3558: process_t *process = msdos_process_info_create(psp_seg);
3559: strcpy(process->module_dir, msdos_short_full_dir(path));
3560: process->dta.w.l = 0x80;
3561: process->dta.w.h = psp_seg;
3562: process->switchar = '/';
3563: process->max_files = 20;
3564: process->parent_int_10h_feh_called = int_10h_feh_called;
3565: process->parent_int_10h_ffh_called = int_10h_ffh_called;
1.1.1.14 root 3566: process->parent_ds = SREG(DS);
1.1 root 3567:
3568: current_psp = psp_seg;
1.1.1.23 root 3569: msdos_sda_update(current_psp);
1.1 root 3570:
3571: if(al == 0x00) {
3572: int_10h_feh_called = int_10h_ffh_called = false;
3573:
3574: // registers and segments
3575: REG16(AX) = REG16(BX) = 0x00;
3576: REG16(CX) = 0xff;
3577: REG16(DX) = psp_seg;
3578: REG16(SI) = ip;
3579: REG16(DI) = sp;
3580: REG16(SP) = sp;
1.1.1.3 root 3581: SREG(DS) = SREG(ES) = psp_seg;
3582: SREG(SS) = ss;
3583: i386_load_segment_descriptor(DS);
3584: i386_load_segment_descriptor(ES);
3585: i386_load_segment_descriptor(SS);
1.1 root 3586:
3587: *(UINT16 *)(mem + (ss << 4) + sp) = 0;
3588: i386_jmp_far(cs, ip);
3589: } else if(al == 0x01) {
3590: // copy ss:sp and cs:ip to param block
3591: param->sp = sp;
3592: param->ss = ss;
3593: param->ip = ip;
3594: param->cs = cs;
3595: }
3596: return(0);
3597: }
3598:
3599: void msdos_process_terminate(int psp_seg, int ret, int mem_free)
3600: {
3601: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
3602:
3603: *(UINT32 *)(mem + 4 * 0x22) = psp->int_22h.dw;
3604: *(UINT32 *)(mem + 4 * 0x23) = psp->int_23h.dw;
3605: *(UINT32 *)(mem + 4 * 0x24) = psp->int_24h.dw;
3606:
1.1.1.3 root 3607: SREG(SS) = psp->stack.w.h;
3608: i386_load_segment_descriptor(SS);
1.1 root 3609: REG16(SP) = psp->stack.w.l;
3610: i386_jmp_far(psp->int_22h.w.h, psp->int_22h.w.l);
3611:
3612: process_t *process = msdos_process_info_get(psp_seg);
3613: int_10h_feh_called = process->parent_int_10h_feh_called;
3614: int_10h_ffh_called = process->parent_int_10h_ffh_called;
1.1.1.14 root 3615: SREG(DS) = process->parent_ds;
3616: i386_load_segment_descriptor(DS);
1.1 root 3617:
3618: if(mem_free) {
1.1.1.8 root 3619: int mcb_seg;
3620: while((mcb_seg = msdos_mem_get_last_mcb(first_mcb, psp_seg)) != -1) {
3621: msdos_mem_free(mcb_seg + 1);
3622: }
3623: while((mcb_seg = msdos_mem_get_last_mcb(UMB_TOP >> 4, psp_seg)) != -1) {
3624: msdos_mem_free(mcb_seg + 1);
3625: }
1.1 root 3626:
3627: for(int i = 0; i < MAX_FILES; i++) {
3628: if(file_handler[i].valid && file_handler[i].psp == psp_seg) {
3629: _close(i);
1.1.1.20 root 3630: msdos_file_handler_close(i);
3631: msdos_psp_set_file_table(i, 0x0ff, psp_seg); // FIXME: consider duplicated file handles
1.1 root 3632: }
3633: }
1.1.1.13 root 3634: msdos_dta_info_free(psp_seg);
1.1 root 3635: }
1.1.1.14 root 3636: msdos_stdio_reopen();
1.1 root 3637:
3638: memset(process, 0, sizeof(process_t));
3639:
3640: current_psp = psp->parent_psp;
3641: retval = ret;
1.1.1.23 root 3642: msdos_sda_update(current_psp);
1.1 root 3643: }
3644:
3645: // drive
3646:
3647: int msdos_drive_param_block_update(int drive_num, UINT16 *seg, UINT16 *ofs, int force_update)
3648: {
3649: *seg = DPB_TOP >> 4;
3650: *ofs = sizeof(dpb_t) * drive_num;
3651: dpb_t *dpb = (dpb_t *)(mem + (*seg << 4) + *ofs);
3652:
3653: if(!force_update && dpb->free_clusters != 0) {
3654: return(dpb->bytes_per_sector ? 1 : 0);
3655: }
3656: memset(dpb, 0, sizeof(dpb_t));
3657:
3658: int res = 0;
3659: char dev[64];
3660: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num);
3661:
1.1.1.17 root 3662: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1.1 root 3663: if(hFile != INVALID_HANDLE_VALUE) {
3664: DISK_GEOMETRY geo;
3665: DWORD dwSize;
3666: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
3667: dpb->bytes_per_sector = (UINT16)geo.BytesPerSector;
3668: dpb->highest_sector_num = (UINT8)(geo.SectorsPerTrack - 1);
3669: dpb->highest_cluster_num = (UINT16)(geo.TracksPerCylinder * geo.Cylinders.QuadPart + 1);
1.1.1.14 root 3670: dpb->maximum_cluster_num = (UINT32)(geo.TracksPerCylinder * geo.Cylinders.QuadPart + 1);
1.1 root 3671: switch(geo.MediaType) {
3672: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K)
3673: dpb->media_type = 0xff;
3674: break;
3675: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K)
3676: dpb->media_type = 0xfe;
3677: break;
3678: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K)
3679: dpb->media_type = 0xfd;
3680: break;
3681: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K)
3682: dpb->media_type = 0xfc;
3683: break;
3684: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M)
3685: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5")
3686: dpb->media_type = 0xf9;
3687: break;
3688: case FixedMedia: // hard disk
3689: case RemovableMedia:
1.1.1.19 root 3690: case Unknown:
1.1 root 3691: dpb->media_type = 0xf8;
3692: break;
3693: default:
3694: dpb->media_type = 0xf0;
3695: break;
3696: }
3697: res = 1;
3698: }
3699: dpb->drive_num = drive_num;
3700: dpb->unit_num = drive_num;
3701: dpb->next_dpb_ofs = *ofs + sizeof(dpb_t);
3702: dpb->next_dpb_seg = *seg;
1.1.1.14 root 3703: dpb->info_sector = 0xffff;
3704: dpb->backup_boot_sector = 0xffff;
1.1 root 3705: dpb->free_clusters = 0xffff;
1.1.1.14 root 3706: dpb->free_search_cluster = 0xffffffff;
1.1 root 3707: CloseHandle(hFile);
3708: }
3709: return(res);
3710: }
3711:
3712: // pc bios
3713:
1.1.1.19 root 3714: UINT32 get_ticks_since_midnight(UINT32 cur_msec)
3715: {
3716: static unsigned __int64 start_msec_since_midnight = 0;
3717: static unsigned __int64 start_msec_since_hostboot = 0;
3718:
3719: if(start_msec_since_midnight == 0) {
3720: SYSTEMTIME time;
3721: GetLocalTime(&time);
3722: start_msec_since_midnight = ((time.wHour * 60 + time.wMinute) * 60 + time.wSecond) * 1000 + time.wMilliseconds;
3723: start_msec_since_hostboot = cur_msec;
3724: }
3725: unsigned __int64 msec = (start_msec_since_midnight + cur_msec - start_msec_since_hostboot) % (24 * 60 * 60 * 1000);
3726: unsigned __int64 tick = msec * 0x1800b0 / (24 * 60 * 60 * 1000);
3727: return (UINT32)tick;
3728: }
3729:
3730: void pcbios_update_daily_timer_counter(UINT32 cur_msec)
3731: {
3732: UINT32 prev_tick = *(UINT32 *)(mem + 0x46c);
3733: UINT32 next_tick = get_ticks_since_midnight(cur_msec);
3734:
3735: if(prev_tick > next_tick) {
3736: mem[0x470] = 1;
3737: }
3738: *(UINT32 *)(mem + 0x46c) = next_tick;
3739: }
3740:
1.1.1.14 root 3741: inline void pcbios_irq0()
3742: {
3743: //++*(UINT32 *)(mem + 0x46c);
1.1.1.19 root 3744: pcbios_update_daily_timer_counter(timeGetTime());
1.1.1.14 root 3745: }
3746:
1.1.1.16 root 3747: int pcbios_get_text_vram_address(int page)
1.1 root 3748: {
3749: if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 3750: return TEXT_VRAM_TOP;
1.1 root 3751: } else {
1.1.1.14 root 3752: return TEXT_VRAM_TOP + VIDEO_REGEN * (page % vram_pages);
1.1 root 3753: }
3754: }
3755:
1.1.1.16 root 3756: int pcbios_get_shadow_buffer_address(int page)
1.1 root 3757: {
1.1.1.14 root 3758: if(!int_10h_feh_called) {
1.1.1.16 root 3759: return pcbios_get_text_vram_address(page);
1.1.1.14 root 3760: } else if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 3761: return SHADOW_BUF_TOP;
3762: } else {
1.1.1.14 root 3763: return SHADOW_BUF_TOP + VIDEO_REGEN * (page % vram_pages);
1.1.1.8 root 3764: }
3765: }
3766:
1.1.1.16 root 3767: int pcbios_get_shadow_buffer_address(int page, int x, int y)
1.1.1.8 root 3768: {
1.1.1.16 root 3769: return pcbios_get_shadow_buffer_address(page) + (x + y * scr_width) * 2;
1.1 root 3770: }
3771:
1.1.1.16 root 3772: void pcbios_set_console_size(int width, int height, bool clr_screen)
1.1 root 3773: {
1.1.1.14 root 3774: // clear the existing screen, not just the new one
3775: int clr_height = max(height, scr_height);
3776:
1.1.1.16 root 3777: if(scr_width != width || scr_height != height) {
3778: change_console_size(width, height);
1.1.1.14 root 3779: }
3780: mem[0x462] = 0;
3781: *(UINT16 *)(mem + 0x44e) = 0;
3782:
1.1.1.16 root 3783: text_vram_top_address = pcbios_get_text_vram_address(0);
3784: text_vram_end_address = text_vram_top_address + width * height * 2;
3785: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(0);
3786: shadow_buffer_end_address = shadow_buffer_top_address + width * height * 2;
1.1 root 3787:
1.1.1.23 root 3788: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.16 root 3789: if(clr_screen) {
1.1.1.14 root 3790: for(int ofs = shadow_buffer_top_address; ofs < shadow_buffer_end_address;) {
3791: mem[ofs++] = 0x20;
3792: mem[ofs++] = 0x07;
3793: }
3794:
3795: EnterCriticalSection(&vram_crit_sect);
3796: for(int y = 0; y < clr_height; y++) {
3797: for(int x = 0; x < scr_width; x++) {
3798: SCR_BUF(y,x).Char.AsciiChar = ' ';
3799: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
1.1 root 3800: }
3801: }
3802: SMALL_RECT rect;
1.1.1.14 root 3803: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + clr_height - 1);
3804: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
3805: vram_length_char = vram_last_length_char = 0;
3806: vram_length_attr = vram_last_length_attr = 0;
3807: LeaveCriticalSection(&vram_crit_sect);
1.1 root 3808: }
1.1.1.14 root 3809: COORD co;
3810: co.X = 0;
3811: co.Y = scr_top;
3812: SetConsoleCursorPosition(hStdout, co);
3813: cursor_moved = true;
3814: SetConsoleTextAttribute(hStdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
1.1 root 3815: }
3816:
1.1.1.16 root 3817: inline void pcbios_int_10h_00h()
3818: {
3819: switch(REG8(AL) & 0x7f) {
3820: case 0x70: // v-text mode
3821: case 0x71: // extended cga v-text mode
3822: pcbios_set_console_size(scr_width, scr_height, !(REG8(AL) & 0x80));
3823: break;
3824: default:
3825: pcbios_set_console_size(80, 25, !(REG8(AL) & 0x80));
3826: break;
3827: }
3828: if(REG8(AL) & 0x80) {
3829: mem[0x487] |= 0x80;
3830: } else {
3831: mem[0x487] &= ~0x80;
3832: }
3833: mem[0x449] = REG8(AL) & 0x7f;
3834: }
3835:
1.1 root 3836: inline void pcbios_int_10h_01h()
3837: {
1.1.1.13 root 3838: mem[0x460] = REG8(CL);
3839: mem[0x461] = REG8(CH);
1.1.1.14 root 3840:
1.1.1.23 root 3841: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 3842: CONSOLE_CURSOR_INFO ci;
3843: GetConsoleCursorInfo(hStdout, &ci);
3844: // ci.bVisible = !(REG8(CH) & 0x60) && REG8(CH) <= REG8(CL);
3845: // if(ci.bVisible) {
3846: int lines = max(8, REG8(CL) + 1);
3847: ci.dwSize = (REG8(CL) - REG8(CH) + 1) * 100 / lines;
3848: // }
3849: SetConsoleCursorInfo(hStdout, &ci);
1.1 root 3850: }
3851:
3852: inline void pcbios_int_10h_02h()
3853: {
1.1.1.14 root 3854: // continuously setting the cursor effectively stops it blinking
3855: if(mem[0x462] == REG8(BH) && (REG8(DL) != mem[0x450 + REG8(BH) * 2] || REG8(DH) != mem[0x451 + REG8(BH) * 2])) {
1.1 root 3856: COORD co;
3857: co.X = REG8(DL);
1.1.1.14 root 3858: co.Y = REG8(DH) + scr_top;
3859:
3860: // some programs hide the cursor by moving it off screen
3861: static bool hidden = false;
1.1.1.23 root 3862: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 3863: CONSOLE_CURSOR_INFO ci;
3864: GetConsoleCursorInfo(hStdout, &ci);
3865:
3866: if(REG8(DH) >= scr_height || !SetConsoleCursorPosition(hStdout, co)) {
3867: if(ci.bVisible) {
3868: ci.bVisible = FALSE;
3869: // SetConsoleCursorInfo(hStdout, &ci);
3870: hidden = true;
3871: }
3872: } else if(hidden) {
3873: if(!ci.bVisible) {
3874: ci.bVisible = TRUE;
3875: // SetConsoleCursorInfo(hStdout, &ci);
3876: }
3877: hidden = false;
3878: }
1.1 root 3879: }
1.1.1.14 root 3880: mem[0x450 + (REG8(BH) % vram_pages) * 2] = REG8(DL);
3881: mem[0x451 + (REG8(BH) % vram_pages) * 2] = REG8(DH);
1.1 root 3882: }
3883:
3884: inline void pcbios_int_10h_03h()
3885: {
1.1.1.14 root 3886: REG8(DL) = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3887: REG8(DH) = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 3888: REG8(CL) = mem[0x460];
3889: REG8(CH) = mem[0x461];
3890: }
3891:
3892: inline void pcbios_int_10h_05h()
3893: {
1.1.1.14 root 3894: if(REG8(AL) >= vram_pages) {
3895: return;
3896: }
3897: if(mem[0x462] != REG8(AL)) {
3898: vram_flush();
3899:
1.1.1.23 root 3900: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 3901: SMALL_RECT rect;
1.1.1.14 root 3902: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
3903: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3904:
1.1.1.16 root 3905: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(mem[0x462]); y < scr_height; y++) {
1.1.1.14 root 3906: for(int x = 0; x < scr_width; x++) {
3907: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
3908: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 3909: }
3910: }
1.1.1.16 root 3911: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(REG8(AL)); y < scr_height; y++) {
1.1.1.14 root 3912: for(int x = 0; x < scr_width; x++) {
3913: SCR_BUF(y,x).Char.AsciiChar = mem[ofs++];
3914: SCR_BUF(y,x).Attributes = mem[ofs++];
1.1 root 3915: }
3916: }
1.1.1.14 root 3917: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3918:
3919: COORD co;
1.1.1.14 root 3920: co.X = mem[0x450 + REG8(AL) * 2];
3921: co.Y = mem[0x451 + REG8(AL) * 2] + scr_top;
3922: if(co.Y < scr_top + scr_height) {
3923: SetConsoleCursorPosition(hStdout, co);
3924: }
1.1 root 3925: }
1.1.1.14 root 3926: mem[0x462] = REG8(AL);
3927: *(UINT16 *)(mem + 0x44e) = REG8(AL) * VIDEO_REGEN;
3928: int regen = min(scr_width * scr_height * 2, 0x8000);
1.1.1.16 root 3929: text_vram_top_address = pcbios_get_text_vram_address(mem[0x462]);
1.1.1.14 root 3930: text_vram_end_address = text_vram_top_address + regen;
1.1.1.16 root 3931: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(mem[0x462]);
1.1.1.14 root 3932: shadow_buffer_end_address = shadow_buffer_top_address + regen;
1.1 root 3933: }
3934:
3935: inline void pcbios_int_10h_06h()
3936: {
1.1.1.14 root 3937: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
3938: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
3939: return;
3940: }
3941: vram_flush();
3942:
1.1.1.23 root 3943: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 3944: SMALL_RECT rect;
1.1.1.14 root 3945: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
3946: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
3947:
3948: int right = min(REG8(DL), scr_width - 1);
3949: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 3950:
3951: if(REG8(AL) == 0) {
1.1.1.14 root 3952: for(int y = REG8(CH); y <= bottom; y++) {
1.1.1.16 root 3953: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 3954: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
3955: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3956: }
3957: }
3958: } else {
1.1.1.14 root 3959: for(int y = REG8(CH), y2 = min(REG8(CH) + REG8(AL), bottom + 1); y <= bottom; y++, y2++) {
1.1.1.16 root 3960: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 3961: if(y2 <= bottom) {
3962: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 3963: } else {
1.1.1.14 root 3964: SCR_BUF(y,x).Char.AsciiChar = ' ';
3965: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3966: }
1.1.1.14 root 3967: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
3968: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 3969: }
3970: }
3971: }
1.1.1.14 root 3972: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3973: }
3974:
3975: inline void pcbios_int_10h_07h()
3976: {
1.1.1.14 root 3977: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
3978: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
3979: return;
3980: }
3981: vram_flush();
3982:
1.1.1.23 root 3983: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 3984: SMALL_RECT rect;
1.1.1.14 root 3985: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
3986: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
3987:
3988: int right = min(REG8(DL), scr_width - 1);
3989: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 3990:
3991: if(REG8(AL) == 0) {
1.1.1.14 root 3992: for(int y = REG8(CH); y <= bottom; y++) {
1.1.1.16 root 3993: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 3994: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
3995: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3996: }
3997: }
3998: } else {
1.1.1.14 root 3999: for(int y = bottom, y2 = max(REG8(CH) - 1, bottom - REG8(AL)); y >= REG8(CH); y--, y2--) {
1.1.1.16 root 4000: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 4001: if(y2 >= REG8(CH)) {
4002: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 4003: } else {
1.1.1.14 root 4004: SCR_BUF(y,x).Char.AsciiChar = ' ';
4005: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 4006: }
1.1.1.14 root 4007: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
4008: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 4009: }
4010: }
4011: }
1.1.1.14 root 4012: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 4013: }
4014:
4015: inline void pcbios_int_10h_08h()
4016: {
4017: COORD co;
4018: DWORD num;
4019:
1.1.1.14 root 4020: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
4021: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 4022:
4023: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 4024: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 4025: co.Y += scr_top;
4026: vram_flush();
1.1 root 4027: ReadConsoleOutputCharacter(hStdout, scr_char, 1, co, &num);
4028: ReadConsoleOutputAttribute(hStdout, scr_attr, 1, co, &num);
4029: REG8(AL) = scr_char[0];
4030: REG8(AH) = scr_attr[0];
4031: } else {
1.1.1.16 root 4032: REG16(AX) = *(UINT16 *)(mem + pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y));
1.1 root 4033: }
4034: }
4035:
4036: inline void pcbios_int_10h_09h()
4037: {
4038: COORD co;
4039:
1.1.1.14 root 4040: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
4041: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
4042:
1.1.1.16 root 4043: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
4044: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 4045:
4046: if(mem[0x462] == REG8(BH)) {
1.1.1.14 root 4047: EnterCriticalSection(&vram_crit_sect);
1.1.1.16 root 4048: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 4049: while(dest < end) {
4050: write_text_vram_char(dest - vram, REG8(AL));
4051: mem[dest++] = REG8(AL);
4052: write_text_vram_attr(dest - vram, REG8(BL));
4053: mem[dest++] = REG8(BL);
1.1 root 4054: }
1.1.1.14 root 4055: LeaveCriticalSection(&vram_crit_sect);
1.1 root 4056: } else {
1.1.1.14 root 4057: while(dest < end) {
1.1 root 4058: mem[dest++] = REG8(AL);
4059: mem[dest++] = REG8(BL);
4060: }
4061: }
4062: }
4063:
4064: inline void pcbios_int_10h_0ah()
4065: {
4066: COORD co;
4067:
1.1.1.14 root 4068: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
4069: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
4070:
1.1.1.16 root 4071: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
4072: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 4073:
4074: if(mem[0x462] == REG8(BH)) {
1.1.1.14 root 4075: EnterCriticalSection(&vram_crit_sect);
1.1.1.16 root 4076: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 4077: while(dest < end) {
4078: write_text_vram_char(dest - vram, REG8(AL));
4079: mem[dest++] = REG8(AL);
4080: dest++;
1.1 root 4081: }
1.1.1.14 root 4082: LeaveCriticalSection(&vram_crit_sect);
1.1 root 4083: } else {
1.1.1.14 root 4084: while(dest < end) {
1.1 root 4085: mem[dest++] = REG8(AL);
4086: dest++;
4087: }
4088: }
4089: }
4090:
4091: inline void pcbios_int_10h_0eh()
4092: {
1.1.1.14 root 4093: DWORD num;
4094: COORD co;
4095:
4096: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
4097: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
4098:
4099: if(REG8(AL) == 7) {
4100: //MessageBeep(-1);
4101: } else if(REG8(AL) == 8 || REG8(AL) == 10 || REG8(AL) == 13) {
4102: if(REG8(AL) == 10) {
4103: vram_flush();
4104: }
1.1.1.23 root 4105: WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ®8(AL), 1, &num, NULL);
1.1.1.14 root 4106: cursor_moved = true;
4107: } else {
1.1.1.16 root 4108: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
1.1.1.14 root 4109: if(mem[0x462] == REG8(BH)) {
4110: EnterCriticalSection(&vram_crit_sect);
1.1.1.16 root 4111: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 4112: write_text_vram_char(dest - vram, REG8(AL));
4113: LeaveCriticalSection(&vram_crit_sect);
4114:
1.1.1.23 root 4115: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 4116: if(++co.X == scr_width) {
4117: co.X = 0;
4118: if(++co.Y == scr_height) {
4119: vram_flush();
4120: WriteConsole(hStdout, "\n", 1, &num, NULL);
4121: cursor_moved = true;
4122: }
4123: }
4124: if(!cursor_moved) {
4125: co.Y += scr_top;
4126: SetConsoleCursorPosition(hStdout, co);
4127: cursor_moved = true;
4128: }
4129: }
4130: mem[dest] = REG8(AL);
4131: }
1.1 root 4132: }
4133:
4134: inline void pcbios_int_10h_0fh()
4135: {
4136: REG8(AL) = mem[0x449];
4137: REG8(AH) = mem[0x44a];
4138: REG8(BH) = mem[0x462];
4139: }
4140:
1.1.1.14 root 4141: inline void pcbios_int_10h_11h()
4142: {
4143: switch(REG8(AL)) {
1.1.1.16 root 4144: case 0x01:
1.1.1.14 root 4145: case 0x11:
1.1.1.16 root 4146: pcbios_set_console_size(80, 28, true);
1.1.1.14 root 4147: break;
1.1.1.16 root 4148: case 0x02:
1.1.1.14 root 4149: case 0x12:
1.1.1.16 root 4150: pcbios_set_console_size(80, 50, true);
1.1.1.14 root 4151: break;
1.1.1.16 root 4152: case 0x04:
1.1.1.14 root 4153: case 0x14:
1.1.1.16 root 4154: pcbios_set_console_size(80, 25, true);
4155: break;
4156: case 0x18:
4157: pcbios_set_console_size(80, 50, true);
1.1.1.14 root 4158: break;
4159: case 0x30:
4160: SREG(ES) = 0;
4161: i386_load_segment_descriptor(ES);
4162: REG16(BP) = 0;
4163: REG16(CX) = mem[0x485];
4164: REG8(DL) = mem[0x484];
4165: break;
4166: }
4167: }
4168:
4169: inline void pcbios_int_10h_12h()
4170: {
1.1.1.16 root 4171: switch(REG8(BL)) {
4172: case 0x10:
1.1.1.14 root 4173: REG16(BX) = 0x0003;
4174: REG16(CX) = 0x0009;
1.1.1.16 root 4175: break;
1.1.1.14 root 4176: }
4177: }
4178:
1.1 root 4179: inline void pcbios_int_10h_13h()
4180: {
1.1.1.3 root 4181: int ofs = SREG_BASE(ES) + REG16(BP);
1.1 root 4182: COORD co;
4183: DWORD num;
4184:
4185: co.X = REG8(DL);
1.1.1.14 root 4186: co.Y = REG8(DH) + scr_top;
4187:
4188: vram_flush();
1.1 root 4189:
4190: switch(REG8(AL)) {
4191: case 0x00:
4192: case 0x01:
4193: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 4194: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 4195: CONSOLE_SCREEN_BUFFER_INFO csbi;
4196: GetConsoleScreenBufferInfo(hStdout, &csbi);
4197: SetConsoleCursorPosition(hStdout, co);
4198:
4199: if(csbi.wAttributes != REG8(BL)) {
4200: SetConsoleTextAttribute(hStdout, REG8(BL));
4201: }
1.1.1.14 root 4202: WriteConsole(hStdout, &mem[ofs], REG16(CX), &num, NULL);
4203:
1.1 root 4204: if(csbi.wAttributes != REG8(BL)) {
4205: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
4206: }
4207: if(REG8(AL) == 0x00) {
1.1.1.15 root 4208: if(!restore_console_on_exit) {
4209: GetConsoleScreenBufferInfo(hStdout, &csbi);
4210: scr_top = csbi.srWindow.Top;
4211: }
1.1.1.14 root 4212: co.X = mem[0x450 + REG8(BH) * 2];
4213: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 4214: SetConsoleCursorPosition(hStdout, co);
4215: } else {
4216: cursor_moved = true;
4217: }
4218: } else {
1.1.1.3 root 4219: m_CF = 1;
1.1 root 4220: }
4221: break;
4222: case 0x02:
4223: case 0x03:
4224: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 4225: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 4226: CONSOLE_SCREEN_BUFFER_INFO csbi;
4227: GetConsoleScreenBufferInfo(hStdout, &csbi);
4228: SetConsoleCursorPosition(hStdout, co);
4229:
4230: WORD wAttributes = csbi.wAttributes;
4231: for(int i = 0; i < REG16(CX); i++, ofs += 2) {
4232: if(wAttributes != mem[ofs + 1]) {
4233: SetConsoleTextAttribute(hStdout, mem[ofs + 1]);
4234: wAttributes = mem[ofs + 1];
4235: }
1.1.1.14 root 4236: WriteConsole(hStdout, &mem[ofs], 1, &num, NULL);
1.1 root 4237: }
4238: if(csbi.wAttributes != wAttributes) {
4239: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
4240: }
4241: if(REG8(AL) == 0x02) {
1.1.1.14 root 4242: co.X = mem[0x450 + REG8(BH) * 2];
4243: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 4244: SetConsoleCursorPosition(hStdout, co);
4245: } else {
4246: cursor_moved = true;
4247: }
4248: } else {
1.1.1.3 root 4249: m_CF = 1;
1.1 root 4250: }
4251: break;
4252: case 0x10:
4253: case 0x11:
4254: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 4255: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 4256: ReadConsoleOutputCharacter(hStdout, scr_char, REG16(CX), co, &num);
4257: ReadConsoleOutputAttribute(hStdout, scr_attr, REG16(CX), co, &num);
4258: for(int i = 0; i < num; i++) {
4259: mem[ofs++] = scr_char[i];
4260: mem[ofs++] = scr_attr[i];
4261: if(REG8(AL) == 0x11) {
4262: mem[ofs++] = 0;
4263: mem[ofs++] = 0;
4264: }
4265: }
4266: } else {
1.1.1.16 root 4267: 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 4268: mem[ofs++] = mem[src++];
4269: mem[ofs++] = mem[src++];
4270: if(REG8(AL) == 0x11) {
4271: mem[ofs++] = 0;
4272: mem[ofs++] = 0;
4273: }
1.1.1.14 root 4274: if(++co.X == scr_width) {
4275: if(++co.Y == scr_height) {
1.1 root 4276: break;
4277: }
4278: co.X = 0;
4279: }
4280: }
4281: }
4282: break;
4283: case 0x20:
4284: case 0x21:
4285: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 4286: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 4287: int len = min(REG16(CX), scr_width * scr_height);
4288: for(int i = 0; i < len; i++) {
1.1 root 4289: scr_char[i] = mem[ofs++];
4290: scr_attr[i] = mem[ofs++];
4291: if(REG8(AL) == 0x21) {
4292: ofs += 2;
4293: }
4294: }
1.1.1.14 root 4295: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
4296: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 4297: } else {
1.1.1.16 root 4298: 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 4299: mem[dest++] = mem[ofs++];
4300: mem[dest++] = mem[ofs++];
4301: if(REG8(AL) == 0x21) {
4302: ofs += 2;
4303: }
1.1.1.14 root 4304: if(++co.X == scr_width) {
4305: if(++co.Y == scr_height) {
1.1 root 4306: break;
4307: }
4308: co.X = 0;
4309: }
4310: }
4311: }
4312: break;
4313: default:
1.1.1.22 root 4314: 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 4315: m_CF = 1;
1.1 root 4316: break;
4317: }
4318: }
4319:
1.1.1.14 root 4320: inline void pcbios_int_10h_1ah()
4321: {
4322: switch(REG8(AL)) {
4323: case 0x00:
4324: REG8(AL) = 0x1a;
4325: REG8(BL) = 0x08;
4326: REG8(BH) = 0x00;
4327: break;
4328: default:
1.1.1.22 root 4329: 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 4330: m_CF = 1;
4331: break;
4332: }
4333: }
4334:
1.1 root 4335: inline void pcbios_int_10h_1dh()
4336: {
4337: switch(REG8(AL)) {
4338: case 0x01:
4339: break;
4340: case 0x02:
4341: REG16(BX) = 0;
4342: break;
4343: default:
1.1.1.22 root 4344: 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));
4345: m_CF = 1;
4346: break;
4347: }
4348: }
4349:
4350: inline void pcbios_int_10h_4fh()
4351: {
4352: switch(REG8(AL)) {
4353: case 0x00:
4354: REG8(AH) = 0x02; // not supported
4355: break;
4356: case 0x01:
4357: case 0x02:
4358: case 0x03:
4359: case 0x04:
4360: case 0x05:
4361: case 0x06:
4362: case 0x07:
4363: case 0x08:
4364: case 0x09:
4365: case 0x0a:
4366: case 0x0b:
4367: case 0x0c:
4368: REG8(AH) = 0x01; // failed
4369: break;
4370: default:
4371: 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 4372: m_CF = 1;
1.1 root 4373: break;
4374: }
4375: }
4376:
4377: inline void pcbios_int_10h_82h()
4378: {
4379: static UINT8 mode = 0;
4380:
4381: switch(REG8(AL)) {
1.1.1.22 root 4382: case 0x00:
1.1 root 4383: if(REG8(BL) != 0xff) {
4384: mode = REG8(BL);
4385: }
4386: REG8(AL) = mode;
4387: break;
4388: default:
1.1.1.22 root 4389: 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 4390: m_CF = 1;
1.1 root 4391: break;
4392: }
4393: }
4394:
1.1.1.22 root 4395: inline void pcbios_int_10h_83h()
4396: {
4397: static UINT8 mode = 0;
4398:
4399: switch(REG8(AL)) {
4400: case 0x00:
4401: REG16(AX) = 0; // offset???
4402: SREG(ES) = (SHADOW_BUF_TOP >> 4);
4403: i386_load_segment_descriptor(ES);
4404: REG16(BX) = (SHADOW_BUF_TOP & 0x0f);
4405: break;
4406: default:
4407: 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));
4408: m_CF = 1;
4409: break;
4410: }
4411: }
4412:
4413: inline void pcbios_int_10h_90h()
4414: {
4415: REG8(AL) = mem[0x449];
4416: }
4417:
4418: inline void pcbios_int_10h_91h()
4419: {
4420: REG8(AL) = 0x04; // VGA
4421: }
4422:
4423: inline void pcbios_int_10h_efh()
4424: {
4425: REG16(DX) = 0xffff;
4426: }
4427:
1.1 root 4428: inline void pcbios_int_10h_feh()
4429: {
4430: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 4431: SREG(ES) = (SHADOW_BUF_TOP >> 4);
1.1.1.3 root 4432: i386_load_segment_descriptor(ES);
1.1.1.8 root 4433: REG16(DI) = (SHADOW_BUF_TOP & 0x0f);
1.1 root 4434: }
4435: int_10h_feh_called = true;
4436: }
4437:
4438: inline void pcbios_int_10h_ffh()
4439: {
4440: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.23 root 4441: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 4442: COORD co;
4443: DWORD num;
4444:
1.1.1.14 root 4445: vram_flush();
4446:
4447: co.X = (REG16(DI) >> 1) % scr_width;
4448: co.Y = (REG16(DI) >> 1) / scr_width;
1.1.1.16 root 4449: int ofs = pcbios_get_shadow_buffer_address(0, co.X, co.Y);
4450: int end = min(ofs + REG16(CX) * 2, pcbios_get_shadow_buffer_address(0, 0, scr_height));
1.1.1.14 root 4451: int len;
4452: for(len = 0; ofs < end; len++) {
4453: scr_char[len] = mem[ofs++];
4454: scr_attr[len] = mem[ofs++];
4455: }
4456: co.Y += scr_top;
4457: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
4458: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 4459: }
4460: int_10h_ffh_called = true;
4461: }
4462:
1.1.1.25 root 4463: inline void pcbios_int_14h_00h()
4464: {
4465: if(REG16(DX) < 2) {
4466: static const unsigned int rate[] = {110, 150, 300, 600, 1200, 2400, 4800, 9600};
4467: UINT8 selector = sio_read(REG16(DX), 3);
4468: selector &= ~0x3f;
4469: selector |= REG8(AL) & 0x1f;
4470: UINT16 divisor = 115200 / rate[REG8(AL) >> 5];
4471: sio_write(REG16(DX), 3, selector | 0x80);
4472: sio_write(REG16(DX), 0, divisor & 0xff);
4473: sio_write(REG16(DX), 1, divisor >> 8);
4474: sio_write(REG16(DX), 3, selector);
4475: REG8(AH) = sio_read(REG16(DX), 5);
4476: REG8(AL) = sio_read(REG16(DX), 6);
4477: } else {
4478: REG8(AH) = 0x80;
4479: }
4480: }
4481:
4482: inline void pcbios_int_14h_01h()
4483: {
4484: if(REG16(DX) < 2) {
4485: UINT8 selector = sio_read(REG16(DX), 3);
4486: sio_write(REG16(DX), 3, selector & ~0x80);
4487: sio_write(REG16(DX), 0, REG8(AL));
4488: sio_write(REG16(DX), 3, selector);
4489: REG8(AH) = sio_read(REG16(DX), 5);
4490: } else {
4491: REG8(AH) = 0x80;
4492: }
4493: }
4494:
4495: inline void pcbios_int_14h_02h()
4496: {
4497: if(REG16(DX) < 2) {
4498: UINT8 selector = sio_read(REG16(DX), 3);
4499: sio_write(REG16(DX), 3, selector & ~0x80);
4500: REG8(AL) = sio_read(REG16(DX), 0);
4501: sio_write(REG16(DX), 3, selector);
4502: REG8(AH) = sio_read(REG16(DX), 5);
4503: } else {
4504: REG8(AH) = 0x80;
4505: }
4506: }
4507:
4508: inline void pcbios_int_14h_03h()
4509: {
4510: if(REG16(DX) < 2) {
4511: REG8(AH) = sio_read(REG16(DX), 5);
4512: REG8(AL) = sio_read(REG16(DX), 6);
4513: } else {
4514: REG8(AH) = 0x80;
4515: }
4516: }
4517:
4518: inline void pcbios_int_14h_04h()
4519: {
4520: if(REG16(DX) < 2) {
4521: UINT8 selector = sio_read(REG16(DX), 3);
4522: if(REG8(CH) <= 0x03) {
4523: selector = (selector & ~0x03) | REG8(CH);
4524: }
4525: if(REG8(BL) == 0x00) {
4526: selector &= ~0x04;
4527: } else if(REG8(BL) == 0x01) {
4528: selector |= 0x04;
4529: }
4530: if(REG8(BH) == 0x00) {
4531: selector = (selector & ~0x38) | 0x00;
4532: } else if(REG8(BH) == 0x01) {
4533: selector = (selector & ~0x38) | 0x08;
4534: } else if(REG8(BH) == 0x02) {
4535: selector = (selector & ~0x38) | 0x18;
4536: } else if(REG8(BH) == 0x03) {
4537: selector = (selector & ~0x38) | 0x28;
4538: } else if(REG8(BH) == 0x04) {
4539: selector = (selector & ~0x38) | 0x38;
4540: }
4541: if(REG8(AL) == 0x00) {
4542: selector |= 0x40;
4543: } else if(REG8(AL) == 0x01) {
4544: selector &= ~0x40;
4545: }
4546: if(REG8(CL) <= 0x0b) {
4547: static const unsigned int rate[] = {110, 150, 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200};
4548: UINT16 divisor = 115200 / rate[REG8(CL)];
4549: sio_write(REG16(DX), 3, selector | 0x80);
4550: sio_write(REG16(DX), 0, divisor & 0xff);
4551: sio_write(REG16(DX), 1, divisor >> 8);
4552: }
4553: sio_write(REG16(DX), 3, selector);
4554: REG8(AH) = sio_read(REG16(DX), 5);
4555: REG8(AL) = sio_read(REG16(DX), 6);
4556: } else {
4557: REG8(AH) = 0x80;
4558: }
4559: }
4560:
4561: inline void pcbios_int_14h_05h()
4562: {
4563: if(REG16(DX) < 2) {
4564: if(REG8(AL) == 0x00) {
4565: REG8(BL) = sio_read(REG16(DX), 4);
4566: REG8(AH) = sio_read(REG16(DX), 5);
4567: REG8(AL) = sio_read(REG16(DX), 6);
4568: } else if(REG8(AL) == 0x01) {
4569: sio_write(REG16(DX), 4, REG8(BL));
4570: REG8(AH) = sio_read(REG16(DX), 5);
4571: REG8(AL) = sio_read(REG16(DX), 6);
4572: } else {
4573: unimplemented_14h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x14, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
4574: }
4575: } else {
4576: REG8(AH) = 0x80;
4577: }
4578: }
4579:
1.1.1.14 root 4580: inline void pcbios_int_15h_10h()
4581: {
1.1.1.22 root 4582: switch(REG8(AL)) {
4583: case 0x00:
1.1.1.14 root 4584: Sleep(10);
4585: hardware_update();
1.1.1.22 root 4586: break;
4587: default:
4588: 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 4589: REG8(AH) = 0x86;
4590: m_CF = 1;
4591: }
4592: }
4593:
1.1 root 4594: inline void pcbios_int_15h_23h()
4595: {
4596: switch(REG8(AL)) {
1.1.1.22 root 4597: case 0x00:
1.1.1.8 root 4598: REG8(CL) = cmos_read(0x2d);
4599: REG8(CH) = cmos_read(0x2e);
1.1 root 4600: break;
1.1.1.22 root 4601: case 0x01:
1.1.1.8 root 4602: cmos_write(0x2d, REG8(CL));
4603: cmos_write(0x2e, REG8(CH));
1.1 root 4604: break;
4605: default:
1.1.1.22 root 4606: 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 4607: REG8(AH) = 0x86;
1.1.1.3 root 4608: m_CF = 1;
1.1 root 4609: break;
4610: }
4611: }
4612:
4613: inline void pcbios_int_15h_24h()
4614: {
4615: switch(REG8(AL)) {
1.1.1.22 root 4616: case 0x00:
1.1.1.3 root 4617: i386_set_a20_line(0);
1.1 root 4618: REG8(AH) = 0;
4619: break;
1.1.1.22 root 4620: case 0x01:
1.1.1.3 root 4621: i386_set_a20_line(1);
1.1 root 4622: REG8(AH) = 0;
4623: break;
1.1.1.22 root 4624: case 0x02:
1.1 root 4625: REG8(AH) = 0;
1.1.1.3 root 4626: REG8(AL) = (m_a20_mask >> 20) & 1;
1.1 root 4627: REG16(CX) = 0;
4628: break;
1.1.1.22 root 4629: case 0x03:
1.1 root 4630: REG16(AX) = 0;
4631: REG16(BX) = 0;
4632: break;
1.1.1.22 root 4633: default:
4634: 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));
4635: REG8(AH) = 0x86;
4636: m_CF = 1;
4637: break;
1.1 root 4638: }
4639: }
4640:
4641: inline void pcbios_int_15h_49h()
4642: {
1.1.1.27! root 4643: REG8(AH) = 0x00;
! 4644: REG8(BL) = 0x00; // DOS/V
1.1 root 4645: }
4646:
1.1.1.22 root 4647: inline void pcbios_int_15h_50h()
4648: {
4649: switch(REG8(AL)) {
4650: case 0x00:
4651: case 0x01:
4652: if(REG8(BH) != 0x00 && REG8(BH) != 0x01) {
4653: REG8(AH) = 0x01; // invalid font type in bh
4654: m_CF = 1;
1.1.1.27! root 4655: } else if(REG8(BL) != 0x00) {
1.1.1.22 root 4656: REG8(AH) = 0x02; // bl not zero
4657: m_CF = 1;
4658: } else if(REG16(BP) != 0 && REG16(BP) != 437 && REG16(BP) != 932 && REG16(BP) != 934 && REG16(BP) != 936 && REG16(BP) != 938) {
4659: REG8(AH) = 0x04; // invalid code page
4660: m_CF = 1;
1.1.1.27! root 4661: } else if(REG8(AL) == 0x01) {
! 4662: REG8(AH) = 0x06; // font is read only
1.1.1.22 root 4663: m_CF = 1;
1.1.1.27! root 4664: } else {
! 4665: // dummy font read routine is at fffd:000d
! 4666: SREG(ES) = 0xfffd;
! 4667: i386_load_segment_descriptor(ES);
! 4668: REG16(BX) = 0x0d;
! 4669: REG8(AH) = 0x00; // success
1.1.1.22 root 4670: }
4671: break;
4672: default:
4673: 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));
4674: REG8(AH) = 0x86;
4675: m_CF = 1;
4676: break;
4677: }
4678: }
4679:
1.1 root 4680: inline void pcbios_int_15h_86h()
4681: {
4682: UINT32 usec = (REG16(CX) << 16) | REG16(DX);
1.1.1.14 root 4683: UINT32 msec = usec / 1000;
4684:
4685: while(msec) {
4686: UINT32 tmp = min(msec, 100);
4687: if(msec - tmp < 10) {
4688: tmp = msec;
4689: }
4690: Sleep(tmp);
4691:
4692: if(m_halted) {
4693: return;
4694: }
4695: msec -= tmp;
4696: }
1.1 root 4697: }
4698:
4699: inline void pcbios_int_15h_87h()
4700: {
4701: // copy extended memory (from DOSBox)
4702: int len = REG16(CX) * 2;
1.1.1.3 root 4703: int ofs = SREG_BASE(ES) + REG16(SI);
1.1 root 4704: int src = (*(UINT32 *)(mem + ofs + 0x12) & 0xffffff); // + (mem[ofs + 0x16] << 24);
4705: int dst = (*(UINT32 *)(mem + ofs + 0x1a) & 0xffffff); // + (mem[ofs + 0x1e] << 24);
4706: memcpy(mem + dst, mem + src, len);
4707: REG16(AX) = 0x00;
4708: }
4709:
4710: inline void pcbios_int_15h_88h()
4711: {
1.1.1.17 root 4712: REG16(AX) = ((min(MAX_MEM, 0x4000000) - 0x100000) >> 10);
1.1 root 4713: }
4714:
4715: inline void pcbios_int_15h_89h()
4716: {
1.1.1.21 root 4717: #if defined(HAS_I286) || defined(HAS_I386)
1.1 root 4718: // switch to protected mode (from DOSBox)
4719: write_io_byte(0x20, 0x10);
4720: write_io_byte(0x21, REG8(BH));
4721: write_io_byte(0x21, 0x00);
4722: write_io_byte(0xa0, 0x10);
4723: write_io_byte(0xa1, REG8(BL));
4724: write_io_byte(0xa1, 0x00);
1.1.1.3 root 4725: i386_set_a20_line(1);
4726: int ofs = SREG_BASE(ES) + REG16(SI);
4727: m_gdtr.limit = *(UINT16 *)(mem + ofs + 0x08);
4728: m_gdtr.base = *(UINT32 *)(mem + ofs + 0x08 + 0x02) & 0xffffff;
4729: m_idtr.limit = *(UINT16 *)(mem + ofs + 0x10);
4730: m_idtr.base = *(UINT32 *)(mem + ofs + 0x10 + 0x02) & 0xffffff;
4731: #if defined(HAS_I386)
4732: m_cr[0] |= 1;
4733: #else
4734: m_msw |= 1;
4735: #endif
4736: SREG(DS) = 0x18;
4737: SREG(ES) = 0x20;
4738: SREG(SS) = 0x28;
4739: i386_load_segment_descriptor(DS);
4740: i386_load_segment_descriptor(ES);
4741: i386_load_segment_descriptor(SS);
1.1.1.21 root 4742: UINT16 offset = *(UINT16 *)(mem + SREG_BASE(SS) + REG16(SP));
1.1 root 4743: REG16(SP) += 6;
1.1.1.3 root 4744: #if defined(HAS_I386)
1.1.1.21 root 4745: UINT32 flags = get_flags();
4746: flags &= (0x20000 | 0x40000 | 0x80000 | 0x100000 | 0x200000);
4747: set_flags(flags);
1.1.1.3 root 4748: #else
1.1.1.21 root 4749: UINT32 flags = CompressFlags();
4750: flags &= (0x20000 | 0x40000 | 0x80000 | 0x100000 | 0x200000);
4751: ExpandFlags(flags);
1.1.1.3 root 4752: #endif
1.1 root 4753: REG16(AX) = 0x00;
1.1.1.21 root 4754: i386_jmp_far(0x30, /*REG16(CX)*/offset);
1.1 root 4755: #else
1.1.1.21 root 4756: // i86/i186/v30: protected mode is not supported
1.1 root 4757: REG8(AH) = 0x86;
1.1.1.3 root 4758: m_CF = 1;
1.1 root 4759: #endif
4760: }
4761:
1.1.1.21 root 4762: inline void pcbios_int_15h_8ah()
4763: {
4764: UINT32 size = MAX_MEM - 0x100000;
4765: REG16(AX) = size & 0xffff;
4766: REG16(DX) = size >> 16;
4767: }
4768:
1.1.1.3 root 4769: #if defined(HAS_I386)
1.1 root 4770: inline void pcbios_int_15h_c9h()
4771: {
4772: REG8(AH) = 0x00;
4773: REG8(CH) = cpu_type;
4774: REG8(CL) = cpu_step;
4775: }
1.1.1.3 root 4776: #endif
1.1 root 4777:
4778: inline void pcbios_int_15h_cah()
4779: {
4780: switch(REG8(AL)) {
1.1.1.22 root 4781: case 0x00:
1.1 root 4782: if(REG8(BL) > 0x3f) {
4783: REG8(AH) = 0x03;
1.1.1.3 root 4784: m_CF = 1;
1.1 root 4785: } else if(REG8(BL) < 0x0e) {
4786: REG8(AH) = 0x04;
1.1.1.3 root 4787: m_CF = 1;
1.1 root 4788: } else {
1.1.1.8 root 4789: REG8(CL) = cmos_read(REG8(BL));
1.1 root 4790: }
4791: break;
1.1.1.22 root 4792: case 0x01:
1.1 root 4793: if(REG8(BL) > 0x3f) {
4794: REG8(AH) = 0x03;
1.1.1.3 root 4795: m_CF = 1;
1.1 root 4796: } else if(REG8(BL) < 0x0e) {
4797: REG8(AH) = 0x04;
1.1.1.3 root 4798: m_CF = 1;
1.1 root 4799: } else {
1.1.1.8 root 4800: cmos_write(REG8(BL), REG8(CL));
1.1 root 4801: }
4802: break;
4803: default:
1.1.1.22 root 4804: 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 4805: REG8(AH) = 0x86;
1.1.1.3 root 4806: m_CF = 1;
1.1 root 4807: break;
4808: }
4809: }
4810:
1.1.1.22 root 4811: inline void pcbios_int_15h_e8h()
1.1.1.17 root 4812: {
1.1.1.22 root 4813: switch(REG8(AL)) {
4814: #if defined(HAS_I386)
4815: case 0x01:
4816: REG16(AX) = REG16(CX) = ((min(MAX_MEM, 0x1000000) - 0x100000) >> 10);
4817: REG16(BX) = REG16(DX) = ((max(MAX_MEM, 0x1000000) - 0x1000000) >> 16);
4818: break;
1.1.1.17 root 4819: #endif
1.1.1.22 root 4820: default:
4821: 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));
4822: REG8(AH) = 0x86;
4823: m_CF = 1;
4824: break;
4825: }
4826: }
1.1.1.17 root 4827:
1.1.1.16 root 4828: UINT32 pcbios_get_key_code(bool clear_buffer)
1.1 root 4829: {
4830: UINT32 code = 0;
4831:
4832: if(key_buf_char->count() == 0) {
1.1.1.14 root 4833: if(!update_key_buffer()) {
4834: if(clear_buffer) {
4835: Sleep(10);
4836: } else {
4837: maybe_idle();
4838: }
4839: }
1.1 root 4840: }
4841: if(!clear_buffer) {
4842: key_buf_char->store_buffer();
4843: key_buf_scan->store_buffer();
4844: }
4845: if(key_buf_char->count() != 0) {
4846: code = key_buf_char->read() | (key_buf_scan->read() << 8);
4847: }
4848: if(key_buf_char->count() != 0) {
4849: code |= (key_buf_char->read() << 16) | (key_buf_scan->read() << 24);
4850: }
4851: if(!clear_buffer) {
4852: key_buf_char->restore_buffer();
4853: key_buf_scan->restore_buffer();
4854: }
4855: return code;
4856: }
4857:
4858: inline void pcbios_int_16h_00h()
4859: {
1.1.1.14 root 4860: while(key_code == 0 && !m_halted) {
1.1.1.16 root 4861: key_code = pcbios_get_key_code(true);
1.1 root 4862: }
4863: if((key_code & 0xffff) == 0x0000 || (key_code & 0xffff) == 0xe000) {
4864: if(REG8(AH) == 0x10) {
4865: key_code = ((key_code >> 8) & 0xff) | ((key_code >> 16) & 0xff00);
4866: } else {
4867: key_code = ((key_code >> 16) & 0xff00);
4868: }
4869: }
4870: REG16(AX) = key_code & 0xffff;
4871: key_code >>= 16;
4872: }
4873:
4874: inline void pcbios_int_16h_01h()
4875: {
1.1.1.5 root 4876: UINT32 key_code_tmp = key_code;
1.1 root 4877:
1.1.1.5 root 4878: if(key_code_tmp == 0) {
1.1.1.16 root 4879: key_code_tmp = pcbios_get_key_code(false);
1.1.1.5 root 4880: }
1.1.1.14 root 4881: if((key_code_tmp & 0xffff) == 0x0000 || (key_code_tmp & 0xffff) == 0xe000) {
4882: if(REG8(AH) == 0x11) {
4883: key_code_tmp = ((key_code_tmp >> 8) & 0xff) | ((key_code_tmp >> 16) & 0xff00);
4884: } else {
4885: key_code_tmp = ((key_code_tmp >> 16) & 0xff00);
1.1 root 4886: }
4887: }
1.1.1.5 root 4888: if(key_code_tmp != 0) {
4889: REG16(AX) = key_code_tmp & 0xffff;
1.1 root 4890: }
1.1.1.3 root 4891: #if defined(HAS_I386)
1.1.1.5 root 4892: m_ZF = (key_code_tmp == 0);
1.1.1.3 root 4893: #else
1.1.1.5 root 4894: m_ZeroVal = (key_code_tmp != 0);
1.1.1.3 root 4895: #endif
1.1 root 4896: }
4897:
4898: inline void pcbios_int_16h_02h()
4899: {
4900: REG8(AL) = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
4901: REG8(AL) |= (GetAsyncKeyState(VK_CAPITAL) & 0x0001) ? 0x40 : 0;
4902: REG8(AL) |= (GetAsyncKeyState(VK_NUMLOCK) & 0x0001) ? 0x20 : 0;
4903: REG8(AL) |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
4904: REG8(AL) |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
4905: REG8(AL) |= (GetAsyncKeyState(VK_CONTROL) & 0x8000) ? 0x04 : 0;
4906: REG8(AL) |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
4907: REG8(AL) |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
4908: }
4909:
4910: inline void pcbios_int_16h_03h()
4911: {
4912: static UINT16 status = 0;
4913:
4914: switch(REG8(AL)) {
4915: case 0x05:
4916: status = REG16(BX);
4917: break;
4918: case 0x06:
4919: REG16(BX) = status;
4920: break;
4921: default:
1.1.1.3 root 4922: m_CF = 1;
1.1 root 4923: break;
4924: }
4925: }
4926:
4927: inline void pcbios_int_16h_05h()
4928: {
1.1.1.14 root 4929: key_buf_char->write(REG8(CL));
4930: key_buf_scan->write(REG8(CH));
1.1 root 4931: REG8(AL) = 0x00;
4932: }
4933:
4934: inline void pcbios_int_16h_12h()
4935: {
4936: pcbios_int_16h_02h();
4937:
4938: REG8(AH) = 0;//(GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x80 : 0;
4939: REG8(AH) |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
4940: REG8(AH) |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
4941: REG8(AH) |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
4942: REG8(AH) |= (GetAsyncKeyState(VK_RMENU ) & 0x8000) ? 0x08 : 0;
4943: REG8(AH) |= (GetAsyncKeyState(VK_RCONTROL) & 0x8000) ? 0x04 : 0;
4944: REG8(AH) |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
4945: REG8(AH) |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
4946: }
4947:
4948: inline void pcbios_int_16h_13h()
4949: {
4950: static UINT16 status = 0;
4951:
4952: switch(REG8(AL)) {
4953: case 0x00:
4954: status = REG16(DX);
4955: break;
4956: case 0x01:
4957: REG16(DX) = status;
4958: break;
4959: default:
1.1.1.22 root 4960: 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 4961: m_CF = 1;
1.1 root 4962: break;
4963: }
4964: }
4965:
4966: inline void pcbios_int_16h_14h()
4967: {
4968: static UINT8 status = 0;
4969:
4970: switch(REG8(AL)) {
4971: case 0x00:
4972: case 0x01:
4973: status = REG8(AL);
4974: break;
4975: case 0x02:
4976: REG8(AL) = status;
4977: break;
4978: default:
1.1.1.22 root 4979: 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 4980: m_CF = 1;
1.1 root 4981: break;
4982: }
4983: }
4984:
1.1.1.24 root 4985: inline void pcbios_int_16h_55h()
4986: {
4987: switch(REG8(AL)) {
4988: case 0x00:
4989: // keyboard tsr is not present
4990: break;
4991: case 0xfe:
4992: // handlers for INT 08, INT 09, INT 16, INT 1B, and INT 1C are installed
4993: break;
4994: case 0xff:
4995: break;
4996: default:
4997: 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));
4998: m_CF = 1;
4999: break;
5000: }
5001: }
5002:
1.1 root 5003: inline void pcbios_int_1ah_00h()
5004: {
1.1.1.19 root 5005: pcbios_update_daily_timer_counter(timeGetTime());
5006: REG16(CX) = *(UINT16 *)(mem + 0x46e);
5007: REG16(DX) = *(UINT16 *)(mem + 0x46c);
5008: REG8(AL) = mem[0x470];
5009: mem[0x470] = 0;
1.1 root 5010: }
5011:
5012: inline int to_bcd(int t)
5013: {
5014: int u = (t % 100) / 10;
5015: return (u << 4) | (t % 10);
5016: }
5017:
5018: inline void pcbios_int_1ah_02h()
5019: {
5020: SYSTEMTIME time;
5021:
5022: GetLocalTime(&time);
5023: REG8(CH) = to_bcd(time.wHour);
5024: REG8(CL) = to_bcd(time.wMinute);
5025: REG8(DH) = to_bcd(time.wSecond);
5026: REG8(DL) = 0x00;
5027: }
5028:
5029: inline void pcbios_int_1ah_04h()
5030: {
5031: SYSTEMTIME time;
5032:
5033: GetLocalTime(&time);
5034: REG8(CH) = to_bcd(time.wYear / 100);
5035: REG8(CL) = to_bcd(time.wYear);
5036: REG8(DH) = to_bcd(time.wMonth);
5037: REG8(DL) = to_bcd(time.wDay);
5038: }
5039:
5040: inline void pcbios_int_1ah_0ah()
5041: {
5042: SYSTEMTIME time;
5043: FILETIME file_time;
5044: WORD dos_date, dos_time;
5045:
5046: GetLocalTime(&time);
5047: SystemTimeToFileTime(&time, &file_time);
5048: FileTimeToDosDateTime(&file_time, &dos_date, &dos_time);
5049: REG16(CX) = dos_date;
5050: }
5051:
5052: // msdos system call
5053:
5054: inline void msdos_int_21h_00h()
5055: {
1.1.1.3 root 5056: msdos_process_terminate(SREG(CS), retval, 1);
1.1 root 5057: }
5058:
5059: inline void msdos_int_21h_01h()
5060: {
5061: REG8(AL) = msdos_getche();
1.1.1.26 root 5062: ctrl_c_detected = ctrl_c_pressed;
5063:
1.1.1.8 root 5064: // some seconds may be passed in console
1.1 root 5065: hardware_update();
5066: }
5067:
5068: inline void msdos_int_21h_02h()
5069: {
5070: msdos_putch(REG8(DL));
1.1.1.26 root 5071: ctrl_c_detected = ctrl_c_pressed;
1.1 root 5072: }
5073:
5074: inline void msdos_int_21h_03h()
5075: {
5076: REG8(AL) = msdos_aux_in();
5077: }
5078:
5079: inline void msdos_int_21h_04h()
5080: {
5081: msdos_aux_out(REG8(DL));
5082: }
5083:
5084: inline void msdos_int_21h_05h()
5085: {
5086: msdos_prn_out(REG8(DL));
5087: }
5088:
5089: inline void msdos_int_21h_06h()
5090: {
5091: if(REG8(DL) == 0xff) {
5092: if(msdos_kbhit()) {
5093: REG8(AL) = msdos_getch();
1.1.1.3 root 5094: #if defined(HAS_I386)
5095: m_ZF = 0;
5096: #else
5097: m_ZeroVal = 1;
5098: #endif
1.1 root 5099: } else {
5100: REG8(AL) = 0;
1.1.1.3 root 5101: #if defined(HAS_I386)
5102: m_ZF = 1;
5103: #else
5104: m_ZeroVal = 0;
5105: #endif
1.1.1.14 root 5106: maybe_idle();
1.1 root 5107: }
5108: } else {
5109: msdos_putch(REG8(DL));
5110: }
5111: }
5112:
5113: inline void msdos_int_21h_07h()
5114: {
5115: REG8(AL) = msdos_getch();
1.1.1.26 root 5116:
1.1.1.8 root 5117: // some seconds may be passed in console
1.1 root 5118: hardware_update();
5119: }
5120:
5121: inline void msdos_int_21h_08h()
5122: {
5123: REG8(AL) = msdos_getch();
1.1.1.26 root 5124: ctrl_c_detected = ctrl_c_pressed;
5125:
1.1.1.8 root 5126: // some seconds may be passed in console
1.1 root 5127: hardware_update();
5128: }
5129:
5130: inline void msdos_int_21h_09h()
5131: {
1.1.1.21 root 5132: msdos_stdio_reopen();
5133:
1.1.1.20 root 5134: process_t *process = msdos_process_info_get(current_psp);
5135: int fd = msdos_psp_get_file_table(1, current_psp);
5136:
1.1.1.14 root 5137: char *str = (char *)(mem + SREG_BASE(DS) + REG16(DX));
5138: int len = 0;
1.1 root 5139:
1.1.1.14 root 5140: while(str[len] != '$' && len < 0x10000) {
5141: len++;
5142: }
1.1.1.20 root 5143: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 5144: // stdout is redirected to file
1.1.1.20 root 5145: msdos_write(fd, str, len);
1.1 root 5146: } else {
5147: for(int i = 0; i < len; i++) {
1.1.1.14 root 5148: msdos_putch(str[i]);
1.1 root 5149: }
5150: }
1.1.1.26 root 5151: ctrl_c_detected = ctrl_c_pressed;
1.1 root 5152: }
5153:
5154: inline void msdos_int_21h_0ah()
5155: {
1.1.1.3 root 5156: int ofs = SREG_BASE(DS) + REG16(DX);
1.1 root 5157: int max = mem[ofs] - 1;
5158: UINT8 *buf = mem + ofs + 2;
5159: int chr, p = 0;
5160:
5161: while((chr = msdos_getch()) != 0x0d) {
1.1.1.26 root 5162: if(ctrl_c_pressed) {
5163: p = 0;
5164: msdos_putch(chr);
5165: break;
5166: } else if(chr == 0x00) {
1.1 root 5167: // skip 2nd byte
5168: msdos_getch();
5169: } else if(chr == 0x08) {
5170: // back space
5171: if(p > 0) {
5172: p--;
1.1.1.20 root 5173: if(msdos_ctrl_code_check(buf[p])) {
5174: msdos_putch(chr);
5175: msdos_putch(chr);
5176: msdos_putch(' ');
5177: msdos_putch(' ');
5178: msdos_putch(chr);
5179: msdos_putch(chr);
5180: } else {
5181: msdos_putch(chr);
5182: msdos_putch(' ');
5183: msdos_putch(chr);
5184: }
1.1 root 5185: }
5186: } else if(p < max) {
5187: buf[p++] = chr;
5188: msdos_putch(chr);
5189: }
5190: }
5191: buf[p] = 0x0d;
5192: mem[ofs + 1] = p;
1.1.1.26 root 5193: ctrl_c_detected = ctrl_c_pressed;
5194:
1.1.1.8 root 5195: // some seconds may be passed in console
1.1 root 5196: hardware_update();
5197: }
5198:
5199: inline void msdos_int_21h_0bh()
5200: {
5201: if(msdos_kbhit()) {
5202: REG8(AL) = 0xff;
5203: } else {
5204: REG8(AL) = 0x00;
1.1.1.14 root 5205: maybe_idle();
1.1 root 5206: }
1.1.1.26 root 5207: ctrl_c_detected = ctrl_c_pressed;
1.1 root 5208: }
5209:
5210: inline void msdos_int_21h_0ch()
5211: {
5212: // clear key buffer
1.1.1.21 root 5213: msdos_stdio_reopen();
5214:
1.1.1.20 root 5215: process_t *process = msdos_process_info_get(current_psp);
5216: int fd = msdos_psp_get_file_table(0, current_psp);
5217:
5218: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 5219: // stdin is redirected to file
5220: } else {
5221: while(msdos_kbhit()) {
5222: msdos_getch();
5223: }
5224: }
5225:
5226: switch(REG8(AL)) {
5227: case 0x01:
5228: msdos_int_21h_01h();
5229: break;
5230: case 0x06:
5231: msdos_int_21h_06h();
5232: break;
5233: case 0x07:
5234: msdos_int_21h_07h();
5235: break;
5236: case 0x08:
5237: msdos_int_21h_08h();
5238: break;
5239: case 0x0a:
5240: msdos_int_21h_0ah();
5241: break;
5242: default:
1.1.1.22 root 5243: // 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));
5244: // REG16(AX) = 0x01;
5245: // m_CF = 1;
1.1 root 5246: break;
5247: }
5248: }
5249:
5250: inline void msdos_int_21h_0dh()
5251: {
5252: }
5253:
5254: inline void msdos_int_21h_0eh()
5255: {
5256: if(REG8(DL) < 26) {
5257: _chdrive(REG8(DL) + 1);
5258: msdos_cds_update(REG8(DL));
1.1.1.23 root 5259: msdos_sda_update(current_psp);
1.1 root 5260: }
5261: REG8(AL) = 26; // zdrive
5262: }
5263:
1.1.1.14 root 5264: inline void msdos_int_21h_0fh()
5265: {
5266: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5267: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5268: char *path = msdos_fcb_path(fcb);
5269: 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 5270:
1.1.1.14 root 5271: if(hFile == INVALID_HANDLE_VALUE) {
5272: REG8(AL) = 0xff;
5273: } else {
5274: REG8(AL) = 0;
5275: fcb->current_block = 0;
5276: fcb->record_size = 128;
5277: fcb->file_size = GetFileSize(hFile, NULL);
5278: fcb->handle = hFile;
5279: fcb->cur_record = 0;
5280: }
5281: }
5282:
5283: inline void msdos_int_21h_10h()
5284: {
5285: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5286: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5287:
5288: REG8(AL) = CloseHandle(fcb->handle) ? 0 : 0xff;
5289: }
5290:
1.1 root 5291: inline void msdos_int_21h_11h()
5292: {
1.1.1.3 root 5293: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5294: fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 5295:
5296: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 5297: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5298: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
5299: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 5300: char *path = msdos_fcb_path(fcb);
5301: WIN32_FIND_DATA fd;
5302:
1.1.1.13 root 5303: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
5304: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
5305: FindClose(dtainfo->find_handle);
5306: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 5307: }
5308: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 5309: dtainfo->allowable_mask = (ext_fcb->flag == 0xff) ? ext_fcb->attribute : 0x20;
5310: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 5311:
1.1.1.14 root 5312: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
5313: dtainfo->allowable_mask &= ~8;
1.1 root 5314: }
1.1.1.14 root 5315: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
5316: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 5317: !msdos_find_file_has_8dot3name(&fd)) {
5318: if(!FindNextFile(dtainfo->find_handle, &fd)) {
5319: FindClose(dtainfo->find_handle);
5320: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 5321: break;
5322: }
5323: }
5324: }
1.1.1.13 root 5325: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 5326: if(ext_fcb->flag == 0xff) {
5327: ext_find->flag = 0xff;
5328: memset(ext_find->reserved, 0, 5);
5329: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
5330: }
5331: find->drive = _getdrive();
1.1.1.13 root 5332: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 5333: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
5334: find->nt_res = 0;
5335: msdos_find_file_conv_local_time(&fd);
5336: find->create_time_ms = 0;
5337: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
5338: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
5339: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
5340: find->cluster_hi = find->cluster_lo = 0;
5341: find->file_size = fd.nFileSizeLow;
5342: REG8(AL) = 0x00;
1.1.1.14 root 5343: } else if(dtainfo->allowable_mask & 8) {
1.1 root 5344: if(ext_fcb->flag == 0xff) {
5345: ext_find->flag = 0xff;
5346: memset(ext_find->reserved, 0, 5);
5347: ext_find->attribute = 8;
5348: }
5349: find->drive = _getdrive();
5350: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
5351: find->attribute = 8;
5352: find->nt_res = 0;
5353: msdos_find_file_conv_local_time(&fd);
5354: find->create_time_ms = 0;
5355: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
5356: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
5357: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
5358: find->cluster_hi = find->cluster_lo = 0;
5359: find->file_size = 0;
1.1.1.14 root 5360: dtainfo->allowable_mask &= ~8;
1.1 root 5361: REG8(AL) = 0x00;
5362: } else {
5363: REG8(AL) = 0xff;
5364: }
5365: }
5366:
5367: inline void msdos_int_21h_12h()
5368: {
1.1.1.3 root 5369: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1.1.14 root 5370: // fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 5371:
5372: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 5373: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5374: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
5375: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 5376: WIN32_FIND_DATA fd;
5377:
1.1.1.13 root 5378: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
5379: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
5380: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 5381: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 5382: !msdos_find_file_has_8dot3name(&fd)) {
5383: if(!FindNextFile(dtainfo->find_handle, &fd)) {
5384: FindClose(dtainfo->find_handle);
5385: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 5386: break;
5387: }
5388: }
5389: } else {
1.1.1.13 root 5390: FindClose(dtainfo->find_handle);
5391: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 5392: }
5393: }
1.1.1.13 root 5394: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 5395: if(ext_fcb->flag == 0xff) {
5396: ext_find->flag = 0xff;
5397: memset(ext_find->reserved, 0, 5);
5398: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
5399: }
5400: find->drive = _getdrive();
1.1.1.13 root 5401: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 5402: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
5403: find->nt_res = 0;
5404: msdos_find_file_conv_local_time(&fd);
5405: find->create_time_ms = 0;
5406: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
5407: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
5408: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
5409: find->cluster_hi = find->cluster_lo = 0;
5410: find->file_size = fd.nFileSizeLow;
5411: REG8(AL) = 0x00;
1.1.1.14 root 5412: } else if(dtainfo->allowable_mask & 8) {
1.1 root 5413: if(ext_fcb->flag == 0xff) {
5414: ext_find->flag = 0xff;
5415: memset(ext_find->reserved, 0, 5);
5416: ext_find->attribute = 8;
5417: }
5418: find->drive = _getdrive();
5419: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
5420: find->attribute = 8;
5421: find->nt_res = 0;
5422: msdos_find_file_conv_local_time(&fd);
5423: find->create_time_ms = 0;
5424: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
5425: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
5426: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
5427: find->cluster_hi = find->cluster_lo = 0;
5428: find->file_size = 0;
1.1.1.14 root 5429: dtainfo->allowable_mask &= ~8;
1.1 root 5430: REG8(AL) = 0x00;
5431: } else {
5432: REG8(AL) = 0xff;
5433: }
5434: }
5435:
5436: inline void msdos_int_21h_13h()
5437: {
1.1.1.3 root 5438: if(remove(msdos_fcb_path((fcb_t *)(mem + SREG_BASE(DS) + REG16(DX))))) {
1.1 root 5439: REG8(AL) = 0xff;
5440: } else {
5441: REG8(AL) = 0x00;
5442: }
5443: }
5444:
1.1.1.16 root 5445: inline void msdos_int_21h_14h()
5446: {
5447: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5448: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5449: process_t *process = msdos_process_info_get(current_psp);
5450: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5451: DWORD num = 0;
5452:
5453: memset(mem + dta_laddr, 0, fcb->record_size);
5454: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
5455: REG8(AL) = 1;
5456: } else {
5457: UINT32 position = fcb->current_block * fcb->record_size + fcb->cur_record + num;
5458: fcb->current_block = (position & 0xffffff) / fcb->record_size;
5459: fcb->cur_record = (position & 0xffffff) % fcb->record_size;
5460: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
5461: }
5462: }
5463:
5464: inline void msdos_int_21h_15h()
1.1.1.14 root 5465: {
5466: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5467: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.16 root 5468: process_t *process = msdos_process_info_get(current_psp);
5469: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5470: DWORD num = 0;
1.1.1.14 root 5471:
1.1.1.16 root 5472: if(!WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
5473: REG8(AL) = 1;
5474: } else {
5475: fcb->file_size = GetFileSize(fcb->handle, NULL);
5476: UINT32 position = fcb->current_block * fcb->record_size + fcb->cur_record + num;
5477: fcb->current_block = (position & 0xffffff) / fcb->record_size;
5478: fcb->cur_record = (position & 0xffffff) % fcb->record_size;
5479: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
5480: }
5481: }
5482:
5483: inline void msdos_int_21h_16h()
5484: {
5485: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5486: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.14 root 5487: char *path = msdos_fcb_path(fcb);
5488: 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 5489:
1.1.1.14 root 5490: if(hFile == INVALID_HANDLE_VALUE) {
5491: REG8(AL) = 0xff;
5492: } else {
5493: REG8(AL) = 0;
5494: fcb->current_block = 0;
5495: fcb->record_size = 128;
5496: fcb->file_size = 0;
5497: fcb->handle = hFile;
5498: fcb->cur_record = 0;
5499: }
5500: }
5501:
1.1.1.16 root 5502: inline void msdos_int_21h_17h()
5503: {
5504: ext_fcb_t *ext_fcb_src = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5505: fcb_t *fcb_src = (fcb_t *)(ext_fcb_src + (ext_fcb_src->flag == 0xff ? 1 : 0));
5506: char *path_src = msdos_fcb_path(fcb_src);
5507: ext_fcb_t *ext_fcb_dst = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + 16);
5508: fcb_t *fcb_dst = (fcb_t *)(ext_fcb_dst + (ext_fcb_dst->flag == 0xff ? 1 : 0));
5509: char *path_dst = msdos_fcb_path(fcb_dst);
5510:
5511: if(rename(path_src, path_dst)) {
5512: REG8(AL) = 0xff;
5513: } else {
5514: REG8(AL) = 0;
5515: }
5516: }
5517:
1.1 root 5518: inline void msdos_int_21h_18h()
5519: {
5520: REG8(AL) = 0x00;
5521: }
5522:
5523: inline void msdos_int_21h_19h()
5524: {
5525: REG8(AL) = _getdrive() - 1;
5526: }
5527:
5528: inline void msdos_int_21h_1ah()
5529: {
5530: process_t *process = msdos_process_info_get(current_psp);
5531:
5532: process->dta.w.l = REG16(DX);
1.1.1.3 root 5533: process->dta.w.h = SREG(DS);
1.1.1.23 root 5534: msdos_sda_update(current_psp);
1.1 root 5535: }
5536:
5537: inline void msdos_int_21h_1bh()
5538: {
5539: int drive_num = _getdrive() - 1;
5540: UINT16 seg, ofs;
5541:
5542: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
5543: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
5544: REG8(AL) = dpb->highest_sector_num + 1;
5545: REG16(CX) = dpb->bytes_per_sector;
5546: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 5547: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 5548: } else {
5549: REG8(AL) = 0xff;
1.1.1.3 root 5550: m_CF = 1;
1.1 root 5551: }
5552:
5553: }
5554:
5555: inline void msdos_int_21h_1ch()
5556: {
5557: int drive_num = REG8(DL) ? (REG8(DL) - 1) : (_getdrive() - 1);
5558: UINT16 seg, ofs;
5559:
5560: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
5561: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
5562: REG8(AL) = dpb->highest_sector_num + 1;
5563: REG16(CX) = dpb->bytes_per_sector;
5564: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 5565: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 5566: } else {
5567: REG8(AL) = 0xff;
1.1.1.3 root 5568: m_CF = 1;
1.1 root 5569: }
5570:
5571: }
5572:
5573: inline void msdos_int_21h_1dh()
5574: {
5575: REG8(AL) = 0;
5576: }
5577:
5578: inline void msdos_int_21h_1eh()
5579: {
5580: REG8(AL) = 0;
5581: }
5582:
5583: inline void msdos_int_21h_1fh()
5584: {
5585: int drive_num = _getdrive() - 1;
5586: UINT16 seg, ofs;
5587:
5588: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
5589: REG8(AL) = 0;
1.1.1.3 root 5590: SREG(DS) = seg;
5591: i386_load_segment_descriptor(DS);
1.1 root 5592: REG16(BX) = ofs;
5593: } else {
5594: REG8(AL) = 0xff;
1.1.1.3 root 5595: m_CF = 1;
1.1 root 5596: }
5597: }
5598:
5599: inline void msdos_int_21h_20h()
5600: {
5601: REG8(AL) = 0;
5602: }
5603:
1.1.1.14 root 5604: inline void msdos_int_21h_21h()
5605: {
5606: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5607: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5608:
5609: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
5610: REG8(AL) = 1;
5611: } else {
5612: process_t *process = msdos_process_info_get(current_psp);
5613: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5614: memset(mem + dta_laddr, 0, fcb->record_size);
1.1.1.16 root 5615: DWORD num = 0;
1.1.1.14 root 5616: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
5617: REG8(AL) = 1;
5618: } else {
5619: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
5620: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
1.1.1.16 root 5621: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
1.1.1.14 root 5622: }
5623: }
5624: }
5625:
5626: inline void msdos_int_21h_22h()
5627: {
5628: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5629: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5630:
5631: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
5632: REG8(AL) = 0xff;
5633: } else {
5634: process_t *process = msdos_process_info_get(current_psp);
5635: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
1.1.1.16 root 5636: DWORD num = 0;
1.1.1.14 root 5637: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL);
5638: fcb->file_size = GetFileSize(fcb->handle, NULL);
5639: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
5640: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
1.1.1.16 root 5641: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
1.1.1.14 root 5642: }
5643: }
5644:
1.1.1.16 root 5645: inline void msdos_int_21h_23h()
5646: {
5647: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5648: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5649: char *path = msdos_fcb_path(fcb);
5650: HANDLE hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
5651:
5652: if(hFile == INVALID_HANDLE_VALUE) {
5653: REG8(AL) = 0xff;
5654: } else {
5655: UINT32 size = GetFileSize(hFile, NULL);
5656: fcb->rand_record = size / fcb->record_size + ((size % fcb->record_size) != 0);
5657: REG8(AL) = 0;
5658: }
5659: }
5660:
5661: inline void msdos_int_21h_24h()
5662: {
5663: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5664: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5665:
5666: fcb->rand_record = fcb->current_block * fcb->record_size + fcb->cur_record;
5667: }
5668:
1.1 root 5669: inline void msdos_int_21h_25h()
5670: {
5671: *(UINT16 *)(mem + 4 * REG8(AL) + 0) = REG16(DX);
1.1.1.3 root 5672: *(UINT16 *)(mem + 4 * REG8(AL) + 2) = SREG(DS);
1.1 root 5673: }
5674:
5675: inline void msdos_int_21h_26h()
5676: {
5677: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
5678:
5679: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
5680: psp->first_mcb = REG16(DX) + 16;
5681: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
5682: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
5683: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
5684: psp->parent_psp = 0;
5685: }
5686:
1.1.1.16 root 5687: inline void msdos_int_21h_27h()
5688: {
5689: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5690: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5691:
5692: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
5693: REG8(AL) = 1;
5694: } else {
5695: process_t *process = msdos_process_info_get(current_psp);
5696: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5697: memset(mem + dta_laddr, 0, fcb->record_size * REG16(CX));
5698: DWORD num = 0;
5699: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size * REG16(CX), &num, NULL) || num == 0) {
5700: REG8(AL) = 1;
5701: } else {
5702: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
5703: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
5704: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
5705: REG16(CX) = num / fcb->record_size + ((num % fcb->record_size) != 0);
5706: }
5707: }
5708: }
5709:
5710: inline void msdos_int_21h_28h()
5711: {
5712: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5713: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5714:
5715: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
5716: REG8(AL) = 0xff;
5717: } else {
5718: process_t *process = msdos_process_info_get(current_psp);
5719: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5720: DWORD num = 0;
5721: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size * REG16(CX), &num, NULL);
5722: fcb->file_size = GetFileSize(fcb->handle, NULL);
5723: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
5724: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
5725: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
5726: REG16(CX) = num / fcb->record_size + ((num % fcb->record_size) != 0);
5727: }
5728: }
5729:
1.1 root 5730: inline void msdos_int_21h_29h()
5731: {
1.1.1.20 root 5732: int ofs = 0;//SREG_BASE(DS) + REG16(SI);
5733: char buffer[1024], name[MAX_PATH], ext[MAX_PATH];
1.1 root 5734: UINT8 drv = 0;
5735: char sep_chars[] = ":.;,=+";
5736: char end_chars[] = "\\<>|/\"[]";
5737: char spc_chars[] = " \t";
5738:
1.1.1.20 root 5739: memcpy(buffer, mem + SREG_BASE(DS) + REG16(SI), 1023);
5740: buffer[1023] = 0;
5741: memset(name, 0x20, sizeof(name));
5742: memset(ext, 0x20, sizeof(ext));
5743:
1.1 root 5744: if(REG8(AL) & 1) {
1.1.1.20 root 5745: ofs += strspn((char *)(buffer + ofs), spc_chars);
5746: if(my_strchr(sep_chars, buffer[ofs]) && buffer[ofs] != '\0') {
1.1 root 5747: ofs++;
5748: }
5749: }
1.1.1.20 root 5750: ofs += strspn((char *)(buffer + ofs), spc_chars);
1.1 root 5751:
1.1.1.24 root 5752: if(buffer[ofs + 1] == ':') {
5753: if(buffer[ofs] >= 'a' && buffer[ofs] <= 'z') {
5754: drv = buffer[ofs] - 'a' + 1;
1.1.1.20 root 5755: ofs += 2;
1.1.1.24 root 5756: if(buffer[ofs] == '\\' || buffer[ofs] == '/') {
5757: ofs++;
5758: }
5759: } else if(buffer[ofs] >= 'A' && buffer[ofs] <= 'Z') {
5760: drv = buffer[ofs] - 'A' + 1;
1.1 root 5761: ofs += 2;
1.1.1.24 root 5762: if(buffer[ofs] == '\\' || buffer[ofs] == '/') {
5763: ofs++;
5764: }
1.1 root 5765: }
5766: }
1.1.1.20 root 5767: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) {
5768: UINT8 c = buffer[ofs];
5769: if(is_kanji) {
5770: is_kanji = 0;
5771: } else if(msdos_lead_byte_check(c)) {
5772: is_kanji = 1;
5773: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
1.1 root 5774: break;
5775: } else if(c >= 'a' && c <= 'z') {
5776: c -= 0x20;
5777: }
5778: ofs++;
5779: name[i] = c;
5780: }
1.1.1.20 root 5781: if(buffer[ofs] == '.') {
1.1 root 5782: ofs++;
1.1.1.20 root 5783: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) {
5784: UINT8 c = buffer[ofs];
5785: if(is_kanji) {
5786: is_kanji = 0;
5787: } else if(msdos_lead_byte_check(c)) {
5788: is_kanji = 1;
5789: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
1.1 root 5790: break;
5791: } else if(c >= 'a' && c <= 'z') {
5792: c -= 0x20;
5793: }
5794: ofs++;
5795: ext[i] = c;
5796: }
5797: }
1.1.1.20 root 5798: int si = REG16(SI) + ofs;
1.1.1.3 root 5799: int ds = SREG(DS);
1.1 root 5800: while(si > 0xffff) {
5801: si -= 0x10;
5802: ds++;
5803: }
5804: REG16(SI) = si;
1.1.1.3 root 5805: SREG(DS) = ds;
5806: i386_load_segment_descriptor(DS);
1.1 root 5807:
1.1.1.3 root 5808: UINT8 *fcb = mem + SREG_BASE(ES) + REG16(DI);
1.1.1.20 root 5809: if(!(REG8(AL) & 2) || drv != 0) {
5810: fcb[0] = drv;
5811: }
5812: if(!(REG8(AL) & 4) || name[0] != 0x20) {
5813: memcpy(fcb + 1, name, 8);
5814: }
5815: if(!(REG8(AL) & 8) || ext[0] != 0x20) {
5816: memcpy(fcb + 9, ext, 3);
5817: }
5818: for(int i = 1, found_star = 0; i < 1 + 8; i++) {
1.1 root 5819: if(fcb[i] == '*') {
5820: found_star = 1;
5821: }
5822: if(found_star) {
5823: fcb[i] = '?';
5824: }
5825: }
1.1.1.20 root 5826: for(int i = 9, found_star = 0; i < 9 + 3; i++) {
1.1 root 5827: if(fcb[i] == '*') {
5828: found_star = 1;
5829: }
5830: if(found_star) {
5831: fcb[i] = '?';
5832: }
5833: }
5834:
5835: if(drv == 0 || (drv > 0 && drv <= 26 && (GetLogicalDrives() & ( 1 << (drv - 1) )))) {
5836: if(memchr(fcb + 1, '?', 8 + 3)) {
5837: REG8(AL) = 0x01;
1.1.1.20 root 5838: } else {
5839: REG8(AL) = 0x00;
1.1 root 5840: }
5841: } else {
5842: REG8(AL) = 0xff;
5843: }
5844: }
5845:
5846: inline void msdos_int_21h_2ah()
5847: {
5848: SYSTEMTIME sTime;
5849:
5850: GetLocalTime(&sTime);
5851: REG16(CX) = sTime.wYear;
5852: REG8(DH) = (UINT8)sTime.wMonth;
5853: REG8(DL) = (UINT8)sTime.wDay;
5854: REG8(AL) = (UINT8)sTime.wDayOfWeek;
5855: }
5856:
5857: inline void msdos_int_21h_2bh()
5858: {
1.1.1.14 root 5859: REG8(AL) = 0xff;
1.1 root 5860: }
5861:
5862: inline void msdos_int_21h_2ch()
5863: {
5864: SYSTEMTIME sTime;
5865:
5866: GetLocalTime(&sTime);
5867: REG8(CH) = (UINT8)sTime.wHour;
5868: REG8(CL) = (UINT8)sTime.wMinute;
5869: REG8(DH) = (UINT8)sTime.wSecond;
1.1.1.14 root 5870: REG8(DL) = (UINT8)sTime.wMilliseconds / 10;
1.1 root 5871: }
5872:
5873: inline void msdos_int_21h_2dh()
5874: {
5875: REG8(AL) = 0x00;
5876: }
5877:
5878: inline void msdos_int_21h_2eh()
5879: {
5880: process_t *process = msdos_process_info_get(current_psp);
5881:
5882: process->verify = REG8(AL);
5883: }
5884:
5885: inline void msdos_int_21h_2fh()
5886: {
5887: process_t *process = msdos_process_info_get(current_psp);
5888:
5889: REG16(BX) = process->dta.w.l;
1.1.1.3 root 5890: SREG(ES) = process->dta.w.h;
5891: i386_load_segment_descriptor(ES);
1.1 root 5892: }
5893:
5894: inline void msdos_int_21h_30h()
5895: {
5896: // Version Flag / OEM
1.1.1.27! root 5897: if(REG8(AL) == 0x01) {
! 5898: REG16(BX) = 0x1000; // DOS is in HMA
1.1 root 5899: } else {
1.1.1.27! root 5900: // NOTE: EXDEB invites BL shows the machine type (0=PC-98, 1=PC/AT, 2=FMR),
! 5901: // but this is not correct on Windows 98 SE
! 5902: // REG16(BX) = 0xff01; // OEM = Microsoft, PC/AT
! 5903: REG16(BX) = 0xff00; // OEM = Microsoft
1.1 root 5904: }
1.1.1.27! root 5905: REG16(CX) = 0x0000;
1.1.1.9 root 5906: REG8(AL) = major_version; // 7
5907: REG8(AH) = minor_version; // 10
1.1 root 5908: }
5909:
5910: inline void msdos_int_21h_31h()
5911: {
1.1.1.14 root 5912: msdos_mem_realloc(current_psp, REG16(DX), NULL);
1.1 root 5913: msdos_process_terminate(current_psp, REG8(AL) | 0x300, 0);
5914: }
5915:
5916: inline void msdos_int_21h_32h()
5917: {
5918: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
5919: UINT16 seg, ofs;
5920:
5921: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
5922: REG8(AL) = 0;
1.1.1.3 root 5923: SREG(DS) = seg;
5924: i386_load_segment_descriptor(DS);
1.1 root 5925: REG16(BX) = ofs;
5926: } else {
5927: REG8(AL) = 0xff;
1.1.1.3 root 5928: m_CF = 1;
1.1 root 5929: }
5930: }
5931:
5932: inline void msdos_int_21h_33h()
5933: {
5934: char path[MAX_PATH];
5935:
5936: switch(REG8(AL)) {
5937: case 0x00:
1.1.1.26 root 5938: REG8(DL) = ctrl_c_checking;
1.1 root 5939: break;
5940: case 0x01:
1.1.1.26 root 5941: ctrl_c_checking = REG8(DL);
1.1 root 5942: break;
5943: case 0x05:
5944: GetSystemDirectory(path, MAX_PATH);
5945: if(path[0] >= 'a' && path[0] <= 'z') {
5946: REG8(DL) = path[0] - 'a' + 1;
5947: } else {
5948: REG8(DL) = path[0] - 'A' + 1;
5949: }
5950: break;
5951: case 0x06:
1.1.1.2 root 5952: // MS-DOS version (7.10)
1.1 root 5953: REG8(BL) = 7;
1.1.1.2 root 5954: REG8(BH) = 10;
1.1 root 5955: REG8(DL) = 0;
5956: REG8(DH) = 0x10; // in HMA
5957: break;
1.1.1.6 root 5958: case 0x07:
5959: if(REG8(DL) == 0) {
5960: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag &= ~0x20;
5961: } else if(REG8(DL) == 1) {
5962: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag |= 0x20;
5963: }
5964: break;
1.1 root 5965: default:
1.1.1.22 root 5966: 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 5967: REG16(AX) = 0x01;
1.1.1.3 root 5968: m_CF = 1;
1.1 root 5969: break;
5970: }
5971: }
5972:
1.1.1.23 root 5973: inline void msdos_int_21h_34h()
5974: {
5975: SREG(ES) = SDA_TOP >> 4;
5976: i386_load_segment_descriptor(ES);
5977: REG16(BX) = offsetof(sda_t, indos_flag);;
5978: }
5979:
1.1 root 5980: inline void msdos_int_21h_35h()
5981: {
5982: REG16(BX) = *(UINT16 *)(mem + 4 * REG8(AL) + 0);
1.1.1.3 root 5983: SREG(ES) = *(UINT16 *)(mem + 4 * REG8(AL) + 2);
5984: i386_load_segment_descriptor(ES);
1.1 root 5985: }
5986:
5987: inline void msdos_int_21h_36h()
5988: {
5989: struct _diskfree_t df = {0};
5990:
5991: if(_getdiskfree(REG8(DL), &df) == 0) {
5992: REG16(AX) = (UINT16)df.sectors_per_cluster;
5993: REG16(CX) = (UINT16)df.bytes_per_sector;
1.1.1.13 root 5994: REG16(BX) = df.avail_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.avail_clusters;
5995: REG16(DX) = df.total_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.total_clusters;
1.1 root 5996: } else {
5997: REG16(AX) = 0xffff;
5998: }
5999: }
6000:
6001: inline void msdos_int_21h_37h()
6002: {
1.1.1.22 root 6003: static UINT8 dev_flag = 0xff;
1.1 root 6004:
6005: switch(REG8(AL)) {
6006: case 0x00:
1.1.1.22 root 6007: {
6008: process_t *process = msdos_process_info_get(current_psp);
6009: REG8(AL) = 0x00;
6010: REG8(DL) = process->switchar;
6011: }
1.1 root 6012: break;
6013: case 0x01:
1.1.1.22 root 6014: {
6015: process_t *process = msdos_process_info_get(current_psp);
6016: REG8(AL) = 0x00;
6017: process->switchar = REG8(DL);
1.1.1.23 root 6018: msdos_sda_update(current_psp);
1.1.1.22 root 6019: }
6020: break;
6021: case 0x02:
6022: REG8(DL) = dev_flag;
6023: break;
6024: case 0x03:
6025: dev_flag = REG8(DL);
6026: break;
6027: case 0xd0:
6028: case 0xd1:
6029: case 0xd2:
6030: case 0xd3:
6031: case 0xd4:
6032: case 0xd5:
6033: case 0xd6:
6034: case 0xd7:
6035: case 0xdc:
6036: case 0xdd:
6037: case 0xde:
6038: case 0xdf:
6039: // diet ???
6040: REG16(AX) = 1;
1.1 root 6041: break;
6042: default:
1.1.1.22 root 6043: 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 6044: REG16(AX) = 1;
6045: break;
6046: }
6047: }
6048:
1.1.1.19 root 6049: int get_country_info(country_info_t *ci)
1.1.1.17 root 6050: {
6051: char LCdata[80];
6052:
1.1.1.19 root 6053: ZeroMemory(ci, offsetof(country_info_t, reserved));
1.1.1.17 root 6054: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRDIGITS, LCdata, sizeof(LCdata));
6055: ci->currency_dec_digits = atoi(LCdata);
6056: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRENCY, LCdata, sizeof(LCdata));
6057: ci->currency_format = *LCdata - '0';
6058: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDATE, LCdata, sizeof(LCdata));
6059: ci->date_format = *LCdata - '0';
6060: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SCURRENCY, LCdata, sizeof(LCdata));
6061: memcpy(&ci->currency_symbol, LCdata, 4);
6062: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDATE, LCdata, sizeof(LCdata));
6063: *ci->date_sep = *LCdata;
6064: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, LCdata, sizeof(LCdata));
6065: *ci->dec_sep = *LCdata;
6066: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SLIST, LCdata, sizeof(LCdata));
6067: *ci->list_sep = *LCdata;
6068: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, LCdata, sizeof(LCdata));
6069: *ci->thou_sep = *LCdata;
6070: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIME, LCdata, sizeof(LCdata));
6071: *ci->time_sep = *LCdata;
6072: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIMEFORMAT, LCdata, sizeof(LCdata));
6073: if(strchr(LCdata, 'H') != NULL) {
6074: ci->time_format = 1;
6075: }
1.1.1.27! root 6076: ci->case_map.w.l = 0x000a; // dummy case map routine is at fffd:000a
1.1.1.24 root 6077: ci->case_map.w.h = 0xfffd;
1.1.1.17 root 6078: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICOUNTRY, LCdata, sizeof(LCdata));
6079: return atoi(LCdata);
6080: }
6081:
1.1.1.14 root 6082: inline void msdos_int_21h_38h()
6083: {
6084: switch(REG8(AL)) {
6085: case 0x00:
1.1.1.19 root 6086: REG16(BX) = get_country_info((country_info_t *)(mem + SREG_BASE(DS) + REG16(DX)));
1.1.1.14 root 6087: break;
6088: default:
1.1.1.22 root 6089: 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 6090: REG16(AX) = 2;
6091: m_CF = 1;
6092: break;
6093: }
6094: }
6095:
1.1 root 6096: inline void msdos_int_21h_39h(int lfn)
6097: {
1.1.1.3 root 6098: if(_mkdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 6099: REG16(AX) = errno;
1.1.1.3 root 6100: m_CF = 1;
1.1 root 6101: }
6102: }
6103:
6104: inline void msdos_int_21h_3ah(int lfn)
6105: {
1.1.1.3 root 6106: if(_rmdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 6107: REG16(AX) = errno;
1.1.1.3 root 6108: m_CF = 1;
1.1 root 6109: }
6110: }
6111:
6112: inline void msdos_int_21h_3bh(int lfn)
6113: {
1.1.1.3 root 6114: if(_chdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1.1.17 root 6115: REG16(AX) = 3; // must be 3 (path not found)
1.1.1.3 root 6116: m_CF = 1;
1.1 root 6117: }
6118: }
6119:
6120: inline void msdos_int_21h_3ch()
6121: {
1.1.1.3 root 6122: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 6123: int attr = GetFileAttributes(path);
6124: int fd = -1;
1.1.1.11 root 6125: UINT16 info;
1.1 root 6126:
1.1.1.11 root 6127: if(msdos_is_con_path(path)) {
6128: fd = _open("CON", _O_WRONLY | _O_BINARY);
6129: info = 0x80d3;
1.1.1.14 root 6130: } else if(msdos_is_nul_path(path)) {
6131: fd = _open("NUL", _O_WRONLY | _O_BINARY);
6132: info = 0x80d3;
1.1.1.24 root 6133: } else if(msdos_is_driver_name(path)) {
1.1.1.20 root 6134: fd = _open("NUL", _O_WRONLY | _O_BINARY);
6135: info = 0x80d3;
1.1 root 6136: } else {
6137: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
1.1.1.11 root 6138: info = msdos_drive_number(path);
1.1 root 6139: }
6140: if(fd != -1) {
6141: if(attr == -1) {
6142: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
6143: }
6144: SetFileAttributes(path, attr);
6145: REG16(AX) = fd;
1.1.1.11 root 6146: msdos_file_handler_open(fd, path, _isatty(fd), 2, info, current_psp);
1.1.1.20 root 6147: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 6148: } else {
6149: REG16(AX) = errno;
1.1.1.3 root 6150: m_CF = 1;
1.1 root 6151: }
6152: }
6153:
6154: inline void msdos_int_21h_3dh()
6155: {
1.1.1.3 root 6156: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 6157: int mode = REG8(AL) & 0x03;
1.1.1.11 root 6158: int fd = -1;
6159: UINT16 info;
1.1 root 6160:
6161: if(mode < 0x03) {
1.1.1.11 root 6162: if(msdos_is_con_path(path)) {
1.1.1.13 root 6163: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 6164: info = 0x80d3;
1.1.1.14 root 6165: } else if(msdos_is_nul_path(path)) {
6166: fd = msdos_open("NUL", file_mode[mode].mode);
6167: info = 0x80d3;
1.1.1.24 root 6168: } else if(msdos_is_driver_name(path)) {
1.1.1.20 root 6169: fd = msdos_open("NUL", file_mode[mode].mode);
6170: info = 0x80d3;
1.1.1.11 root 6171: } else {
1.1.1.13 root 6172: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 6173: info = msdos_drive_number(path);
6174: }
1.1 root 6175: if(fd != -1) {
6176: REG16(AX) = fd;
1.1.1.11 root 6177: msdos_file_handler_open(fd, path, _isatty(fd), mode, info, current_psp);
1.1.1.20 root 6178: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 6179: } else {
6180: REG16(AX) = errno;
1.1.1.3 root 6181: m_CF = 1;
1.1 root 6182: }
6183: } else {
6184: REG16(AX) = 0x0c;
1.1.1.3 root 6185: m_CF = 1;
1.1 root 6186: }
6187: }
6188:
6189: inline void msdos_int_21h_3eh()
6190: {
6191: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 6192: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 6193:
1.1.1.20 root 6194: if(fd < process->max_files && file_handler[fd].valid) {
6195: _close(fd);
6196: msdos_file_handler_close(fd);
6197: msdos_psp_set_file_table(REG16(BX), 0x0ff, current_psp);
1.1 root 6198: } else {
6199: REG16(AX) = 0x06;
1.1.1.3 root 6200: m_CF = 1;
1.1 root 6201: }
6202: }
6203:
6204: inline void msdos_int_21h_3fh()
6205: {
6206: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 6207: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 6208:
1.1.1.20 root 6209: if(fd < process->max_files && file_handler[fd].valid) {
6210: if(file_mode[file_handler[fd].mode].in) {
6211: if(file_handler[fd].atty) {
1.1 root 6212: // BX is stdin or is redirected to stdin
1.1.1.3 root 6213: UINT8 *buf = mem + SREG_BASE(DS) + REG16(DX);
1.1 root 6214: int max = REG16(CX);
6215: int p = 0;
6216:
6217: while(max > p) {
6218: int chr = msdos_getch();
6219:
1.1.1.26 root 6220: if(ctrl_c_pressed) {
6221: p = 0;
6222: buf[p++] = 0x0d;
6223: if(max > p) {
6224: buf[p++] = 0x0a;
6225: }
6226: msdos_putch(chr);
6227: msdos_putch('\n');
6228: break;
6229: } else if(chr == 0x00) {
1.1 root 6230: // skip 2nd byte
6231: msdos_getch();
6232: } else if(chr == 0x0d) {
6233: // carriage return
6234: buf[p++] = 0x0d;
6235: if(max > p) {
6236: buf[p++] = 0x0a;
6237: }
1.1.1.14 root 6238: msdos_putch('\n');
1.1 root 6239: break;
6240: } else if(chr == 0x08) {
6241: // back space
6242: if(p > 0) {
6243: p--;
1.1.1.20 root 6244: if(msdos_ctrl_code_check(buf[p])) {
6245: msdos_putch(chr);
6246: msdos_putch(chr);
6247: msdos_putch(' ');
6248: msdos_putch(' ');
6249: msdos_putch(chr);
6250: msdos_putch(chr);
6251: } else {
6252: msdos_putch(chr);
6253: msdos_putch(' ');
6254: msdos_putch(chr);
6255: }
1.1 root 6256: }
6257: } else {
6258: buf[p++] = chr;
6259: msdos_putch(chr);
6260: }
6261: }
6262: REG16(AX) = p;
1.1.1.26 root 6263:
1.1.1.8 root 6264: // some seconds may be passed in console
1.1 root 6265: hardware_update();
6266: } else {
1.1.1.20 root 6267: REG16(AX) = _read(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 6268: }
6269: } else {
6270: REG16(AX) = 0x05;
1.1.1.3 root 6271: m_CF = 1;
1.1 root 6272: }
6273: } else {
6274: REG16(AX) = 0x06;
1.1.1.3 root 6275: m_CF = 1;
1.1 root 6276: }
6277: }
6278:
6279: inline void msdos_int_21h_40h()
6280: {
6281: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 6282: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 6283:
1.1.1.20 root 6284: if(fd < process->max_files && file_handler[fd].valid) {
6285: if(file_mode[file_handler[fd].mode].out) {
1.1 root 6286: if(REG16(CX)) {
1.1.1.20 root 6287: if(file_handler[fd].atty) {
1.1 root 6288: // BX is stdout/stderr or is redirected to stdout
6289: for(int i = 0; i < REG16(CX); i++) {
1.1.1.3 root 6290: msdos_putch(mem[SREG_BASE(DS) + REG16(DX) + i]);
1.1 root 6291: }
6292: REG16(AX) = REG16(CX);
6293: } else {
1.1.1.20 root 6294: REG16(AX) = msdos_write(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 6295: }
6296: } else {
1.1.1.20 root 6297: UINT32 pos = _tell(fd);
6298: _lseek(fd, 0, SEEK_END);
6299: UINT32 size = _tell(fd);
1.1.1.12 root 6300: if(pos < size) {
1.1.1.20 root 6301: _lseek(fd, pos, SEEK_SET);
6302: SetEndOfFile((HANDLE)_get_osfhandle(fd));
1.1.1.12 root 6303: } else {
6304: for(UINT32 i = size; i < pos; i++) {
6305: UINT8 tmp = 0;
1.1.1.23 root 6306: msdos_write(fd, &tmp, 1);
1.1.1.12 root 6307: }
1.1.1.20 root 6308: _lseek(fd, pos, SEEK_SET);
1.1 root 6309: }
1.1.1.23 root 6310: REG16(AX) = 0;
1.1 root 6311: }
6312: } else {
6313: REG16(AX) = 0x05;
1.1.1.3 root 6314: m_CF = 1;
1.1 root 6315: }
6316: } else {
6317: REG16(AX) = 0x06;
1.1.1.3 root 6318: m_CF = 1;
1.1 root 6319: }
6320: }
6321:
6322: inline void msdos_int_21h_41h(int lfn)
6323: {
1.1.1.3 root 6324: if(remove(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 6325: REG16(AX) = errno;
1.1.1.3 root 6326: m_CF = 1;
1.1 root 6327: }
6328: }
6329:
6330: inline void msdos_int_21h_42h()
6331: {
6332: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 6333: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 6334:
1.1.1.20 root 6335: if(fd < process->max_files && file_handler[fd].valid) {
1.1 root 6336: if(REG8(AL) < 0x03) {
6337: static int ptrname[] = { SEEK_SET, SEEK_CUR, SEEK_END };
1.1.1.20 root 6338: _lseek(fd, (REG16(CX) << 16) | REG16(DX), ptrname[REG8(AL)]);
6339: UINT32 pos = _tell(fd);
1.1 root 6340: REG16(AX) = pos & 0xffff;
6341: REG16(DX) = (pos >> 16);
6342: } else {
6343: REG16(AX) = 0x01;
1.1.1.3 root 6344: m_CF = 1;
1.1 root 6345: }
6346: } else {
6347: REG16(AX) = 0x06;
1.1.1.3 root 6348: m_CF = 1;
1.1 root 6349: }
6350: }
6351:
6352: inline void msdos_int_21h_43h(int lfn)
6353: {
1.1.1.3 root 6354: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn);
1.1 root 6355: int attr;
6356:
1.1.1.14 root 6357: if(!lfn && REG8(AL) > 2) {
6358: REG16(AX) = 0x01;
6359: m_CF = 1;
6360: return;
6361: }
6362: switch(REG8(lfn ? BL : AL)) {
1.1 root 6363: case 0x00:
6364: if((attr = GetFileAttributes(path)) != -1) {
1.1.1.14 root 6365: REG16(CX) = (UINT16)msdos_file_attribute_create((UINT16)attr);
6366: } else {
6367: REG16(AX) = (UINT16)GetLastError();
6368: m_CF = 1;
6369: }
6370: break;
6371: case 0x01:
6372: if(!SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)))) {
6373: REG16(AX) = (UINT16)GetLastError();
6374: m_CF = 1;
6375: }
6376: break;
6377: case 0x02:
6378: {
6379: DWORD size = GetCompressedFileSize(path, NULL);
6380: if(size != INVALID_FILE_SIZE) {
6381: if(size != 0 && size == GetFileSize(path, NULL)) {
6382: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
6383: // this isn't correct if the file is in the NTFS MFT
6384: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
6385: size = ((size - 1) | (sectors_per_cluster * bytes_per_sector - 1)) + 1;
6386: }
6387: }
6388: REG16(AX) = LOWORD(size);
6389: REG16(DX) = HIWORD(size);
6390: } else {
6391: REG16(AX) = (UINT16)GetLastError();
6392: m_CF = 1;
1.1 root 6393: }
1.1.1.14 root 6394: }
6395: break;
6396: case 0x03:
6397: case 0x05:
6398: case 0x07:
6399: {
6400: HANDLE hFile = CreateFile(path, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
6401: if(hFile != INVALID_HANDLE_VALUE) {
6402: FILETIME local, time;
6403: DosDateTimeToFileTime(REG16(DI), /*REG8(BL) == 5 ? 0 : */REG16(CX), &local);
6404: if(REG8(BL) == 7) {
6405: ULARGE_INTEGER hund;
6406: hund.LowPart = local.dwLowDateTime;
6407: hund.HighPart = local.dwHighDateTime;
6408: hund.QuadPart += REG16(SI) * 100000;
6409: local.dwLowDateTime = hund.LowPart;
6410: local.dwHighDateTime = hund.HighPart;
6411: }
6412: LocalFileTimeToFileTime(&local, &time);
6413: if(!SetFileTime(hFile, REG8(BL) == 0x07 ? &time : NULL,
6414: REG8(BL) == 0x05 ? &time : NULL,
6415: REG8(BL) == 0x03 ? &time : NULL)) {
6416: REG16(AX) = (UINT16)GetLastError();
6417: m_CF = 1;
6418: }
6419: CloseHandle(hFile);
6420: } else {
6421: REG16(AX) = (UINT16)GetLastError();
6422: m_CF = 1;
1.1 root 6423: }
1.1.1.14 root 6424: }
6425: break;
6426: case 0x04:
6427: case 0x06:
6428: case 0x08:
6429: {
6430: WIN32_FILE_ATTRIBUTE_DATA fad;
6431: if(GetFileAttributesEx(path, GetFileExInfoStandard, (LPVOID)&fad)) {
6432: FILETIME *time, local;
6433: time = REG8(BL) == 0x04 ? &fad.ftLastWriteTime :
6434: 0x06 ? &fad.ftLastAccessTime :
6435: &fad.ftCreationTime;
6436: FileTimeToLocalFileTime(time, &local);
6437: FileTimeToDosDateTime(&local, ®16(DI), ®16(CX));
6438: if(REG8(BL) == 0x08) {
6439: ULARGE_INTEGER hund;
6440: hund.LowPart = local.dwLowDateTime;
6441: hund.HighPart = local.dwHighDateTime;
6442: hund.QuadPart /= 100000;
6443: REG16(SI) = (UINT16)(hund.QuadPart % 200);
6444: }
6445: } else {
6446: REG16(AX) = (UINT16)GetLastError();
6447: m_CF = 1;
1.1 root 6448: }
1.1.1.14 root 6449: }
6450: break;
6451: default:
1.1.1.22 root 6452: 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 6453: REG16(AX) = 0x01;
6454: m_CF = 1;
6455: break;
6456: }
6457: }
6458:
6459: inline void msdos_int_21h_44h()
6460: {
1.1.1.22 root 6461: static UINT16 iteration_count = 0;
6462:
1.1.1.20 root 6463: process_t *process = msdos_process_info_get(current_psp);
6464: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
6465:
1.1.1.14 root 6466: UINT32 val = DRIVE_NO_ROOT_DIR;
6467:
6468: switch(REG8(AL)) {
6469: case 0x00:
6470: case 0x01:
6471: case 0x02:
6472: case 0x03:
6473: case 0x04:
6474: case 0x05:
6475: case 0x06:
6476: case 0x07:
1.1.1.20 root 6477: if(fd >= process->max_files || !file_handler[fd].valid) {
6478: REG16(AX) = 0x06;
6479: m_CF = 1;
6480: return;
1.1.1.14 root 6481: }
6482: break;
6483: case 0x08:
6484: case 0x09:
6485: if(REG8(BL) >= ('Z' - 'A' + 1)) {
6486: // invalid drive number
6487: REG16(AX) = 0x0f;
6488: m_CF = 1;
6489: return;
6490: } else {
6491: if(REG8(BL) == 0) {
6492: val = GetDriveType(NULL);
6493: } else {
6494: char tmp[8];
6495: sprintf(tmp, "%c:\\", 'A' + REG8(BL) - 1);
6496: val = GetDriveType(tmp);
6497: }
6498: if(val == DRIVE_NO_ROOT_DIR) {
6499: // no drive
6500: REG16(AX) = 0x0f;
6501: m_CF = 1;
6502: return;
1.1 root 6503: }
6504: }
6505: break;
6506: }
6507: switch(REG8(AL)) {
6508: case 0x00: // get ioctrl data
1.1.1.20 root 6509: REG16(DX) = file_handler[fd].info;
1.1 root 6510: break;
6511: case 0x01: // set ioctrl data
1.1.1.20 root 6512: file_handler[fd].info |= REG8(DL);
1.1 root 6513: break;
6514: case 0x02: // recv from character device
6515: case 0x03: // send to character device
6516: case 0x04: // recv from block device
6517: case 0x05: // send to block device
6518: REG16(AX) = 0x05;
1.1.1.3 root 6519: m_CF = 1;
1.1 root 6520: break;
6521: case 0x06: // get read status
1.1.1.20 root 6522: if(file_mode[file_handler[fd].mode].in) {
6523: if(file_handler[fd].atty) {
1.1.1.14 root 6524: REG8(AL) = msdos_kbhit() ? 0xff : 0x00;
1.1 root 6525: } else {
1.1.1.20 root 6526: REG8(AL) = eof(fd) ? 0x00 : 0xff;
1.1 root 6527: }
1.1.1.14 root 6528: } else {
6529: REG8(AL) = 0x00;
1.1 root 6530: }
6531: break;
6532: case 0x07: // get write status
1.1.1.20 root 6533: if(file_mode[file_handler[fd].mode].out) {
1.1.1.14 root 6534: REG8(AL) = 0xff;
6535: } else {
6536: REG8(AL) = 0x00;
1.1 root 6537: }
6538: break;
6539: case 0x08: // check removable drive
1.1.1.14 root 6540: if(val == DRIVE_REMOVABLE || val == DRIVE_CDROM) {
6541: // removable drive
6542: REG16(AX) = 0x00;
1.1 root 6543: } else {
1.1.1.14 root 6544: // fixed drive
6545: REG16(AX) = 0x01;
1.1 root 6546: }
6547: break;
6548: case 0x09: // check remote drive
1.1.1.14 root 6549: if(val == DRIVE_REMOTE) {
6550: // remote drive
6551: REG16(DX) = 0x1000;
1.1 root 6552: } else {
1.1.1.14 root 6553: // local drive
6554: REG16(DX) = 0x00;
1.1 root 6555: }
6556: break;
1.1.1.21 root 6557: case 0x0a: // check remote handle
6558: REG16(DX) = 0x00; // FIXME
6559: break;
1.1 root 6560: case 0x0b: // set retry count
6561: break;
1.1.1.22 root 6562: case 0x0c: // generic character device request
6563: if(REG8(CL) == 0x45) {
6564: // set iteration (retry) count
6565: iteration_count = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX));
6566: } else if(REG8(CL) == 0x4a) {
6567: // select code page
6568: active_code_page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2);
6569: msdos_nls_tables_update();
6570: } else if(REG8(CL) == 0x65) {
6571: // get iteration (retry) count
6572: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX)) = iteration_count;
6573: } else if(REG8(CL) == 0x6a) {
6574: // query selected code page
6575: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = 2; // FIXME
6576: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2) = active_code_page;
6577:
6578: CPINFO info;
6579: GetCPInfo(active_code_page, &info);
6580:
6581: if(info.MaxCharSize != 1) {
6582: for(int i = 0;; i++) {
6583: UINT8 lo = info.LeadByte[2 * i + 0];
6584: UINT8 hi = info.LeadByte[2 * i + 1];
6585:
6586: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4 + 4 * i + 0) = lo;
6587: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4 + 4 * i + 2) = hi;
6588: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) + 4;
6589:
6590: if(lo == 0 && hi == 0) {
6591: break;
6592: }
6593: }
6594: }
6595: } else if(REG8(CL) == 0x7f) {
6596: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x00) = 0;
6597: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x01) = 0;
6598: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02) = 14;
6599: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x04) = 1;
6600: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x06) = 1;
6601: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x07) = 0;
6602: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x08) = 4;
6603: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0a) = 8 * (*(UINT16 *)(mem + 0x44a));
6604: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0c) = 16 * (*(UINT8 *)(mem + 0x484) + 1);
6605: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0e) = *(UINT16 *)(mem + 0x44a);
6606: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x10) = *(UINT8 *)(mem + 0x484) + 1;
6607: } else {
6608: 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));
6609: REG16(AX) = 0x01; // invalid function
6610: m_CF = 1;
6611: }
6612: break;
6613: case 0x0d: // generic block device request
6614: if(REG8(CL) == 0x40) {
6615: // set device parameters
6616: } else if(REG8(CL) == 0x46) {
6617: // set volume serial number
6618: } else if(REG8(CL) == 0x4a) {
6619: // lock logical volume
6620: } else if(REG8(CL) == 0x4b) {
6621: // lock physical volume
6622: } else if(REG8(CL) == 0x60) {
6623: // get device parameters
6624: char dev[] = "\\\\.\\A:";
6625: dev[4] = 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
6626:
6627: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
6628: if(hFile != INVALID_HANDLE_VALUE) {
6629: DISK_GEOMETRY geo;
6630: DWORD dwSize;
6631: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
6632: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x07; // ???
6633: switch(geo.MediaType) {
6634: case F5_360_512:
6635: case F5_320_512:
6636: case F5_320_1024:
6637: case F5_180_512:
6638: case F5_160_512:
6639: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x00; // 320K/360K disk
6640: break;
6641: case F5_1Pt2_512:
6642: case F3_1Pt2_512:
6643: case F3_1Pt23_1024:
6644: case F5_1Pt23_1024:
6645: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x01; // 1.2M disk
6646: break;
6647: case F3_720_512:
6648: case F3_640_512:
6649: case F5_640_512:
6650: case F5_720_512:
6651: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x02; // 720K disk
6652: break;
6653: case F8_256_128:
6654: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x03; // single-density 8-inch disk
6655: break;
6656: case FixedMedia:
6657: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // fixed disk
6658: break;
6659: case F3_1Pt44_512:
6660: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x07; // (DOS 3.3+) other type of block device, normally 1.44M floppy
6661: break;
6662: case F3_2Pt88_512:
6663: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x09; // (DOS 5+) 2.88M floppy
6664: break;
6665: default:
6666: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // fixed disk
6667: // *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // (DOS 3.3+) other type of block device, normally 1.44M floppy
6668: break;
6669: }
6670: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x02) = (geo.MediaType == FixedMedia) ? 0x01 : 0x00;
6671: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04) = (geo.Cylinders.QuadPart > 0xffff) ? 0xffff : geo.Cylinders.QuadPart;
6672: switch(geo.MediaType) {
6673: case F5_360_512:
6674: case F5_320_512:
6675: case F5_320_1024:
6676: case F5_180_512:
6677: case F5_160_512:
6678: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06) = 0x01; // 320K/360K disk
6679: break;
6680: default:
6681: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06) = 0x00; // other drive types
6682: break;
6683: }
6684: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x00) = geo.BytesPerSector;
6685: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x02) = geo.SectorsPerTrack * geo.TracksPerCylinder;
6686: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x03) = 0;
6687: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x05) = 0;
6688: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x06) = 0;
6689: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x08) = 0;
6690: switch(geo.MediaType) {
6691: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K)
6692: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xff;
6693: break;
6694: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K)
6695: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfe;
6696: break;
6697: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K)
6698: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfd;
6699: break;
6700: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K)
6701: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfc;
6702: break;
6703: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M)
6704: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5")
6705: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf9;
6706: break;
6707: case FixedMedia: // hard disk
6708: case RemovableMedia:
6709: case Unknown:
6710: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf8;
6711: break;
6712: default:
6713: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf0;
6714: break;
6715: }
6716: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0d) = geo.SectorsPerTrack;
6717: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0f) = 1;
6718: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x11) = 0;
6719: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x15) = geo.TracksPerCylinder * geo.Cylinders.QuadPart;
6720: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x1f) = geo.Cylinders.QuadPart;
6721: // 21h BYTE device type
6722: // 22h WORD device attributes (removable or not, etc)
6723: } else {
6724: REG16(AX) = 0x0f; // invalid drive
6725: m_CF = 1;
6726: }
6727: CloseHandle(hFile);
6728: } else {
6729: REG16(AX) = 0x0f; // invalid drive
6730: m_CF = 1;
6731: }
6732: } else if(REG8(CL) == 0x66) {
6733: // get volume serial number
6734: char path[] = "A:\\";
6735: char volume_label[MAX_PATH];
6736: DWORD serial_number = 0;
6737: char file_system[MAX_PATH];
6738:
6739: path[0] = 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
6740:
6741: if(GetVolumeInformation(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) {
6742: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0;
6743: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x02) = serial_number;
6744: memset(mem + SREG_BASE(DS) + REG16(SI) + 0x06, 0x20, 11);
6745: memcpy(mem + SREG_BASE(DS) + REG16(SI) + 0x06, volume_label, min(strlen(volume_label), 11));
6746: memset(mem + SREG_BASE(DS) + REG16(SI) + 0x11, 0x20, 8);
6747: memcpy(mem + SREG_BASE(DS) + REG16(SI) + 0x11, file_system, min(strlen(file_system), 8));
6748: } else {
6749: REG16(AX) = 0x0f; // invalid drive
6750: m_CF = 1;
6751: }
6752: } else if(REG8(CL) == 0x67) {
6753: // get access flag
6754: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0;
6755: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 1;
6756: } else if(REG8(CL) == 0x68) {
6757: // sense media type
6758: char dev[64];
6759: sprintf(dev, "\\\\.\\%c:", 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1);
6760:
6761: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
6762: if(hFile != INVALID_HANDLE_VALUE) {
6763: DISK_GEOMETRY geo;
6764: DWORD dwSize;
6765: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
6766: switch(geo.MediaType) {
6767: case F3_720_512:
6768: case F5_720_512:
6769: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
6770: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x02;
6771: break;
6772: case F3_1Pt44_512:
6773: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
6774: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x07;
6775: break;
6776: case F3_2Pt88_512:
6777: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
6778: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x09;
6779: break;
6780: default:
6781: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x00;
6782: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x00; // ???
6783: break;
6784: }
6785: } else {
6786: REG16(AX) = 0x0f; // invalid drive
6787: m_CF = 1;
6788: }
6789: CloseHandle(hFile);
6790: } else {
6791: REG16(AX) = 0x0f; // invalid drive
6792: m_CF = 1;
6793: }
6794: } else if(REG8(CL) == 0x6a) {
6795: // unlock logical volume
6796: } else if(REG8(CL) == 0x6b) {
6797: // unlock physical volume
6798: } else {
6799: 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));
6800: REG16(AX) = 0x01; // invalid function
6801: m_CF = 1;
6802: }
6803: break;
6804: case 0x0e: // get logical drive map
6805: {
6806: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
6807: if(!(GetLogicalDrives() & bits)) {
6808: REG16(AX) = 0x0f; // invalid drive
6809: m_CF = 1;
6810: } else {
6811: REG8(AL) = 0;
6812: }
6813: }
6814: break;
6815: case 0x0f: // set logical drive map
6816: {
6817: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
6818: if(!(GetLogicalDrives() & bits)) {
6819: REG16(AX) = 0x0f; // invalid drive
6820: m_CF = 1;
6821: }
6822: }
6823: break;
6824: case 0x10: // query generic ioctrl capability (handle)
6825: switch(REG8(CL)) {
6826: case 0x45:
6827: case 0x4a:
6828: case 0x65:
6829: case 0x6a:
6830: case 0x7f:
6831: REG16(AX) = 0x0000; // supported
6832: break;
6833: default:
6834: REG8(AL) = 0x01; // ioctl capability not available
6835: m_CF = 1;
6836: break;
6837: }
6838: break;
6839: case 0x11: // query generic ioctrl capability (drive)
6840: switch(REG8(CL)) {
6841: case 0x40:
6842: case 0x46:
6843: case 0x4a:
6844: case 0x4b:
6845: case 0x60:
6846: case 0x66:
6847: case 0x67:
6848: case 0x68:
6849: case 0x6a:
6850: case 0x6b:
6851: REG16(AX) = 0x0000; // supported
6852: break;
6853: default:
6854: REG8(AL) = 0x01; // ioctl capability not available
6855: m_CF = 1;
6856: break;
6857: }
6858: break;
6859: case 0x12: // determine dos type
6860: case 0x51: // concurrent dos v3.2+ - installation check
6861: case 0x52: // determine dos type/get dr dos versuin
6862: REG16(AX) = 0x01; // this is not DR-DOS
6863: m_CF = 1;
6864: break;
1.1 root 6865: default:
1.1.1.22 root 6866: 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 6867: REG16(AX) = 0x01;
1.1.1.3 root 6868: m_CF = 1;
1.1 root 6869: break;
6870: }
6871: }
6872:
6873: inline void msdos_int_21h_45h()
6874: {
6875: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 6876: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 6877:
1.1.1.20 root 6878: if(fd < process->max_files && file_handler[fd].valid) {
6879: int dup_fd = _dup(fd);
6880: if(dup_fd != -1) {
6881: REG16(AX) = dup_fd;
6882: msdos_file_handler_dup(dup_fd, fd, current_psp);
6883: // msdos_psp_set_file_table(dup_fd, fd, current_psp);
6884: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp);
1.1 root 6885: } else {
6886: REG16(AX) = errno;
1.1.1.3 root 6887: m_CF = 1;
1.1 root 6888: }
6889: } else {
6890: REG16(AX) = 0x06;
1.1.1.3 root 6891: m_CF = 1;
1.1 root 6892: }
6893: }
6894:
6895: inline void msdos_int_21h_46h()
6896: {
6897: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 6898: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
6899: int dup_fd = REG16(CX);
6900: int tmp_fd = msdos_psp_get_file_table(REG16(CX), current_psp);
1.1 root 6901:
1.1.1.20 root 6902: if(REG16(BX) == REG16(CX)) {
6903: REG16(AX) = 0x06;
6904: m_CF = 1;
6905: } else if(fd < process->max_files && file_handler[fd].valid && dup_fd < process->max_files) {
6906: if(tmp_fd < process->max_files && file_handler[tmp_fd].valid) {
6907: _close(tmp_fd);
6908: msdos_file_handler_close(tmp_fd);
6909: msdos_psp_set_file_table(dup_fd, 0x0ff, current_psp);
6910: }
6911: if(_dup2(fd, dup_fd) != -1) {
6912: msdos_file_handler_dup(dup_fd, fd, current_psp);
6913: // msdos_psp_set_file_table(dup_fd, fd, current_psp);
6914: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp);
1.1 root 6915: } else {
6916: REG16(AX) = errno;
1.1.1.3 root 6917: m_CF = 1;
1.1 root 6918: }
6919: } else {
6920: REG16(AX) = 0x06;
1.1.1.3 root 6921: m_CF = 1;
1.1 root 6922: }
6923: }
6924:
6925: inline void msdos_int_21h_47h(int lfn)
6926: {
6927: char path[MAX_PATH];
6928:
6929: if(_getdcwd(REG8(DL), path, MAX_PATH) != NULL) {
6930: if(path[1] == ':') {
6931: // the returned path does not include a drive or the initial backslash
1.1.1.3 root 6932: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), (lfn ? path : msdos_short_path(path)) + 3);
1.1 root 6933: } else {
1.1.1.3 root 6934: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn ? path : msdos_short_path(path));
1.1 root 6935: }
6936: } else {
6937: REG16(AX) = errno;
1.1.1.3 root 6938: m_CF = 1;
1.1 root 6939: }
6940: }
6941:
6942: inline void msdos_int_21h_48h()
6943: {
1.1.1.19 root 6944: int seg, umb_linked;
1.1 root 6945:
1.1.1.8 root 6946: if((malloc_strategy & 0xf0) == 0x00) {
1.1.1.19 root 6947: // unlink umb not to allocate memory in umb
6948: if((umb_linked = msdos_mem_get_umb_linked()) != 0) {
6949: msdos_mem_unlink_umb();
6950: }
1.1.1.8 root 6951: if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
6952: REG16(AX) = seg;
6953: } else {
6954: REG16(AX) = 0x08;
6955: REG16(BX) = msdos_mem_get_free(first_mcb, 0);
6956: m_CF = 1;
6957: }
1.1.1.19 root 6958: if(umb_linked != 0) {
6959: msdos_mem_link_umb();
6960: }
1.1.1.8 root 6961: } else if((malloc_strategy & 0xf0) == 0x40) {
6962: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
6963: REG16(AX) = seg;
6964: } else {
6965: REG16(AX) = 0x08;
6966: REG16(BX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
6967: m_CF = 1;
6968: }
6969: } else if((malloc_strategy & 0xf0) == 0x80) {
6970: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
6971: REG16(AX) = seg;
6972: } else if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
6973: REG16(AX) = seg;
6974: } else {
6975: REG16(AX) = 0x08;
6976: REG16(BX) = max(msdos_mem_get_free(UMB_TOP >> 4, 0), msdos_mem_get_free(first_mcb, 0));
6977: m_CF = 1;
6978: }
1.1 root 6979: }
6980: }
6981:
6982: inline void msdos_int_21h_49h()
6983: {
1.1.1.14 root 6984: int mcb_seg = SREG(ES) - 1;
6985: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
6986:
6987: if(mcb->mz == 'M' || mcb->mz == 'Z') {
6988: msdos_mem_free(SREG(ES));
6989: } else {
6990: REG16(AX) = 9;
6991: m_CF = 1;
6992: }
1.1 root 6993: }
6994:
6995: inline void msdos_int_21h_4ah()
6996: {
1.1.1.14 root 6997: int mcb_seg = SREG(ES) - 1;
6998: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1 root 6999: int max_paragraphs;
7000:
1.1.1.14 root 7001: if(mcb->mz == 'M' || mcb->mz == 'Z') {
7002: if(msdos_mem_realloc(SREG(ES), REG16(BX), &max_paragraphs)) {
7003: REG16(AX) = 0x08;
7004: REG16(BX) = max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs;
7005: m_CF = 1;
7006: }
7007: } else {
7008: REG16(AX) = 7;
1.1.1.3 root 7009: m_CF = 1;
1.1 root 7010: }
7011: }
7012:
7013: inline void msdos_int_21h_4bh()
7014: {
1.1.1.3 root 7015: char *command = (char *)(mem + SREG_BASE(DS) + REG16(DX));
7016: param_block_t *param = (param_block_t *)(mem + SREG_BASE(ES) + REG16(BX));
1.1 root 7017:
7018: switch(REG8(AL)) {
7019: case 0x00:
7020: case 0x01:
7021: if(msdos_process_exec(command, param, REG8(AL))) {
7022: REG16(AX) = 0x02;
1.1.1.3 root 7023: m_CF = 1;
1.1 root 7024: }
7025: break;
1.1.1.14 root 7026: case 0x03:
7027: {
7028: int fd;
7029: if((fd = _open(command, _O_RDONLY | _O_BINARY)) == -1) {
7030: REG16(AX) = 0x02;
7031: m_CF = 1;
7032: break;
7033: }
7034: int size = _read(fd, file_buffer, sizeof(file_buffer));
7035: _close(fd);
7036:
7037: UINT16 *overlay = (UINT16 *)param;
7038:
7039: // check exe header
7040: exe_header_t *header = (exe_header_t *)file_buffer;
7041: int header_size = 0;
7042: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
7043: header_size = header->header_size * 16;
7044: // relocation
7045: int start_seg = overlay[1];
7046: for(int i = 0; i < header->relocations; i++) {
7047: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
7048: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
7049: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
7050: }
7051: }
7052: memcpy(mem + (overlay[0] << 4), file_buffer + header_size, size - header_size);
7053: }
7054: break;
1.1 root 7055: default:
1.1.1.22 root 7056: 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 7057: REG16(AX) = 0x01;
1.1.1.3 root 7058: m_CF = 1;
1.1 root 7059: break;
7060: }
7061: }
7062:
7063: inline void msdos_int_21h_4ch()
7064: {
7065: msdos_process_terminate(current_psp, REG8(AL), 1);
7066: }
7067:
7068: inline void msdos_int_21h_4dh()
7069: {
7070: REG16(AX) = retval;
7071: }
7072:
7073: inline void msdos_int_21h_4eh()
7074: {
7075: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 7076: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
7077: find_t *find = (find_t *)(mem + dta_laddr);
1.1.1.3 root 7078: char *path = msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 7079: WIN32_FIND_DATA fd;
7080:
1.1.1.14 root 7081: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
7082: find->find_magic = FIND_MAGIC;
7083: find->dta_index = dtainfo - dtalist;
1.1 root 7084: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 7085: dtainfo->allowable_mask = REG8(CL);
7086: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 7087:
1.1.1.14 root 7088: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
7089: dtainfo->allowable_mask &= ~8;
1.1 root 7090: }
1.1.1.14 root 7091: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
7092: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 7093: !msdos_find_file_has_8dot3name(&fd)) {
7094: if(!FindNextFile(dtainfo->find_handle, &fd)) {
7095: FindClose(dtainfo->find_handle);
7096: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7097: break;
7098: }
7099: }
7100: }
1.1.1.13 root 7101: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 7102: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
7103: msdos_find_file_conv_local_time(&fd);
7104: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
7105: find->size = fd.nFileSizeLow;
1.1.1.13 root 7106: strcpy(find->name, msdos_short_name(&fd));
1.1 root 7107: REG16(AX) = 0;
1.1.1.14 root 7108: } else if(dtainfo->allowable_mask & 8) {
1.1 root 7109: find->attrib = 8;
7110: find->size = 0;
7111: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 7112: dtainfo->allowable_mask &= ~8;
1.1 root 7113: REG16(AX) = 0;
7114: } else {
7115: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 7116: m_CF = 1;
1.1 root 7117: }
7118: }
7119:
7120: inline void msdos_int_21h_4fh()
7121: {
7122: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 7123: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
7124: find_t *find = (find_t *)(mem + dta_laddr);
1.1 root 7125: WIN32_FIND_DATA fd;
7126:
1.1.1.14 root 7127: if(find->find_magic != FIND_MAGIC || find->dta_index >= MAX_DTAINFO) {
7128: REG16(AX) = 0x12;
7129: m_CF = 1;
7130: return;
7131: }
7132: dtainfo_t *dtainfo = &dtalist[find->dta_index];
1.1.1.13 root 7133: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
7134: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 7135: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 7136: !msdos_find_file_has_8dot3name(&fd)) {
7137: if(!FindNextFile(dtainfo->find_handle, &fd)) {
7138: FindClose(dtainfo->find_handle);
7139: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7140: break;
7141: }
7142: }
7143: } else {
1.1.1.13 root 7144: FindClose(dtainfo->find_handle);
7145: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7146: }
7147: }
1.1.1.13 root 7148: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 7149: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
7150: msdos_find_file_conv_local_time(&fd);
7151: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
7152: find->size = fd.nFileSizeLow;
1.1.1.13 root 7153: strcpy(find->name, msdos_short_name(&fd));
1.1 root 7154: REG16(AX) = 0;
1.1.1.14 root 7155: } else if(dtainfo->allowable_mask & 8) {
1.1 root 7156: find->attrib = 8;
7157: find->size = 0;
7158: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 7159: dtainfo->allowable_mask &= ~8;
1.1 root 7160: REG16(AX) = 0;
7161: } else {
7162: REG16(AX) = 0x12;
1.1.1.3 root 7163: m_CF = 1;
1.1 root 7164: }
7165: }
7166:
7167: inline void msdos_int_21h_50h()
7168: {
1.1.1.8 root 7169: if(current_psp != REG16(BX)) {
7170: process_t *process = msdos_process_info_get(current_psp);
7171: if(process != NULL) {
7172: process->psp = REG16(BX);
7173: }
7174: current_psp = REG16(BX);
1.1.1.23 root 7175: msdos_sda_update(current_psp);
1.1.1.8 root 7176: }
1.1 root 7177: }
7178:
7179: inline void msdos_int_21h_51h()
7180: {
7181: REG16(BX) = current_psp;
7182: }
7183:
7184: inline void msdos_int_21h_52h()
7185: {
1.1.1.25 root 7186: SREG(ES) = DOS_INFO_TOP >> 4;
1.1.1.3 root 7187: i386_load_segment_descriptor(ES);
1.1.1.25 root 7188: REG16(BX) = offsetof(dos_info_t, first_dpb);
1.1 root 7189: }
7190:
7191: inline void msdos_int_21h_54h()
7192: {
7193: process_t *process = msdos_process_info_get(current_psp);
7194:
7195: REG8(AL) = process->verify;
7196: }
7197:
7198: inline void msdos_int_21h_55h()
7199: {
7200: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
7201:
7202: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
7203: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
7204: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
7205: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
7206: psp->parent_psp = current_psp;
7207: }
7208:
7209: inline void msdos_int_21h_56h(int lfn)
7210: {
7211: char src[MAX_PATH], dst[MAX_PATH];
1.1.1.3 root 7212: strcpy(src, msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn));
7213: strcpy(dst, msdos_trimmed_path((char *)(mem + SREG_BASE(ES) + REG16(DI)), lfn));
1.1 root 7214:
7215: if(rename(src, dst)) {
7216: REG16(AX) = errno;
1.1.1.3 root 7217: m_CF = 1;
1.1 root 7218: }
7219: }
7220:
7221: inline void msdos_int_21h_57h()
7222: {
7223: FILETIME time, local;
1.1.1.14 root 7224: FILETIME *ctime, *atime, *mtime;
1.1.1.21 root 7225: HANDLE hHandle;
1.1 root 7226:
1.1.1.21 root 7227: if((hHandle = (HANDLE)_get_osfhandle(REG16(BX))) == INVALID_HANDLE_VALUE) {
1.1.1.14 root 7228: REG16(AX) = (UINT16)GetLastError();
7229: m_CF = 1;
7230: return;
7231: }
7232: ctime = atime = mtime = NULL;
7233:
1.1 root 7234: switch(REG8(AL)) {
7235: case 0x00:
1.1.1.6 root 7236: case 0x01:
1.1.1.14 root 7237: mtime = &time;
1.1.1.6 root 7238: break;
7239: case 0x04:
7240: case 0x05:
1.1.1.14 root 7241: atime = &time;
1.1 root 7242: break;
1.1.1.6 root 7243: case 0x06:
7244: case 0x07:
1.1.1.14 root 7245: ctime = &time;
7246: break;
7247: default:
1.1.1.22 root 7248: 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 7249: REG16(AX) = 0x01;
7250: m_CF = 1;
7251: return;
7252: }
7253: if(REG8(AL) & 1) {
1.1 root 7254: DosDateTimeToFileTime(REG16(DX), REG16(CX), &local);
7255: LocalFileTimeToFileTime(&local, &time);
1.1.1.21 root 7256: if(!SetFileTime(hHandle, ctime, atime, mtime)) {
1.1 root 7257: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 7258: m_CF = 1;
1.1 root 7259: }
1.1.1.14 root 7260: } else {
1.1.1.21 root 7261: if(!GetFileTime(hHandle, ctime, atime, mtime)) {
1.1.1.14 root 7262: // assume a device and use the current time
7263: GetSystemTimeAsFileTime(&time);
7264: }
7265: FileTimeToLocalFileTime(&time, &local);
7266: FileTimeToDosDateTime(&local, ®16(DX), ®16(CX));
1.1 root 7267: }
7268: }
7269:
7270: inline void msdos_int_21h_58h()
7271: {
7272: switch(REG8(AL)) {
7273: case 0x00:
1.1.1.7 root 7274: REG16(AX) = malloc_strategy;
7275: break;
7276: case 0x01:
1.1.1.24 root 7277: // switch(REG16(BX)) {
7278: switch(REG8(BL)) {
1.1.1.7 root 7279: case 0x0000:
7280: case 0x0001:
7281: case 0x0002:
7282: case 0x0040:
7283: case 0x0041:
7284: case 0x0042:
7285: case 0x0080:
7286: case 0x0081:
7287: case 0x0082:
7288: malloc_strategy = REG16(BX);
1.1.1.23 root 7289: msdos_sda_update(current_psp);
1.1.1.7 root 7290: break;
7291: default:
1.1.1.22 root 7292: 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 7293: REG16(AX) = 0x01;
7294: m_CF = 1;
7295: break;
7296: }
7297: break;
7298: case 0x02:
1.1.1.19 root 7299: REG8(AL) = msdos_mem_get_umb_linked() ? 1 : 0;
1.1.1.7 root 7300: break;
7301: case 0x03:
1.1.1.24 root 7302: // switch(REG16(BX)) {
7303: switch(REG8(BL)) {
1.1.1.7 root 7304: case 0x0000:
1.1.1.19 root 7305: msdos_mem_unlink_umb();
7306: break;
1.1.1.7 root 7307: case 0x0001:
1.1.1.19 root 7308: msdos_mem_link_umb();
1.1.1.7 root 7309: break;
7310: default:
1.1.1.22 root 7311: 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 7312: REG16(AX) = 0x01;
7313: m_CF = 1;
7314: break;
7315: }
1.1 root 7316: break;
7317: default:
1.1.1.22 root 7318: 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 7319: REG16(AX) = 0x01;
1.1.1.3 root 7320: m_CF = 1;
1.1 root 7321: break;
7322: }
7323: }
7324:
7325: inline void msdos_int_21h_59h()
7326: {
1.1.1.23 root 7327: sda_t *sda = (sda_t *)(mem + SDA_TOP);
7328:
7329: REG16(AX) = sda->extended_error_code;
7330: REG8(BH) = sda->error_class;
7331: REG8(BL) = sda->suggested_action;
7332: REG8(CH) = sda->locus_of_last_error;
1.1 root 7333: }
7334:
7335: inline void msdos_int_21h_5ah()
7336: {
1.1.1.3 root 7337: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 7338: int len = strlen(path);
7339: char tmp[MAX_PATH];
7340:
7341: if(GetTempFileName(path, "TMP", 0, tmp)) {
7342: int fd = _open(tmp, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
7343:
7344: SetFileAttributes(tmp, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
7345: REG16(AX) = fd;
7346: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 7347: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 7348:
7349: strcpy(path, tmp);
7350: int dx = REG16(DX) + len;
1.1.1.3 root 7351: int ds = SREG(DS);
1.1 root 7352: while(dx > 0xffff) {
7353: dx -= 0x10;
7354: ds++;
7355: }
7356: REG16(DX) = dx;
1.1.1.3 root 7357: SREG(DS) = ds;
7358: i386_load_segment_descriptor(DS);
1.1 root 7359: } else {
7360: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 7361: m_CF = 1;
1.1 root 7362: }
7363: }
7364:
7365: inline void msdos_int_21h_5bh()
7366: {
1.1.1.3 root 7367: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 7368:
1.1.1.24 root 7369: if(msdos_is_existing_file(path)) {
1.1 root 7370: // already exists
7371: REG16(AX) = 0x50;
1.1.1.3 root 7372: m_CF = 1;
1.1 root 7373: } else {
7374: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
7375:
7376: if(fd != -1) {
7377: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
7378: REG16(AX) = fd;
7379: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 7380: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 7381: } else {
7382: REG16(AX) = errno;
1.1.1.3 root 7383: m_CF = 1;
1.1 root 7384: }
7385: }
7386: }
7387:
7388: inline void msdos_int_21h_5ch()
7389: {
7390: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 7391: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 7392:
1.1.1.20 root 7393: if(fd < process->max_files && file_handler[fd].valid) {
1.1 root 7394: if(REG8(AL) == 0 || REG8(AL) == 1) {
7395: static int modes[2] = {_LK_LOCK, _LK_UNLCK};
1.1.1.20 root 7396: UINT32 pos = _tell(fd);
7397: _lseek(fd, (REG16(CX) << 16) | REG16(DX), SEEK_SET);
7398: if(_locking(fd, modes[REG8(AL)], (REG16(SI) << 16) | REG16(DI))) {
1.1 root 7399: REG16(AX) = errno;
1.1.1.3 root 7400: m_CF = 1;
1.1 root 7401: }
1.1.1.20 root 7402: _lseek(fd, pos, SEEK_SET);
1.1.1.26 root 7403:
1.1 root 7404: // some seconds may be passed in _locking()
7405: hardware_update();
7406: } else {
7407: REG16(AX) = 0x01;
1.1.1.3 root 7408: m_CF = 1;
1.1 root 7409: }
7410: } else {
7411: REG16(AX) = 0x06;
1.1.1.3 root 7412: m_CF = 1;
1.1 root 7413: }
7414: }
7415:
1.1.1.22 root 7416: inline void msdos_int_21h_5dh()
7417: {
7418: switch(REG8(AL)) {
7419: case 0x06: // get address of dos swappable data area
1.1.1.23 root 7420: SREG(DS) = (SDA_TOP >> 4);
7421: i386_load_segment_descriptor(DS);
7422: REG16(SI) = offsetof(sda_t, crit_error_flag);
7423: REG16(CX) = 0x80;
7424: REG16(DX) = 0x1a;
7425: break;
7426: case 0x0b: // get dos swappable data areas
1.1.1.22 root 7427: REG16(AX) = 0x01;
7428: m_CF = 1;
7429: break;
7430: case 0x08: // set redirected printer mode
7431: case 0x09: // flush redirected printer output
7432: case 0x0a: // set extended error information
7433: break;
7434: default:
7435: 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));
7436: REG16(AX) = 0x01;
7437: m_CF = 1;
7438: break;
7439: }
7440: }
7441:
1.1 root 7442: inline void msdos_int_21h_60h(int lfn)
7443: {
1.1.1.14 root 7444: char full[MAX_PATH], *path;
7445:
1.1 root 7446: if(lfn) {
1.1.1.14 root 7447: char *name;
7448: *full = '\0';
1.1.1.3 root 7449: GetFullPathName((char *)(mem + SREG_BASE(DS) + REG16(SI)), MAX_PATH, full, &name);
1.1.1.14 root 7450: switch(REG8(CL)) {
7451: case 1:
7452: GetShortPathName(full, full, MAX_PATH);
7453: my_strupr(full);
7454: break;
7455: case 2:
7456: GetLongPathName(full, full, MAX_PATH);
7457: break;
7458: }
7459: path = full;
7460: } else {
7461: path = msdos_short_full_path((char *)(mem + SREG_BASE(DS) + REG16(SI)));
7462: }
7463: if(*path != '\0') {
7464: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), path);
1.1 root 7465: } else {
1.1.1.14 root 7466: REG16(AX) = (UINT16)GetLastError();
7467: m_CF = 1;
1.1 root 7468: }
7469: }
7470:
7471: inline void msdos_int_21h_61h()
7472: {
7473: REG8(AL) = 0;
7474: }
7475:
7476: inline void msdos_int_21h_62h()
7477: {
7478: REG16(BX) = current_psp;
7479: }
7480:
7481: inline void msdos_int_21h_63h()
7482: {
7483: switch(REG8(AL)) {
7484: case 0x00:
1.1.1.3 root 7485: SREG(DS) = (DBCS_TABLE >> 4);
7486: i386_load_segment_descriptor(DS);
1.1 root 7487: REG16(SI) = (DBCS_TABLE & 0x0f);
7488: REG8(AL) = 0x00;
7489: break;
1.1.1.22 root 7490: case 0x01: // set korean input mode
7491: case 0x02: // get korean input mode
7492: REG8(AL) = 0xff; // not supported
7493: break;
1.1 root 7494: default:
1.1.1.22 root 7495: 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 7496: REG16(AX) = 0x01;
1.1.1.3 root 7497: m_CF = 1;
1.1 root 7498: break;
7499: }
7500: }
7501:
1.1.1.25 root 7502: UINT16 get_extended_country_info(UINT8 func)
1.1 root 7503: {
1.1.1.25 root 7504: switch(func) {
1.1.1.17 root 7505: case 0x01:
7506: if(REG16(CX) >= 5) {
1.1.1.19 root 7507: UINT8 data[1 + 2 + 2 + 2 + sizeof(country_info_t)];
1.1.1.17 root 7508: if(REG16(CX) > sizeof(data)) // cx = actual transfer size
7509: REG16(CX) = sizeof(data);
7510: ZeroMemory(data, sizeof(data));
7511: data[0] = 0x01;
7512: *(UINT16 *)(data + 1) = REG16(CX) - 3;
1.1.1.19 root 7513: *(UINT16 *)(data + 3) = get_country_info((country_info_t*)(data + 7));
1.1.1.17 root 7514: *(UINT16 *)(data + 5) = active_code_page;
7515: memcpy(mem + SREG_BASE(ES) + REG16(DI), data, REG16(CX));
1.1.1.25 root 7516: // REG16(AX) = active_code_page;
1.1.1.17 root 7517: } else {
1.1.1.25 root 7518: return(0x08); // insufficient memory
1.1.1.17 root 7519: }
7520: break;
7521: case 0x02:
7522: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x02;
7523: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (UPPERTABLE_TOP & 0x0f);
7524: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (UPPERTABLE_TOP >> 4);
1.1.1.25 root 7525: // REG16(AX) = active_code_page;
1.1.1.17 root 7526: REG16(CX) = 0x05;
7527: break;
1.1.1.23 root 7528: case 0x03:
7529: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x02;
7530: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (LOWERTABLE_TOP & 0x0f);
7531: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (LOWERTABLE_TOP >> 4);
1.1.1.25 root 7532: // REG16(AX) = active_code_page;
1.1.1.23 root 7533: REG16(CX) = 0x05;
7534: break;
1.1.1.17 root 7535: case 0x04:
7536: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x04;
7537: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_UPPERTABLE_TOP & 0x0f);
7538: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_UPPERTABLE_TOP >> 4);
1.1.1.25 root 7539: // REG16(AX) = active_code_page;
1.1.1.17 root 7540: REG16(CX) = 0x05;
7541: break;
7542: case 0x05:
7543: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x05;
7544: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_TERMINATOR_TOP & 0x0f);
7545: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_TERMINATOR_TOP >> 4);
1.1.1.25 root 7546: // REG16(AX) = active_code_page;
1.1.1.17 root 7547: REG16(CX) = 0x05;
7548: break;
7549: case 0x06:
7550: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x06;
7551: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (COLLATING_TABLE_TOP & 0x0f);
7552: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (COLLATING_TABLE_TOP >> 4);
1.1.1.25 root 7553: // REG16(AX) = active_code_page;
1.1.1.17 root 7554: REG16(CX) = 0x05;
7555: break;
1.1 root 7556: case 0x07:
1.1.1.3 root 7557: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x07;
7558: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (DBCS_TOP & 0x0f);
7559: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (DBCS_TOP >> 4);
1.1.1.25 root 7560: // REG16(AX) = active_code_page;
1.1 root 7561: REG16(CX) = 0x05;
7562: break;
1.1.1.25 root 7563: default:
7564: return(0x01); // function number invalid
7565: }
7566: return(0x00);
7567: }
7568:
7569: inline void msdos_int_21h_65h()
7570: {
7571: char tmp[0x10000];
7572:
7573: switch(REG8(AL)) {
7574: case 0x01:
7575: case 0x02:
7576: case 0x03:
7577: case 0x04:
7578: case 0x05:
7579: case 0x06:
7580: case 0x07:
7581: {
7582: UINT16 result = get_extended_country_info(REG8(AL));
7583: if(result) {
7584: REG16(AX) = result;
7585: m_CF = 1;
7586: } else {
7587: REG16(AX) = active_code_page; // FIXME: is this correct???
7588: }
7589: }
7590: break;
1.1 root 7591: case 0x20:
1.1.1.25 root 7592: case 0xa0:
1.1.1.19 root 7593: memset(tmp, 0, sizeof(tmp));
7594: tmp[0] = REG8(DL);
1.1 root 7595: my_strupr(tmp);
7596: REG8(DL) = tmp[0];
7597: break;
7598: case 0x21:
1.1.1.25 root 7599: case 0xa1:
1.1 root 7600: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 7601: memcpy(tmp, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 7602: my_strupr(tmp);
1.1.1.3 root 7603: memcpy(mem + SREG_BASE(DS) + REG16(DX), tmp, REG16(CX));
1.1 root 7604: break;
7605: case 0x22:
1.1.1.25 root 7606: case 0xa2:
1.1.1.3 root 7607: my_strupr((char *)(mem + SREG_BASE(DS) + REG16(DX)));
1.1 root 7608: break;
1.1.1.25 root 7609: case 0x23:
7610: // FIXME: need to check multi-byte (kanji) charactre?
7611: if(REG8(DL) == 'N' || REG8(DL) == 'n' || (REG8(DL) == 0x82 && REG8(DH) == 0x78) || (REG8(DL) == 0x82 && REG8(DH) == 0x99)) {
7612: // 8278h/8299h: multi-byte (kanji) Y and y
7613: REG16(AX) = 0x00;
7614: } else if(REG8(DL) == 'Y' || REG8(DL) == 'y' || (REG8(DL) == 0x82 && REG8(DH) == 0x6d) || (REG8(DL) == 0x82 && REG8(DH) == 0x8e)) {
7615: // 826dh/828eh: multi-byte (kanji) N and n
7616: REG16(AX) = 0x01;
7617: } else {
7618: REG16(AX) = 0x02;
7619: }
7620: break;
1.1 root 7621: default:
1.1.1.22 root 7622: 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 7623: REG16(AX) = 0x01;
1.1.1.3 root 7624: m_CF = 1;
1.1 root 7625: break;
7626: }
7627: }
7628:
7629: inline void msdos_int_21h_66h()
7630: {
7631: switch(REG8(AL)) {
7632: case 0x01:
7633: REG16(BX) = active_code_page;
7634: REG16(DX) = system_code_page;
7635: break;
7636: case 0x02:
7637: if(active_code_page == REG16(BX)) {
7638: REG16(AX) = 0xeb41;
7639: } else if(_setmbcp(REG16(BX)) == 0) {
7640: active_code_page = REG16(BX);
1.1.1.17 root 7641: msdos_nls_tables_update();
1.1 root 7642: REG16(AX) = 0xeb41;
7643: } else {
7644: REG16(AX) = 0x25;
1.1.1.3 root 7645: m_CF = 1;
1.1 root 7646: }
7647: break;
7648: default:
1.1.1.22 root 7649: 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 7650: REG16(AX) = 0x01;
1.1.1.3 root 7651: m_CF = 1;
1.1 root 7652: break;
7653: }
7654: }
7655:
7656: inline void msdos_int_21h_67h()
7657: {
7658: process_t *process = msdos_process_info_get(current_psp);
7659:
7660: if(REG16(BX) <= MAX_FILES) {
7661: process->max_files = max(REG16(BX), 20);
7662: } else {
7663: REG16(AX) = 0x08;
1.1.1.3 root 7664: m_CF = 1;
1.1 root 7665: }
7666: }
7667:
7668: inline void msdos_int_21h_68h()
7669: {
7670: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 7671: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 7672:
1.1.1.20 root 7673: if(fd < process->max_files && file_handler[fd].valid) {
7674: // fflush(_fdopen(fd, ""));
1.1 root 7675: } else {
7676: REG16(AX) = 0x06;
1.1.1.3 root 7677: m_CF = 1;
1.1 root 7678: }
7679: }
7680:
7681: inline void msdos_int_21h_69h()
7682: {
1.1.1.3 root 7683: drive_info_t *info = (drive_info_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 7684: char path[] = "A:\\";
7685: char volume_label[MAX_PATH];
7686: DWORD serial_number = 0;
7687: char file_system[MAX_PATH];
7688:
7689: if(REG8(BL) == 0) {
7690: path[0] = 'A' + _getdrive() - 1;
7691: } else {
7692: path[0] = 'A' + REG8(BL) - 1;
7693: }
7694:
7695: switch(REG8(AL)) {
7696: case 0x00:
7697: if(GetVolumeInformation(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) {
7698: info->info_level = 0;
7699: info->serial_number = serial_number;
7700: memset(info->volume_label, 0x20, 11);
7701: memcpy(info->volume_label, volume_label, min(strlen(volume_label), 11));
7702: memset(info->file_system, 0x20, 8);
7703: memcpy(info->file_system, file_system, min(strlen(file_system), 8));
7704: } else {
7705: REG16(AX) = errno;
1.1.1.3 root 7706: m_CF = 1;
1.1 root 7707: }
7708: break;
7709: case 0x01:
7710: REG16(AX) = 0x03;
1.1.1.3 root 7711: m_CF = 1;
1.1 root 7712: }
7713: }
7714:
7715: inline void msdos_int_21h_6ah()
7716: {
7717: REG8(AH) = 0x68;
7718: msdos_int_21h_68h();
7719: }
7720:
7721: inline void msdos_int_21h_6bh()
7722: {
7723: REG8(AL) = 0;
7724: }
7725:
7726: inline void msdos_int_21h_6ch(int lfn)
7727: {
1.1.1.3 root 7728: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn);
1.1 root 7729: int mode = REG8(BL) & 0x03;
7730:
7731: if(mode < 0x03) {
1.1.1.24 root 7732: if(msdos_is_existing_file(path) || msdos_is_driver_name(path)) {
1.1 root 7733: // file exists
7734: if(REG8(DL) & 1) {
1.1.1.11 root 7735: int fd = -1;
7736: UINT16 info;
1.1 root 7737:
1.1.1.11 root 7738: if(msdos_is_con_path(path)) {
1.1.1.13 root 7739: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 7740: info = 0x80d3;
1.1.1.14 root 7741: } else if(msdos_is_nul_path(path)) {
7742: fd = msdos_open("NUL", file_mode[mode].mode);
7743: info = 0x80d3;
1.1.1.24 root 7744: } else if(msdos_is_driver_name(path)) {
1.1.1.20 root 7745: fd = msdos_open("NUL", file_mode[mode].mode);
7746: info = 0x80d3;
1.1.1.11 root 7747: } else {
1.1.1.13 root 7748: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 7749: info = msdos_drive_number(path);
7750: }
1.1 root 7751: if(fd != -1) {
7752: REG16(AX) = fd;
7753: REG16(CX) = 1;
1.1.1.11 root 7754: msdos_file_handler_open(fd, path, _isatty(fd), mode, info, current_psp);
1.1.1.20 root 7755: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 7756: } else {
7757: REG16(AX) = errno;
1.1.1.3 root 7758: m_CF = 1;
1.1 root 7759: }
7760: } else if(REG8(DL) & 2) {
7761: int attr = GetFileAttributes(path);
7762: int fd = -1;
1.1.1.11 root 7763: UINT16 info;
1.1 root 7764:
1.1.1.11 root 7765: if(msdos_is_con_path(path)) {
1.1.1.13 root 7766: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 7767: info = 0x80d3;
1.1.1.14 root 7768: } else if(msdos_is_nul_path(path)) {
7769: fd = msdos_open("NUL", file_mode[mode].mode);
7770: info = 0x80d3;
1.1.1.24 root 7771: } else if(msdos_is_driver_name(path)) {
1.1.1.20 root 7772: fd = msdos_open("NUL", file_mode[mode].mode);
7773: info = 0x80d3;
1.1 root 7774: } else {
7775: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
1.1.1.11 root 7776: info = msdos_drive_number(path);
1.1 root 7777: }
7778: if(fd != -1) {
7779: if(attr == -1) {
7780: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
7781: }
7782: SetFileAttributes(path, attr);
7783: REG16(AX) = fd;
7784: REG16(CX) = 3;
1.1.1.11 root 7785: msdos_file_handler_open(fd, path, _isatty(fd), 2, info, current_psp);
1.1.1.20 root 7786: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 7787: } else {
7788: REG16(AX) = errno;
1.1.1.3 root 7789: m_CF = 1;
1.1 root 7790: }
7791: } else {
7792: REG16(AX) = 0x50;
1.1.1.3 root 7793: m_CF = 1;
1.1 root 7794: }
7795: } else {
7796: // file not exists
7797: if(REG8(DL) & 0x10) {
7798: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
7799:
7800: if(fd != -1) {
7801: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
7802: REG16(AX) = fd;
7803: REG16(CX) = 2;
7804: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 7805: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 7806: } else {
7807: REG16(AX) = errno;
1.1.1.3 root 7808: m_CF = 1;
1.1 root 7809: }
7810: } else {
7811: REG16(AX) = 0x02;
1.1.1.3 root 7812: m_CF = 1;
1.1 root 7813: }
7814: }
7815: } else {
7816: REG16(AX) = 0x0c;
1.1.1.3 root 7817: m_CF = 1;
1.1 root 7818: }
7819: }
7820:
7821: inline void msdos_int_21h_710dh()
7822: {
7823: // reset drive
7824: }
7825:
1.1.1.17 root 7826: inline void msdos_int_21h_7141h(int lfn)
7827: {
7828: if(REG16(SI) == 0) {
7829: msdos_int_21h_41h(lfn);
7830: return;
7831: }
7832: if(REG16(SI) != 1) {
7833: REG16(AX) = 5;
7834: m_CF = 1;
7835: }
7836: /* wild card and matching attributes... */
7837: char tmp[MAX_PATH * 2];
7838: // copy search pathname (and quick check overrun)
7839: ZeroMemory(tmp, sizeof(tmp));
7840: tmp[MAX_PATH - 1] = '\0';
7841: tmp[MAX_PATH] = 1;
7842: strncpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(DX)), MAX_PATH);
7843:
7844: if(tmp[MAX_PATH - 1] != '\0' || tmp[MAX_PATH] != 1) {
7845: REG16(AX) = 1;
7846: m_CF = 1;
7847: return;
7848: }
7849: for(char *s = tmp; *s; ++s) {
7850: if(*s == '/') {
7851: *s = '\\';
7852: }
7853: }
7854: char *tmp_name = (char *)_mbsrchr((unsigned char *)tmp, '\\');
7855: if(tmp_name) {
7856: ++tmp_name;
7857: } else {
7858: tmp_name = strchr(tmp, ':');
7859: tmp_name = tmp_name ? tmp_name + 1 : tmp;
7860: }
7861:
7862: WIN32_FIND_DATAA fd;
7863: HANDLE fh = FindFirstFileA(tmp, &fd);
7864: if(fh == INVALID_HANDLE_VALUE) {
7865: REG16(AX) = 2;
7866: m_CF = 1;
7867: return;
7868: }
7869: do {
7870: if(msdos_find_file_check_attribute(fd.dwFileAttributes, REG8(CL), REG8(CH)) && msdos_find_file_has_8dot3name(&fd)) {
7871: strcpy(tmp_name, fd.cFileName);
7872: if(remove(msdos_trimmed_path(tmp, lfn))) {
7873: REG16(AX) = 5;
7874: m_CF = 1;
7875: break;
7876: }
7877: }
7878: } while(FindNextFileA(fh, &fd));
7879: if(!m_CF) {
7880: if(GetLastError() != ERROR_NO_MORE_FILES) {
7881: m_CF = 1;
7882: REG16(AX) = 2;
7883: }
7884: }
7885: FindClose(fh);
7886: }
7887:
1.1 root 7888: inline void msdos_int_21h_714eh()
7889: {
7890: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 7891: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
7892: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 7893: WIN32_FIND_DATA fd;
7894:
1.1.1.13 root 7895: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
7896: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
7897: FindClose(dtainfo->find_handle);
7898: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7899: }
7900: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 7901: dtainfo->allowable_mask = REG8(CL);
7902: dtainfo->required_mask = REG8(CH);
7903: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 7904:
1.1.1.14 root 7905: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
7906: dtainfo->allowable_mask &= ~8;
1.1 root 7907: }
1.1.1.14 root 7908: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
7909: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 7910: if(!FindNextFile(dtainfo->find_handle, &fd)) {
7911: FindClose(dtainfo->find_handle);
7912: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7913: break;
7914: }
7915: }
7916: }
1.1.1.13 root 7917: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 7918: find->attrib = fd.dwFileAttributes;
7919: msdos_find_file_conv_local_time(&fd);
7920: if(REG16(SI) == 0) {
7921: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
7922: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
7923: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
7924: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
7925: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
7926: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
7927: } else {
7928: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
7929: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
7930: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
7931: }
7932: find->size_hi = fd.nFileSizeHigh;
7933: find->size_lo = fd.nFileSizeLow;
7934: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 7935: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14 root 7936: REG16(AX) = dtainfo - dtalist + 1;
7937: } else if(dtainfo->allowable_mask & 8) {
1.1 root 7938: // volume label
7939: find->attrib = 8;
7940: find->size_hi = find->size_lo = 0;
7941: strcpy(find->full_name, process->volume_label);
7942: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 7943: dtainfo->allowable_mask &= ~8;
7944: REG16(AX) = dtainfo - dtalist + 1;
1.1 root 7945: } else {
7946: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 7947: m_CF = 1;
1.1 root 7948: }
7949: }
7950:
7951: inline void msdos_int_21h_714fh()
7952: {
7953: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 7954: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 7955: WIN32_FIND_DATA fd;
7956:
1.1.1.14 root 7957: if(REG16(BX) - 1u >= MAX_DTAINFO) {
7958: REG16(AX) = 6;
1.1.1.13 root 7959: m_CF = 1;
7960: return;
7961: }
1.1.1.14 root 7962: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 7963: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
7964: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 7965: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 7966: if(!FindNextFile(dtainfo->find_handle, &fd)) {
7967: FindClose(dtainfo->find_handle);
7968: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7969: break;
7970: }
7971: }
7972: } else {
1.1.1.13 root 7973: FindClose(dtainfo->find_handle);
7974: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7975: }
7976: }
1.1.1.13 root 7977: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 7978: find->attrib = fd.dwFileAttributes;
7979: msdos_find_file_conv_local_time(&fd);
7980: if(REG16(SI) == 0) {
7981: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
7982: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
7983: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
7984: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
7985: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
7986: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
7987: } else {
7988: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
7989: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
7990: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
7991: }
7992: find->size_hi = fd.nFileSizeHigh;
7993: find->size_lo = fd.nFileSizeLow;
7994: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 7995: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14 root 7996: } else if(dtainfo->allowable_mask & 8) {
1.1 root 7997: // volume label
7998: find->attrib = 8;
7999: find->size_hi = find->size_lo = 0;
8000: strcpy(find->full_name, process->volume_label);
8001: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 8002: dtainfo->allowable_mask &= ~8;
1.1 root 8003: } else {
8004: REG16(AX) = 0x12;
1.1.1.3 root 8005: m_CF = 1;
1.1 root 8006: }
8007: }
8008:
8009: inline void msdos_int_21h_71a0h()
8010: {
8011: DWORD max_component_len, file_sys_flag;
8012:
1.1.1.14 root 8013: 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))) {
8014: REG16(BX) = (UINT16)file_sys_flag & (FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK | FILE_VOLUME_IS_COMPRESSED);
8015: REG16(BX) |= 0x4000; // supports LFN functions
1.1 root 8016: REG16(CX) = (UINT16)max_component_len; // 255
8017: REG16(DX) = (UINT16)max_component_len + 5; // 260
8018: } else {
8019: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 8020: m_CF = 1;
1.1 root 8021: }
8022: }
8023:
8024: inline void msdos_int_21h_71a1h()
8025: {
1.1.1.14 root 8026: if(REG16(BX) - 1u >= MAX_DTAINFO) {
8027: REG16(AX) = 6;
1.1.1.13 root 8028: m_CF = 1;
8029: return;
8030: }
1.1.1.14 root 8031: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 8032: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
8033: FindClose(dtainfo->find_handle);
8034: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 8035: }
8036: }
8037:
8038: inline void msdos_int_21h_71a6h()
8039: {
8040: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 8041: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
8042:
1.1.1.3 root 8043: UINT8 *buffer = (UINT8 *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 8044: struct _stat64 status;
8045: DWORD serial_number = 0;
8046:
1.1.1.20 root 8047: if(fd < process->max_files && file_handler[fd].valid) {
8048: if(_fstat64(fd, &status) == 0) {
8049: if(file_handler[fd].path[1] == ':') {
1.1 root 8050: // NOTE: we need to consider the network file path "\\host\share\"
8051: char volume[] = "A:\\";
1.1.1.20 root 8052: volume[0] = file_handler[fd].path[1];
1.1 root 8053: GetVolumeInformation(volume, NULL, 0, &serial_number, NULL, NULL, NULL, 0);
8054: }
1.1.1.20 root 8055: *(UINT32 *)(buffer + 0x00) = GetFileAttributes(file_handler[fd].path);
1.1 root 8056: *(UINT32 *)(buffer + 0x04) = (UINT32)(status.st_ctime & 0xffffffff);
8057: *(UINT32 *)(buffer + 0x08) = (UINT32)((status.st_ctime >> 32) & 0xffffffff);
8058: *(UINT32 *)(buffer + 0x0c) = (UINT32)(status.st_atime & 0xffffffff);
8059: *(UINT32 *)(buffer + 0x10) = (UINT32)((status.st_atime >> 32) & 0xffffffff);
8060: *(UINT32 *)(buffer + 0x14) = (UINT32)(status.st_mtime & 0xffffffff);
8061: *(UINT32 *)(buffer + 0x18) = (UINT32)((status.st_mtime >> 32) & 0xffffffff);
8062: *(UINT32 *)(buffer + 0x1c) = serial_number;
8063: *(UINT32 *)(buffer + 0x20) = (UINT32)((status.st_size >> 32) & 0xffffffff);
8064: *(UINT32 *)(buffer + 0x24) = (UINT32)(status.st_size & 0xffffffff);
8065: *(UINT32 *)(buffer + 0x28) = status.st_nlink;
1.1.1.14 root 8066: // this is dummy id and it will be changed when it is reopened...
1.1 root 8067: *(UINT32 *)(buffer + 0x2c) = 0;
1.1.1.20 root 8068: *(UINT32 *)(buffer + 0x30) = file_handler[fd].id;
1.1 root 8069: } else {
8070: REG16(AX) = errno;
1.1.1.3 root 8071: m_CF = 1;
1.1 root 8072: }
8073: } else {
8074: REG16(AX) = 0x06;
1.1.1.3 root 8075: m_CF = 1;
1.1 root 8076: }
8077: }
8078:
8079: inline void msdos_int_21h_71a7h()
8080: {
8081: switch(REG8(BL)) {
8082: case 0x00:
1.1.1.3 root 8083: if(!FileTimeToDosDateTime((FILETIME *)(mem + SREG_BASE(DS) + REG16(SI)), ®16(DX), ®16(CX))) {
1.1 root 8084: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 8085: m_CF = 1;
1.1 root 8086: }
8087: break;
8088: case 0x01:
8089: // NOTE: we need to check BH that shows 10-millisecond untils past time in CX
1.1.1.3 root 8090: if(!DosDateTimeToFileTime(REG16(DX), REG16(CX), (FILETIME *)(mem + SREG_BASE(ES) + REG16(DI)))) {
1.1 root 8091: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 8092: m_CF = 1;
1.1 root 8093: }
8094: break;
8095: default:
1.1.1.22 root 8096: 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 8097: REG16(AX) = 0x01;
1.1.1.3 root 8098: m_CF = 1;
1.1 root 8099: break;
8100: }
8101: }
8102:
8103: inline void msdos_int_21h_71a8h()
8104: {
8105: if(REG8(DH) == 0) {
8106: char tmp[MAX_PATH], fcb[MAX_PATH];
1.1.1.3 root 8107: strcpy(tmp, msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 8108: memset(fcb, 0x20, sizeof(fcb));
8109: int len = strlen(tmp);
1.1.1.21 root 8110: for(int i = 0, pos = 0; i < len; i++) {
1.1 root 8111: if(tmp[i] == '.') {
8112: pos = 8;
8113: } else {
8114: if(msdos_lead_byte_check(tmp[i])) {
8115: fcb[pos++] = tmp[i++];
8116: }
8117: fcb[pos++] = tmp[i];
8118: }
8119: }
1.1.1.3 root 8120: memcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), fcb, 11);
1.1 root 8121: } else {
1.1.1.3 root 8122: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 8123: }
8124: }
8125:
1.1.1.22 root 8126: inline void msdos_int_21h_71aah()
8127: {
8128: char drv[] = "A:", path[MAX_PATH];
8129: char *hoge=(char *)(mem + SREG_BASE(DS) + REG16(DX));
8130:
8131: if(REG8(BL) == 0) {
8132: drv[0] = 'A' + _getdrive() - 1;
8133: } else {
8134: drv[0] = 'A' + REG8(BL) - 1;
8135: }
8136: switch(REG8(BH)) {
8137: case 0x00:
8138: if(DefineDosDevice(0, drv, (char *)(mem + SREG_BASE(DS) + REG16(DX))) == 0) {
8139: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
8140: if(GetLogicalDrives() & bits) {
8141: REG16(AX) = 0x0f; // invalid drive
8142: } else {
8143: REG16(AX) = 0x03; // path not found
8144: }
8145: m_CF = 1;
8146: }
8147: break;
8148: case 0x01:
8149: if(DefineDosDevice(DDD_REMOVE_DEFINITION, drv, NULL) == 0) {
8150: REG16(AX) = 0x0f; // invalid drive
8151: m_CF = 1;
8152: }
8153: break;
8154: case 0x02:
8155: if(QueryDosDevice(drv, path, MAX_PATH) == 0) {
8156: REG16(AX) = 0x0f; // invalid drive
8157: m_CF = 1;
8158: } else if(strncmp(path, "\\??\\", 4) != 0) {
8159: REG16(AX) = 0x0f; // invalid drive
8160: m_CF = 1;
8161: } else {
8162: strcpy((char *)(mem + SREG_BASE(DS) + REG16(DX)), path + 4);
8163: }
8164: break;
8165: default:
8166: 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));
8167: REG16(AX) = 0x01;
8168: m_CF = 1;
8169: break;
8170: }
8171: }
8172:
1.1.1.14 root 8173: inline void msdos_int_21h_7300h()
8174: {
8175: if(REG8(AL) == 0) {
8176: REG8(AL) = REG8(CL);
8177: REG8(AH) = 0;
8178: } else {
8179: REG16(AX) = 0x01;
8180: m_CF = 1;
8181: }
8182: }
8183:
8184: inline void msdos_int_21h_7302h()
8185: {
8186: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
8187: UINT16 seg, ofs;
8188:
8189: if(REG16(CX) < 0x3f) {
8190: REG8(AL) = 0x18;
8191: m_CF = 1;
8192: } else if(!msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
8193: REG8(AL) = 0xff;
8194: m_CF = 1;
8195: } else {
8196: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 2, mem + (seg << 4) + ofs, sizeof(dpb_t));
8197: }
8198: }
8199:
1.1 root 8200: inline void msdos_int_21h_7303h()
8201: {
1.1.1.3 root 8202: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
8203: ext_space_info_t *info = (ext_space_info_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 8204: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
8205:
8206: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
8207: info->size_of_structure = sizeof(ext_space_info_t);
8208: info->structure_version = 0;
8209: info->sectors_per_cluster = sectors_per_cluster;
8210: info->bytes_per_sector = bytes_per_sector;
8211: info->available_clusters_on_drive = free_clusters;
8212: info->total_clusters_on_drive = total_clusters;
8213: info->available_sectors_on_drive = sectors_per_cluster * free_clusters;
8214: info->total_sectors_on_drive = sectors_per_cluster * total_clusters;
8215: info->available_allocation_units = free_clusters; // ???
8216: info->total_allocation_units = total_clusters; // ???
8217: } else {
8218: REG16(AX) = errno;
1.1.1.3 root 8219: m_CF = 1;
1.1 root 8220: }
8221: }
8222:
8223: inline void msdos_int_25h()
8224: {
8225: UINT16 seg, ofs;
8226: DWORD dwSize;
8227:
1.1.1.3 root 8228: #if defined(HAS_I386)
8229: I386OP(pushf)();
8230: #else
8231: PREFIX86(_pushf());
8232: #endif
1.1 root 8233:
8234: if(!(REG8(AL) < 26)) {
8235: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 8236: m_CF = 1;
1.1 root 8237: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
8238: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 8239: m_CF = 1;
1.1 root 8240: } else {
8241: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
8242: char dev[64];
8243: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
8244:
8245: HANDLE hFile = CreateFile(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
8246: if(hFile == INVALID_HANDLE_VALUE) {
8247: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 8248: m_CF = 1;
1.1 root 8249: } else {
1.1.1.19 root 8250: UINT32 top_sector = REG16(DX);
8251: UINT16 sector_num = REG16(CX);
8252: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX);
8253:
8254: if(sector_num == 0xffff) {
8255: top_sector = *(UINT32 *)(mem + buffer_addr + 0);
8256: sector_num = *(UINT16 *)(mem + buffer_addr + 4);
8257: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6);
8258: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8);
8259: buffer_addr = (seg << 4) + ofs;
8260: }
8261: // if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
8262: // REG8(AL) = 0x02; // drive not ready
8263: // m_CF = 1;
8264: // } else
8265: if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1.1 root 8266: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 8267: m_CF = 1;
1.1.1.19 root 8268: } else if(ReadFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 8269: REG8(AL) = 0x0b; // read error
1.1.1.3 root 8270: m_CF = 1;
1.1 root 8271: }
8272: CloseHandle(hFile);
8273: }
8274: }
8275: }
8276:
8277: inline void msdos_int_26h()
8278: {
8279: // this operation may cause serious damage for drives, so always returns error...
8280: UINT16 seg, ofs;
8281: DWORD dwSize;
8282:
1.1.1.3 root 8283: #if defined(HAS_I386)
8284: I386OP(pushf)();
8285: #else
8286: PREFIX86(_pushf());
8287: #endif
1.1 root 8288:
8289: if(!(REG8(AL) < 26)) {
8290: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 8291: m_CF = 1;
1.1 root 8292: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
8293: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 8294: m_CF = 1;
1.1 root 8295: } else {
8296: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
8297: char dev[64];
8298: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
8299:
8300: if(dpb->media_type == 0xf8) {
8301: // this drive is not a floppy
1.1.1.6 root 8302: // if(!(((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag & 0x40)) {
8303: // fatalerror("This application tried the absolute disk write to drive %c:\n", 'A' + REG8(AL));
8304: // }
1.1 root 8305: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 8306: m_CF = 1;
1.1 root 8307: } else {
8308: HANDLE hFile = CreateFile(dev, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
8309: if(hFile == INVALID_HANDLE_VALUE) {
8310: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 8311: m_CF = 1;
1.1 root 8312: } else {
1.1.1.19 root 8313: UINT32 top_sector = REG16(DX);
8314: UINT16 sector_num = REG16(CX);
8315: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX);
8316:
8317: if(sector_num == 0xffff) {
8318: top_sector = *(UINT32 *)(mem + buffer_addr + 0);
8319: sector_num = *(UINT16 *)(mem + buffer_addr + 4);
8320: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6);
8321: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8);
8322: buffer_addr = (seg << 4) + ofs;
8323: }
1.1 root 8324: if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
8325: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 8326: m_CF = 1;
1.1.1.19 root 8327: } else if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1.1 root 8328: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 8329: m_CF = 1;
1.1.1.19 root 8330: } else if(WriteFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 8331: REG8(AL) = 0x0a; // write error
1.1.1.3 root 8332: m_CF = 1;
1.1 root 8333: }
8334: CloseHandle(hFile);
8335: }
8336: }
8337: }
8338: }
8339:
8340: inline void msdos_int_27h()
8341: {
1.1.1.14 root 8342: msdos_mem_realloc(SREG(CS), (REG16(DX) + 15) >> 4, NULL);
1.1.1.3 root 8343: msdos_process_terminate(SREG(CS), retval | 0x300, 0);
1.1.1.14 root 8344:
8345: // int_21h_4bh succeeded
8346: m_CF = 0;
1.1 root 8347: }
8348:
8349: inline void msdos_int_29h()
8350: {
1.1.1.14 root 8351: #if 1
8352: // need to check escape sequences
1.1 root 8353: msdos_putch(REG8(AL));
1.1.1.14 root 8354: #else
8355: DWORD num;
8356: vram_flush();
1.1.1.23 root 8357: WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ®8(AL), 1, &num, NULL);
1.1.1.14 root 8358: cursor_moved = true;
8359: #endif
1.1 root 8360: }
8361:
8362: inline void msdos_int_2eh()
8363: {
8364: char tmp[MAX_PATH], command[MAX_PATH], opt[MAX_PATH];
8365: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 8366: strcpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(SI)));
1.1 root 8367: char *token = my_strtok(tmp, " ");
8368: strcpy(command, token);
8369: strcpy(opt, token + strlen(token) + 1);
8370:
8371: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
8372: param->env_seg = 0;
8373: param->cmd_line.w.l = 44;
8374: param->cmd_line.w.h = (WORK_TOP >> 4);
8375: param->fcb1.w.l = 24;
8376: param->fcb1.w.h = (WORK_TOP >> 4);
8377: param->fcb2.w.l = 24;
8378: param->fcb2.w.h = (WORK_TOP >> 4);
8379:
8380: memset(mem + WORK_TOP + 24, 0x20, 20);
8381:
8382: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
8383: cmd_line->len = strlen(opt);
8384: strcpy(cmd_line->cmd, opt);
8385: cmd_line->cmd[cmd_line->len] = 0x0d;
8386:
8387: msdos_process_exec(command, param, 0);
8388: REG8(AL) = 0;
8389: }
8390:
1.1.1.22 root 8391: inline void msdos_int_2fh_01h()
8392: {
8393: switch(REG8(AL)) {
8394: case 0x00:
8395: REG8(AL) = 0x01; // print.com is not installed, can't install
8396: break;
8397: default:
8398: 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));
8399: REG16(AX) = 0x01;
8400: m_CF = 1;
8401: break;
8402: }
8403: }
8404:
8405: inline void msdos_int_2fh_05h()
8406: {
8407: switch(REG8(AL)) {
8408: case 0x00:
8409: REG8(AL) = 0x01; // critical error handler is not installed, can't install
8410: break;
8411: default:
8412: 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));
8413: REG16(AX) = 0x01;
8414: m_CF = 1;
8415: break;
8416: }
8417: }
8418:
8419: inline void msdos_int_2fh_06h()
8420: {
8421: switch(REG8(AL)) {
8422: case 0x00:
8423: REG8(AL) = 0x01; // assign is not installed, can't install
8424: break;
8425: default:
8426: 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));
8427: REG16(AX) = 0x01;
8428: m_CF = 1;
8429: break;
8430: }
8431: }
8432:
8433: inline void msdos_int_2fh_08h()
8434: {
8435: switch(REG8(AL)) {
8436: case 0x00:
8437: REG8(AL) = 0x01; // driver.sys is not installed, can't install
8438: break;
8439: default:
8440: 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));
8441: REG16(AX) = 0x01;
8442: m_CF = 1;
8443: break;
8444: }
8445: }
8446:
8447: inline void msdos_int_2fh_10h()
8448: {
8449: switch(REG8(AL)) {
8450: case 0x00:
8451: REG8(AL) = 0x01; // share is not installed, can't install
8452: break;
8453: default:
8454: 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));
8455: REG16(AX) = 0x01;
8456: m_CF = 1;
8457: break;
8458: }
8459: }
8460:
8461: inline void msdos_int_2fh_11h()
8462: {
8463: switch(REG8(AL)) {
8464: case 0x00:
8465: REG8(AL) = 0x01; // mscdex is not installed, can't install
8466: break;
8467: default:
8468: 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));
8469: REG16(AX) = 0x01;
8470: m_CF = 1;
8471: break;
8472: }
8473: }
8474:
1.1.1.21 root 8475: inline void msdos_int_2fh_12h()
8476: {
8477: switch(REG8(AL)) {
1.1.1.22 root 8478: case 0x00:
8479: REG8(AL) = 0xff;
8480: break;
1.1.1.21 root 8481: case 0x16:
8482: if(REG16(BX) < 20) {
8483: SREG(ES) = SFT_TOP >> 4;
8484: i386_load_segment_descriptor(ES);
8485: REG16(DI) = 6 + 0x3b * REG16(BX);
8486:
8487: // update system file table
8488: UINT8* sft = mem + SFT_TOP + 6 + 0x3b * REG16(BX);
8489: if(file_handler[REG16(BX)].valid) {
8490: int count = 0;
8491: for(int i = 0; i < 20; i++) {
8492: if(msdos_psp_get_file_table(i, current_psp) == REG16(BX)) {
8493: count++;
8494: }
8495: }
8496: *(UINT16 *)(sft + 0x00) = count ? count : 0xffff;
8497: *(UINT32 *)(sft + 0x15) = _tell(REG16(BX));
8498: _lseek(REG16(BX), 0, SEEK_END);
8499: *(UINT32 *)(sft + 0x11) = _tell(REG16(BX));
8500: _lseek(REG16(BX), *(UINT32 *)(sft + 0x15), SEEK_SET);
8501: } else {
8502: memset(sft, 0, 0x3b);
8503: }
8504: } else {
8505: REG16(AX) = 0x06;
8506: m_CF = 1;
8507: }
8508: break;
8509: case 0x20:
8510: {
8511: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
8512:
8513: if(fd < 20) {
8514: SREG(ES) = current_psp;
8515: i386_load_segment_descriptor(ES);
8516: REG16(DI) = offsetof(psp_t, file_table) + fd;
8517: } else {
8518: REG16(AX) = 0x06;
8519: m_CF = 1;
8520: }
8521: }
8522: break;
1.1.1.22 root 8523: case 0x2e:
8524: if(REG8(DL) == 0x00 || REG8(DL) == 0x02 || REG8(DL) == 0x04 || REG8(DL) == 0x06) {
8525: SREG(ES) = ERR_TABLE_TOP >> 4;
8526: i386_load_segment_descriptor(ES);
8527: REG16(DI) = 0;
8528: }
8529: break;
8530: default:
8531: 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));
8532: REG16(AX) = 0x01;
8533: m_CF = 1;
8534: break;
8535: }
8536: }
8537:
8538: inline void msdos_int_2fh_14h()
8539: {
8540: switch(REG8(AL)) {
8541: case 0x00:
1.1.1.25 root 8542: REG8(AL) = 0xff; // nlsfunc.com is installed
8543: break;
8544: case 0x01:
8545: case 0x03:
8546: REG8(AL) = 0x00;
8547: active_code_page = REG16(BX);
8548: msdos_nls_tables_update();
8549: break;
8550: case 0x02:
8551: REG8(AL) = get_extended_country_info(REG16(BP));
8552: break;
8553: case 0x04:
8554: REG8(AL) = 0x00;
8555: get_country_info((country_info_t *)(mem + SREG_BASE(ES) + REG16(DI)));
1.1.1.22 root 8556: break;
8557: default:
8558: 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));
8559: REG16(AX) = 0x01;
8560: m_CF = 1;
8561: break;
8562: }
8563: }
8564:
8565: inline void msdos_int_2fh_15h()
8566: {
8567: switch(REG8(AL)) {
8568: case 0x00:
8569: // function not supported, do not clear AX
8570: break;
8571: case 0x0b:
8572: // mscdex.exe is not installed
8573: break;
8574: case 0xff:
8575: // corelcdx is not installed
8576: break;
1.1.1.21 root 8577: default:
1.1.1.22 root 8578: 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 8579: REG16(AX) = 0x01;
8580: m_CF = 1;
8581: break;
8582: }
8583: }
8584:
1.1 root 8585: inline void msdos_int_2fh_16h()
8586: {
8587: switch(REG8(AL)) {
8588: case 0x00:
1.1.1.14 root 8589: if(no_windows) {
8590: REG8(AL) = 0;
8591: } else {
1.1 root 8592: OSVERSIONINFO osvi;
8593: ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
8594: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
8595: GetVersionEx(&osvi);
8596: REG8(AL) = osvi.dwMajorVersion;
8597: REG8(AH) = osvi.dwMinorVersion;
8598: }
8599: break;
1.1.1.22 root 8600: case 0x0a:
8601: if(!no_windows) {
8602: OSVERSIONINFO osvi;
8603: ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
8604: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
8605: GetVersionEx(&osvi);
8606: REG16(AX) = 0x0000;
8607: REG8(BH) = osvi.dwMajorVersion;
8608: REG8(BL) = osvi.dwMinorVersion;
8609: REG16(CX) = 0x0003; // enhanced
8610: }
8611: break;
8612: case 0x0e:
8613: case 0x0f:
8614: case 0x11:
8615: case 0x12:
8616: case 0x13:
8617: case 0x14:
8618: case 0x87:
8619: // function not supported, do not clear AX
8620: break;
1.1.1.14 root 8621: case 0x80:
8622: Sleep(10);
8623: hardware_update();
8624: REG8(AL) = 0;
8625: break;
1.1.1.22 root 8626: case 0x8e:
8627: REG16(AX) = 0x00; // failed
8628: break;
1.1.1.20 root 8629: case 0x8f:
8630: switch(REG8(DH)) {
8631: case 0x00:
8632: case 0x02:
8633: case 0x03:
8634: REG16(AX) = 0x00;
8635: break;
8636: case 0x01:
8637: REG16(AX) = 0x168f;
8638: break;
8639: }
8640: break;
1.1 root 8641: default:
1.1.1.22 root 8642: 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));
8643: REG16(AX) = 0x01;
8644: m_CF = 1;
8645: break;
8646: }
8647: }
8648:
8649: inline void msdos_int_2fh_19h()
8650: {
8651: switch(REG8(AL)) {
8652: case 0x00:
8653: // shellb.com is not installed
8654: REG8(AL) = 0x00;
8655: break;
8656: case 0x01:
8657: case 0x02:
8658: case 0x03:
8659: case 0x04:
8660: REG16(AX) = 0x01;
8661: m_CF = 1;
8662: break;
8663: default:
8664: 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 8665: REG16(AX) = 0x01;
1.1.1.3 root 8666: m_CF = 1;
1.1 root 8667: break;
8668: }
8669: }
8670:
8671: inline void msdos_int_2fh_1ah()
8672: {
8673: switch(REG8(AL)) {
8674: case 0x00:
8675: // ansi.sys is installed
8676: REG8(AL) = 0xff;
8677: break;
8678: default:
1.1.1.22 root 8679: 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));
8680: REG16(AX) = 0x01;
8681: m_CF = 1;
8682: break;
8683: }
8684: }
8685:
8686: inline void msdos_int_2fh_1bh()
8687: {
8688: switch(REG8(AL)) {
8689: case 0x00:
8690: // xma2ems.sys is not installed
8691: REG8(AL) = 0x00;
8692: break;
8693: default:
8694: 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 8695: REG16(AX) = 0x01;
1.1.1.3 root 8696: m_CF = 1;
1.1 root 8697: break;
8698: }
8699: }
8700:
8701: inline void msdos_int_2fh_43h()
8702: {
8703: switch(REG8(AL)) {
8704: case 0x00:
1.1.1.19 root 8705: // xms is installed ?
8706: #ifdef SUPPORT_XMS
8707: if(support_xms) {
8708: REG8(AL) = 0x80;
8709: } else
8710: #endif
8711: REG8(AL) = 0x00;
8712: break;
8713: case 0x10:
8714: SREG(ES) = XMS_TOP >> 4;
8715: i386_load_segment_descriptor(ES);
1.1.1.26 root 8716: REG16(BX) = 0x15;
1.1 root 8717: break;
8718: default:
1.1.1.22 root 8719: 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));
8720: REG16(AX) = 0x01;
8721: m_CF = 1;
8722: break;
8723: }
8724: }
8725:
8726: inline void msdos_int_2fh_46h()
8727: {
8728: switch(REG8(AL)) {
8729: case 0x80:
8730: // windows v3.0 is not installed
8731: break;
8732: default:
8733: 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));
8734: REG16(AX) = 0x01;
8735: m_CF = 1;
8736: break;
8737: }
8738: }
8739:
8740: inline void msdos_int_2fh_48h()
8741: {
8742: switch(REG8(AL)) {
8743: case 0x00:
8744: // doskey is not installed
8745: break;
8746: case 0x10:
8747: msdos_int_21h_0ah();
8748: REG16(AX) = 0x00;
8749: break;
8750: default:
8751: 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 8752: REG16(AX) = 0x01;
1.1.1.3 root 8753: m_CF = 1;
1.1 root 8754: break;
8755: }
8756: }
8757:
8758: inline void msdos_int_2fh_4ah()
8759: {
1.1.1.19 root 8760: // hma is not installed
1.1 root 8761: switch(REG8(AL)) {
8762: case 0x01:
8763: case 0x02:
1.1.1.19 root 8764: // hma is not used
1.1.1.27! root 8765: REG16(BX) = 0x0000;
1.1.1.3 root 8766: SREG(ES) = 0xffff;
8767: i386_load_segment_descriptor(ES);
1.1 root 8768: REG16(DI) = 0xffff;
8769: break;
1.1.1.19 root 8770: case 0x03:
8771: // unable to allocate
8772: REG16(DI) = 0xffff;
8773: break;
8774: case 0x04:
8775: // function not supported, do not clear AX
8776: break;
1.1.1.22 root 8777: case 0x10: // smartdrv installation check
8778: case 0x11: // dblspace installation check
8779: break;
8780: default:
8781: 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));
8782: REG16(AX) = 0x01;
8783: m_CF = 1;
8784: break;
8785: }
8786: }
8787:
8788: inline void msdos_int_2fh_4bh()
8789: {
8790: switch(REG8(AL)) {
1.1.1.24 root 8791: case 0x01:
1.1.1.22 root 8792: case 0x02:
1.1.1.24 root 8793: // task switcher not loaded
8794: break;
8795: case 0x03:
8796: // this call is available from within DOSSHELL even if the task switcher is not installed
8797: REG16(AX) = REG16(BX) = 0x0000; // no more avaiable switcher id
1.1.1.22 root 8798: break;
1.1 root 8799: default:
1.1.1.22 root 8800: 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 8801: REG16(AX) = 0x01;
1.1.1.3 root 8802: m_CF = 1;
1.1 root 8803: break;
8804: }
8805: }
8806:
8807: inline void msdos_int_2fh_4fh()
8808: {
8809: switch(REG8(AL)) {
8810: case 0x00:
1.1.1.27! root 8811: // biling is installed
! 8812: REG16(AX) = 0x0000;
! 8813: REG8(DL) = 0x01; // major version
! 8814: REG8(DH) = 0x00; // minor version
1.1 root 8815: break;
8816: case 0x01:
1.1.1.27! root 8817: REG16(AX) = 0x0000;
1.1 root 8818: REG16(BX) = active_code_page;
8819: break;
8820: default:
1.1.1.22 root 8821: 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));
8822: REG16(AX) = 0x01;
8823: m_CF = 1;
8824: break;
8825: }
8826: }
8827:
8828: inline void msdos_int_2fh_55h()
8829: {
8830: switch(REG8(AL)) {
8831: case 0x00:
8832: case 0x01:
8833: // 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));
8834: break;
8835: default:
8836: 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 8837: REG16(AX) = 0x01;
1.1.1.3 root 8838: m_CF = 1;
1.1 root 8839: break;
8840: }
8841: }
8842:
1.1.1.24 root 8843: inline void msdos_int_2fh_adh()
8844: {
8845: switch(REG8(AL)) {
8846: case 0x00:
8847: // display.sys is installed
8848: REG8(AL) = 0xff;
8849: REG16(BX) = 0x100; // ???
8850: break;
8851: case 0x01:
8852: active_code_page = REG16(BX);
8853: msdos_nls_tables_update();
8854: REG16(AX) = 0x01;
8855: break;
8856: case 0x02:
8857: REG16(BX) = active_code_page;
8858: break;
8859: case 0x03:
8860: // FIXME
8861: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 1;
8862: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2) = 3;
8863: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4) = 1;
8864: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 6) = active_code_page;
8865: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 8) = active_code_page;
8866: break;
8867: case 0x80:
8868: break; // keyb.com is not installed
8869: default:
8870: 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));
8871: REG16(AX) = 0x01;
8872: m_CF = 1;
8873: break;
8874: }
8875: }
8876:
1.1 root 8877: inline void msdos_int_2fh_aeh()
8878: {
8879: switch(REG8(AL)) {
8880: case 0x00:
8881: REG8(AL) = 0;
8882: break;
8883: case 0x01:
8884: {
8885: char command[MAX_PATH];
8886: memset(command, 0, sizeof(command));
1.1.1.3 root 8887: memcpy(command, mem + SREG_BASE(DS) + REG16(SI) + 1, mem[SREG_BASE(DS) + REG16(SI)]);
1.1 root 8888:
8889: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
8890: param->env_seg = 0;
8891: param->cmd_line.w.l = 44;
8892: param->cmd_line.w.h = (WORK_TOP >> 4);
8893: param->fcb1.w.l = 24;
8894: param->fcb1.w.h = (WORK_TOP >> 4);
8895: param->fcb2.w.l = 24;
8896: param->fcb2.w.h = (WORK_TOP >> 4);
8897:
8898: memset(mem + WORK_TOP + 24, 0x20, 20);
8899:
8900: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
1.1.1.3 root 8901: cmd_line->len = mem[SREG_BASE(DS) + REG16(BX) + 1];
8902: memcpy(cmd_line->cmd, mem + SREG_BASE(DS) + REG16(BX) + 2, cmd_line->len);
1.1 root 8903: cmd_line->cmd[cmd_line->len] = 0x0d;
8904:
8905: if(msdos_process_exec(command, param, 0)) {
8906: REG16(AX) = 0x02;
1.1.1.3 root 8907: m_CF = 1;
1.1 root 8908: }
8909: }
8910: break;
8911: default:
1.1.1.22 root 8912: 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 8913: REG16(AX) = 0x01;
1.1.1.3 root 8914: m_CF = 1;
1.1 root 8915: break;
8916: }
8917: }
8918:
8919: inline void msdos_int_2fh_b7h()
8920: {
8921: switch(REG8(AL)) {
8922: case 0x00:
8923: // append is not installed
8924: REG8(AL) = 0;
8925: break;
1.1.1.22 root 8926: case 0x07:
8927: case 0x11:
8928: break;
1.1 root 8929: default:
1.1.1.22 root 8930: 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 8931: REG16(AX) = 0x01;
1.1.1.3 root 8932: m_CF = 1;
1.1 root 8933: break;
8934: }
8935: }
8936:
1.1.1.24 root 8937: inline void msdos_int_33h_0000h()
8938: {
8939: REG16(AX) = 0xffff; // hardware/driver installed
8940: REG16(BX) = MAX_MOUSE_BUTTONS;
8941: }
8942:
8943: inline void msdos_int_33h_0001h()
8944: {
8945: if(!mouse.active) {
8946: if(!(dwConsoleMode & ENABLE_MOUSE_INPUT)) {
8947: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode | ENABLE_MOUSE_INPUT);
8948: }
8949: mouse.active = true;
8950: pic[1].imr &= ~0x10; // enable irq12
8951: }
8952: }
8953:
8954: inline void msdos_int_33h_0002h()
8955: {
8956: if(mouse.active) {
8957: if(!(dwConsoleMode & ENABLE_MOUSE_INPUT)) {
8958: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode);
8959: }
8960: mouse.active = false;
8961: pic[1].imr |= 0x10; // disable irq12
8962: }
8963: }
8964:
8965: inline void msdos_int_33h_0003h()
8966: {
8967: REG16(BX) = mouse.get_buttons();
8968: REG16(CX) = max(mouse.min_position.x, min(mouse.max_position.x, mouse.position.x));
8969: REG16(DX) = max(mouse.min_position.y, min(mouse.max_position.y, mouse.position.y));
8970: }
8971:
8972: inline void msdos_int_33h_0005h()
8973: {
8974: if(REG16(BX) < MAX_MOUSE_BUTTONS) {
8975: int idx = REG16(BX);
8976: REG16(BX) = mouse.buttons[idx].pressed_times;
8977: REG16(CX) = max(mouse.min_position.x, min(mouse.max_position.x, mouse.buttons[idx].pressed_position.x));
8978: REG16(DX) = max(mouse.min_position.y, min(mouse.max_position.y, mouse.buttons[idx].pressed_position.y));
8979: mouse.buttons[idx].pressed_times = 0;
8980: } else {
8981: REG16(BX) = REG16(CX) = REG16(DX) = 0x0000;
8982: }
8983: REG16(AX) = mouse.get_buttons();
8984: }
8985:
8986: inline void msdos_int_33h_0006h()
8987: {
8988: if(REG16(BX) < MAX_MOUSE_BUTTONS) {
8989: int idx = REG16(BX);
8990: REG16(BX) = mouse.buttons[idx].released_times;
8991: REG16(CX) = max(mouse.min_position.x, min(mouse.max_position.x, mouse.buttons[idx].released_position.x));
8992: REG16(DX) = max(mouse.min_position.y, min(mouse.max_position.y, mouse.buttons[idx].released_position.y));
8993: mouse.buttons[idx].released_times = 0;
8994: } else {
8995: REG16(BX) = REG16(CX) = REG16(DX) = 0x0000;
8996: }
8997: REG16(AX) = mouse.get_buttons();
8998: }
8999:
9000: inline void msdos_int_33h_0007h()
9001: {
9002: mouse.min_position.x = min(REG16(CX), REG16(DX));
9003: mouse.max_position.x = max(REG16(CX), REG16(DX));
9004: }
9005:
9006: inline void msdos_int_33h_0008h()
9007: {
9008: mouse.min_position.y = min(REG16(CX), REG16(DX));
9009: mouse.max_position.y = max(REG16(CX), REG16(DX));
9010: }
9011:
9012: inline void msdos_int_33h_0009h()
9013: {
9014: mouse.hot_spot[0] = REG16(BX);
9015: mouse.hot_spot[1] = REG16(CX);
9016: }
9017:
9018: inline void msdos_int_33h_000bh()
9019: {
9020: int dx = (mouse.position.x - mouse.prev_position.x) * mouse.mickey.x / 8;
9021: int dy = (mouse.position.y - mouse.prev_position.y) * mouse.mickey.y / 8;
9022: mouse.prev_position.x = mouse.position.x;
9023: mouse.prev_position.y = mouse.position.y;
9024: REG16(CX) = dx;
9025: REG16(DX) = dy;
9026: }
9027:
9028: inline void msdos_int_33h_000ch()
9029: {
9030: mouse.call_mask = REG16(CX);
9031: mouse.call_addr.w.l = REG16(DX);
9032: mouse.call_addr.w.h = SREG(ES);
9033: }
9034:
9035: inline void msdos_int_33h_000fh()
9036: {
9037: mouse.mickey.x = REG16(CX);
9038: mouse.mickey.y = REG16(DX);
9039: }
9040:
9041: inline void msdos_int_33h_0011h()
9042: {
9043: REG16(AX) = 0xffff;
9044: REG16(BX) = MAX_MOUSE_BUTTONS;
9045: }
9046:
9047: inline void msdos_int_33h_0014h()
9048: {
9049: UINT16 old_mask = mouse.call_mask;
9050: UINT16 old_ofs = mouse.call_addr.w.l;
9051: UINT16 old_seg = mouse.call_addr.w.h;
9052:
9053: mouse.call_mask = REG16(CX);
9054: mouse.call_addr.w.l = REG16(DX);
9055: mouse.call_addr.w.h = SREG(ES);
9056:
9057: REG16(CX) = old_mask;
9058: REG16(DX) = old_ofs;
9059: SREG(ES) = old_seg;
9060: i386_load_segment_descriptor(ES);
9061: }
9062:
9063: inline void msdos_int_33h_0015h()
9064: {
9065: REG16(BX) = sizeof(mouse);
9066: }
9067:
9068: inline void msdos_int_33h_0016h()
9069: {
9070: memcpy(mem + SREG_BASE(ES) + REG16(DX), &mouse, sizeof(mouse));
9071: }
9072:
9073: inline void msdos_int_33h_0017h()
9074: {
9075: memcpy(&mouse, mem + SREG_BASE(ES) + REG16(DX), sizeof(mouse));
9076: }
9077:
9078: inline void msdos_int_33h_001ah()
9079: {
9080: mouse.sensitivity[0] = REG16(BX);
9081: mouse.sensitivity[1] = REG16(CX);
9082: mouse.sensitivity[2] = REG16(DX);
9083: }
9084:
9085: inline void msdos_int_33h_001bh()
9086: {
9087: REG16(BX) = mouse.sensitivity[0];
9088: REG16(CX) = mouse.sensitivity[1];
9089: REG16(DX) = mouse.sensitivity[2];
9090: }
9091:
9092: inline void msdos_int_33h_001dh()
9093: {
9094: mouse.display_page = REG16(BX);
9095: }
9096:
9097: inline void msdos_int_33h_001eh()
9098: {
9099: REG16(BX) = mouse.display_page;
9100: }
9101:
9102: inline void msdos_int_33h_0021h()
9103: {
9104: REG16(AX) = 0xffff;
9105: REG16(BX) = MAX_MOUSE_BUTTONS;
9106: }
9107:
9108: inline void msdos_int_33h_0022h()
9109: {
9110: mouse.language = REG16(BX);
9111: }
9112:
9113: inline void msdos_int_33h_0023h()
9114: {
9115: REG16(BX) = mouse.language;
9116: }
9117:
9118: inline void msdos_int_33h_0024h()
9119: {
9120: REG16(BX) = 0x0805; // V8.05
9121: REG16(CX) = 0x0400; // PS/2
9122: }
9123:
9124: inline void msdos_int_33h_0026h()
9125: {
9126: REG16(BX) = 0x0000;
9127: REG16(CX) = mouse.max_position.x;
9128: REG16(DX) = mouse.max_position.y;
9129: }
9130:
9131: inline void msdos_int_33h_002ah()
9132: {
9133: REG16(AX) = mouse.active ? 0 : 0xffff;
9134: REG16(BX) = mouse.hot_spot[0];
9135: REG16(CX) = mouse.hot_spot[1];
9136: REG16(DX) = 4; // PS/2
9137: }
9138:
9139: inline void msdos_int_33h_0031h()
9140: {
9141: REG16(AX) = mouse.min_position.x;
9142: REG16(BX) = mouse.min_position.y;
9143: REG16(CX) = mouse.max_position.x;
9144: REG16(DX) = mouse.max_position.y;
9145: }
9146:
9147: inline void msdos_int_33h_0032h()
9148: {
9149: REG16(AX) = 0;
9150: // REG16(AX) |= 0x8000; // 0025h
9151: REG16(AX) |= 0x4000; // 0026h
9152: // REG16(AX) |= 0x2000; // 0027h
9153: // REG16(AX) |= 0x1000; // 0028h
9154: // REG16(AX) |= 0x0800; // 0029h
9155: REG16(AX) |= 0x0400; // 002ah
9156: // REG16(AX) |= 0x0200; // 002bh
9157: // REG16(AX) |= 0x0100; // 002ch
9158: // REG16(AX) |= 0x0080; // 002dh
9159: // REG16(AX) |= 0x0040; // 002eh
9160: REG16(AX) |= 0x0020; // 002fh
9161: // REG16(AX) |= 0x0010; // 0030h
9162: REG16(AX) |= 0x0008; // 0031h
9163: REG16(AX) |= 0x0004; // 0032h
9164: // REG16(AX) |= 0x0002; // 0033h
9165: // REG16(AX) |= 0x0001; // 0034h
9166: }
9167:
1.1.1.19 root 9168: inline void msdos_int_67h_40h()
9169: {
9170: if(!support_ems) {
9171: REG8(AH) = 0x84;
9172: } else {
9173: REG8(AH) = 0x00;
9174: }
9175: }
9176:
9177: inline void msdos_int_67h_41h()
9178: {
9179: if(!support_ems) {
9180: REG8(AH) = 0x84;
9181: } else {
9182: REG8(AH) = 0x00;
9183: REG16(BX) = EMS_TOP >> 4;
9184: }
9185: }
9186:
9187: inline void msdos_int_67h_42h()
9188: {
9189: if(!support_ems) {
9190: REG8(AH) = 0x84;
9191: } else {
9192: REG8(AH) = 0x00;
9193: REG16(BX) = free_ems_pages;
9194: REG16(DX) = MAX_EMS_PAGES;
9195: }
9196: }
9197:
9198: inline void msdos_int_67h_43h()
9199: {
9200: if(!support_ems) {
9201: REG8(AH) = 0x84;
9202: } else if(REG16(BX) > MAX_EMS_PAGES) {
9203: REG8(AH) = 0x87;
9204: } else if(REG16(BX) > free_ems_pages) {
9205: REG8(AH) = 0x88;
9206: } else if(REG16(BX) == 0) {
9207: REG8(AH) = 0x89;
9208: } else {
9209: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
9210: if(!ems_handles[i].allocated) {
9211: ems_allocate_pages(i, REG16(BX));
9212: REG8(AH) = 0x00;
9213: REG16(DX) = i;
9214: return;
9215: }
9216: }
9217: REG8(AH) = 0x85;
9218: }
9219: }
9220:
9221: inline void msdos_int_67h_44h()
9222: {
9223: if(!support_ems) {
9224: REG8(AH) = 0x84;
9225: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
9226: REG8(AH) = 0x83;
9227: } else if(!(REG16(BX) == 0xffff || REG16(BX) < ems_handles[REG16(DX)].pages)) {
9228: REG8(AH) = 0x8a;
9229: // } else if(!(REG8(AL) < 4)) {
9230: // REG8(AH) = 0x8b;
9231: } else if(REG16(BX) == 0xffff) {
9232: ems_unmap_page(REG8(AL) & 3);
9233: REG8(AH) = 0x00;
9234: } else {
9235: ems_map_page(REG8(AL) & 3, REG16(DX), REG16(BX));
9236: REG8(AH) = 0x00;
9237: }
9238: }
9239:
9240: inline void msdos_int_67h_45h()
9241: {
9242: if(!support_ems) {
9243: REG8(AH) = 0x84;
9244: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
9245: REG8(AH) = 0x83;
9246: } else {
9247: ems_release_pages(REG16(DX));
9248: REG8(AH) = 0x00;
9249: }
9250: }
9251:
9252: inline void msdos_int_67h_46h()
9253: {
9254: if(!support_ems) {
9255: REG8(AH) = 0x84;
9256: } else {
9257: REG16(AX) = 0x0032; // EMS 3.2
9258: // REG16(AX) = 0x0040; // EMS 4.0
9259: }
9260: }
9261:
9262: inline void msdos_int_67h_47h()
9263: {
9264: // NOTE: the map data should be stored in the specified ems page, not process data
9265: process_t *process = msdos_process_info_get(current_psp);
9266:
9267: if(!support_ems) {
9268: REG8(AH) = 0x84;
9269: // } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
9270: // REG8(AH) = 0x83;
9271: } else if(process->ems_pages_stored) {
9272: REG8(AH) = 0x8d;
9273: } else {
9274: for(int i = 0; i < 4; i++) {
9275: process->ems_pages[i].handle = ems_pages[i].handle;
9276: process->ems_pages[i].page = ems_pages[i].page;
9277: process->ems_pages[i].mapped = ems_pages[i].mapped;
9278: }
9279: process->ems_pages_stored = true;
9280: REG8(AH) = 0x00;
9281: }
9282: }
9283:
9284: inline void msdos_int_67h_48h()
9285: {
9286: // NOTE: the map data should be restored from the specified ems page, not process data
9287: process_t *process = msdos_process_info_get(current_psp);
9288:
9289: if(!support_ems) {
9290: REG8(AH) = 0x84;
9291: // } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
9292: // REG8(AH) = 0x83;
9293: } else if(!process->ems_pages_stored) {
9294: REG8(AH) = 0x8e;
9295: } else {
9296: for(int i = 0; i < 4; i++) {
9297: if(process->ems_pages[i].mapped) {
9298: ems_map_page(i, process->ems_pages[i].handle, process->ems_pages[i].page);
9299: } else {
9300: ems_unmap_page(i);
9301: }
9302: }
9303: process->ems_pages_stored = false;
9304: REG8(AH) = 0x00;
9305: }
9306: }
9307:
9308: inline void msdos_int_67h_4bh()
9309: {
9310: if(!support_ems) {
9311: REG8(AH) = 0x84;
9312: } else {
9313: REG8(AH) = 0x00;
9314: REG16(BX) = 0;
9315: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
9316: if(ems_handles[i].allocated) {
9317: REG16(BX)++;
9318: }
9319: }
9320: }
9321: }
9322:
9323: inline void msdos_int_67h_4ch()
9324: {
9325: if(!support_ems) {
9326: REG8(AH) = 0x84;
9327: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
9328: REG8(AH) = 0x83;
9329: } else {
9330: REG8(AH) = 0x00;
9331: REG16(BX) = ems_handles[REG16(DX)].pages;
9332: }
9333: }
9334:
9335: inline void msdos_int_67h_4dh()
9336: {
9337: if(!support_ems) {
9338: REG8(AH) = 0x84;
9339: } else {
9340: REG8(AH) = 0x00;
9341: REG16(BX) = 0;
9342: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
9343: if(ems_handles[i].allocated) {
9344: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 0) = i;
9345: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 2) = ems_handles[i].pages;
9346: REG16(BX)++;
9347: }
9348: }
9349: }
9350: }
9351:
1.1.1.20 root 9352: inline void msdos_int_67h_4eh()
9353: {
9354: if(!support_ems) {
9355: REG8(AH) = 0x84;
9356: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01 || REG8(AL) == 0x02) {
9357: if(REG8(AL) == 0x00 || REG8(AL) == 0x02) {
9358: // save page map
9359: for(int i = 0; i < 4; i++) {
9360: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = ems_pages[i].mapped ? ems_pages[i].handle : 0xffff;
9361: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = ems_pages[i].mapped ? ems_pages[i].page : 0xffff;
9362: }
9363: }
9364: if(REG8(AL) == 0x01 || REG8(AL) == 0x02) {
9365: // restore page map
9366: for(int i = 0; i < 4; i++) {
9367: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0);
9368: UINT16 page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2);
9369:
9370: if(handle < MAX_EMS_HANDLES && ems_handles[handle].allocated && page < ems_handles[handle].pages) {
9371: ems_map_page(i, handle, page);
9372: } else {
9373: ems_unmap_page(i);
9374: }
9375: }
9376: }
9377: REG8(AH) = 0x00;
9378: } else if(REG8(AL) == 0x03) {
9379: REG8(AH) = 0x00;
1.1.1.21 root 9380: REG8(AL) = 4 * 4;
9381: } else {
1.1.1.22 root 9382: 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 9383: REG8(AH) = 0x8f;
9384: }
9385: }
9386:
9387: inline void msdos_int_67h_4fh()
9388: {
9389: if(!support_ems) {
9390: REG8(AH) = 0x84;
9391: } else if(REG8(AL) == 0x00) {
9392: int count = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI));
9393:
9394: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI)) = count;
9395: for(int i = 0; i < count; i++) {
9396: UINT16 segment = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 2 * i);
9397: UINT16 physical = ((segment << 4) - EMS_TOP) / 0x4000;
9398:
9399: // if(!(physical < 4)) {
9400: // REG8(AH) = 0x8b;
9401: // return;
9402: // }
9403: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 0) = segment;
9404: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 2) = ems_pages[physical & 3].handle;
9405: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 4) = ems_pages[physical & 3].mapped ? ems_pages[physical & 3].page : 0xffff;
9406: }
9407: REG8(AH) = 0x00;
9408: } else if(REG8(AL) == 0x01) {
9409: int count = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI));
9410:
9411: for(int i = 0; i < count; i++) {
9412: UINT16 segment = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 0);
9413: UINT16 physical = ((segment << 4) - EMS_TOP) / 0x4000;
9414: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 2);
9415: UINT16 logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 4);
9416:
9417: // if(!(physical < 4)) {
9418: // REG8(AH) = 0x8b;
9419: // return;
9420: // } else
9421: if(!(handle < MAX_EMS_HANDLES && ems_handles[handle].allocated)) {
9422: REG8(AH) = 0x83;
9423: return;
9424: } else if(logical == 0xffff) {
9425: ems_unmap_page(physical & 3);
9426: } else if(logical < ems_handles[handle].pages) {
9427: ems_map_page(physical & 3, handle, logical);
9428: } else {
9429: REG8(AH) = 0x8a;
9430: return;
9431: }
9432: }
9433: REG8(AH) = 0x00;
9434: } else if(REG8(AL) == 0x02) {
9435: REG8(AH) = 0x00;
9436: REG8(AL) = 2 + REG16(BX) * 6;
1.1.1.20 root 9437: } else {
1.1.1.22 root 9438: 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 9439: REG8(AH) = 0x8f;
9440: }
9441: }
9442:
9443: inline void msdos_int_67h_50h()
9444: {
9445: if(!support_ems) {
9446: REG8(AH) = 0x84;
9447: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
9448: REG8(AH) = 0x83;
9449: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
9450: for(int i = 0; i < REG16(CX); i++) {
9451: int logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0);
9452: int physical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2);
9453:
9454: if(REG8(AL) == 0x01) {
9455: physical = ((physical << 4) - EMS_TOP) / 0x4000;
9456: }
9457: // if(!(physical < 4)) {
9458: // REG8(AH) = 0x8b;
9459: // return;
9460: // } else
9461: if(logical == 0xffff) {
9462: ems_unmap_page(physical & 3);
9463: } else if(logical < ems_handles[REG16(DX)].pages) {
9464: ems_map_page(physical & 3, REG16(DX), logical);
9465: } else {
9466: REG8(AH) = 0x8a;
9467: return;
9468: }
9469: }
9470: REG8(AH) = 0x00;
9471: } else {
1.1.1.22 root 9472: 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 9473: REG8(AH) = 0x8f;
9474: }
9475: }
9476:
1.1.1.19 root 9477: inline void msdos_int_67h_51h()
9478: {
9479: if(!support_ems) {
9480: REG8(AH) = 0x84;
9481: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
9482: REG8(AH) = 0x83;
9483: } else if(REG16(BX) > MAX_EMS_PAGES) {
9484: REG8(AH) = 0x87;
9485: } else if(REG16(BX) > free_ems_pages + ems_handles[REG16(DX)].pages) {
9486: REG8(AH) = 0x88;
9487: } else {
9488: ems_reallocate_pages(REG16(DX), REG16(BX));
9489: REG8(AH) = 0x00;
9490: }
9491: }
9492:
1.1.1.20 root 9493: inline void msdos_int_67h_52h()
9494: {
9495: if(!support_ems) {
9496: REG8(AH) = 0x84;
9497: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
9498: REG8(AH) = 0x83;
9499: } else if(REG8(AL) == 0x00) {
9500: REG8(AL) = 0x00; // handle is volatile
9501: REG8(AH) = 0x00;
9502: } else if(REG8(AL) == 0x01) {
9503: if(REG8(BL) == 0x00) {
9504: REG8(AH) = 0x00;
9505: } else {
9506: REG8(AH) = 0x90; // undefined attribute type
9507: }
9508: } else if(REG8(AL) == 0x02) {
9509: REG8(AL) = 0x00; // only volatile handles supported
9510: REG8(AH) = 0x00;
9511: } else {
1.1.1.22 root 9512: 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 9513: REG8(AH) = 0x8f;
9514: }
9515: }
9516:
1.1.1.19 root 9517: inline void msdos_int_67h_53h()
9518: {
9519: if(!support_ems) {
9520: REG8(AH) = 0x84;
9521: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
9522: REG8(AH) = 0x83;
9523: } else if(REG8(AL) == 0x00) {
9524: memcpy(mem + SREG_BASE(ES) + REG16(DI), ems_handles[REG16(DX)].name, 8);
9525: REG8(AH) = 0x00;
9526: } else if(REG8(AL) == 0x01) {
9527: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
9528: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) {
9529: REG8(AH) = 0xa1;
9530: return;
9531: }
9532: }
9533: REG8(AH) = 0x00;
9534: memcpy(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8);
9535: } else {
1.1.1.22 root 9536: 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 9537: REG8(AH) = 0x8f;
1.1.1.19 root 9538: }
9539: }
9540:
9541: inline void msdos_int_67h_54h()
9542: {
9543: if(!support_ems) {
9544: REG8(AH) = 0x84;
9545: } else if(REG8(AL) == 0x00) {
9546: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
9547: if(ems_handles[i].allocated) {
9548: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, ems_handles[i].name, 10);
9549: } else {
9550: memset(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, 0, 10);
9551: }
9552: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 0) = i;
9553: }
9554: REG8(AH) = 0x00;
9555: REG8(AL) = MAX_EMS_HANDLES;
9556: } else if(REG8(AL) == 0x01) {
9557: REG8(AH) = 0xa0; // not found
9558: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
9559: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) {
9560: REG8(AH) = 0x00;
9561: REG16(DX) = i;
9562: break;
9563: }
9564: }
9565: } else if(REG8(AL) == 0x02) {
9566: REG8(AH) = 0x00;
9567: REG16(BX) = MAX_EMS_HANDLES;
9568: } else {
1.1.1.22 root 9569: 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 9570: REG8(AH) = 0x8f;
9571: }
9572: }
9573:
9574: inline void msdos_int_67h_57h_tmp()
9575: {
9576: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00);
9577: UINT8 src_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04);
9578: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x05);
9579: UINT16 src_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07);
9580: UINT16 src_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x09);
9581: UINT8 dest_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0b);
9582: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c);
9583: UINT16 dest_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0e);
9584: UINT16 dest_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x10);
9585:
9586: UINT8 *src_buffer, *dest_buffer;
9587: UINT32 src_addr, dest_addr;
9588: UINT32 src_addr_max, dest_addr_max;
9589:
9590: if(src_type == 0) {
9591: src_buffer = mem;
9592: src_addr = (src_seg << 4) + src_ofs;
9593: src_addr_max = MAX_MEM;
9594: } else {
9595: if(!(src_handle < MAX_EMS_HANDLES && ems_handles[src_handle].allocated)) {
9596: REG8(AH) = 0x83;
9597: return;
9598: } else if(!(src_seg < ems_handles[src_handle].pages)) {
9599: REG8(AH) = 0x8a;
9600: return;
9601: }
9602: src_buffer = ems_handles[src_handle].buffer + 0x4000 * src_seg;
9603: src_addr = src_ofs;
9604: src_addr_max = 0x4000;
9605: }
9606: if(dest_type == 0) {
9607: dest_buffer = mem;
9608: dest_addr = (dest_seg << 4) + dest_ofs;
9609: dest_addr_max = MAX_MEM;
9610: } else {
9611: if(!(dest_handle < MAX_EMS_HANDLES && ems_handles[dest_handle].allocated)) {
9612: REG8(AH) = 0x83;
9613: return;
9614: } else if(!(dest_seg < ems_handles[dest_handle].pages)) {
9615: REG8(AH) = 0x8a;
9616: return;
9617: }
9618: dest_buffer = ems_handles[dest_handle].buffer + 0x4000 * dest_seg;
9619: dest_addr = dest_ofs;
9620: dest_addr_max = 0x4000;
9621: }
9622: for(int i = 0; i < copy_length; i++) {
9623: if(src_addr < src_addr_max && dest_addr < dest_addr_max) {
9624: if(REG8(AL) == 0x00) {
9625: dest_buffer[dest_addr++] = src_buffer[src_addr++];
9626: } else if(REG8(AL) == 0x01) {
9627: UINT8 tmp = dest_buffer[dest_addr];
9628: dest_buffer[dest_addr++] = src_buffer[src_addr];
9629: src_buffer[src_addr++] = tmp;
9630: }
9631: } else {
9632: REG8(AH) = 0x93;
9633: return;
9634: }
9635: }
9636: REG8(AH) = 0x80;
9637: }
9638:
9639: inline void msdos_int_67h_57h()
9640: {
9641: if(!support_ems) {
9642: REG8(AH) = 0x84;
9643: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
9644: struct {
9645: UINT16 handle;
9646: UINT16 page;
9647: bool mapped;
9648: } tmp_pages[4];
9649:
9650: // unmap pages to copy memory data to ems buffer
9651: for(int i = 0; i < 4; i++) {
9652: tmp_pages[i].handle = ems_pages[i].handle;
9653: tmp_pages[i].page = ems_pages[i].page;
9654: tmp_pages[i].mapped = ems_pages[i].mapped;
9655: ems_unmap_page(i);
9656: }
9657:
9658: // run move/exchange operation
9659: msdos_int_67h_57h_tmp();
9660:
9661: // restore unmapped pages
9662: for(int i = 0; i < 4; i++) {
9663: if(tmp_pages[i].mapped) {
9664: ems_map_page(i, tmp_pages[i].handle, tmp_pages[i].page);
9665: }
9666: }
9667: } else {
1.1.1.22 root 9668: 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 9669: REG8(AH) = 0x8f;
9670: }
9671: }
9672:
9673: inline void msdos_int_67h_58h()
9674: {
9675: if(!support_ems) {
9676: REG8(AH) = 0x84;
9677: } else if(REG8(AL) == 0x00) {
9678: for(int i = 0; i < 4; i++) {
9679: *(UINT16 *)(mem +SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = (EMS_TOP + 0x4000 * i) >> 4;
9680: *(UINT16 *)(mem +SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = i;
9681: }
9682: REG8(AH) = 0x00;
9683: REG16(CX) = 4;
9684: } else if(REG8(AL) == 0x01) {
9685: REG8(AH) = 0x00;
9686: REG16(CX) = 4;
9687: } else {
1.1.1.22 root 9688: 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 9689: REG8(AH) = 0x8f;
9690: }
9691: }
9692:
9693: inline void msdos_int_67h_5ah()
9694: {
9695: if(!support_ems) {
1.1.1.19 root 9696: REG8(AH) = 0x84;
1.1.1.20 root 9697: } else if(REG16(BX) > MAX_EMS_PAGES) {
9698: REG8(AH) = 0x87;
9699: } else if(REG16(BX) > free_ems_pages) {
9700: REG8(AH) = 0x88;
9701: // } else if(REG16(BX) == 0) {
9702: // REG8(AH) = 0x89;
9703: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
9704: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
9705: if(!ems_handles[i].allocated) {
9706: ems_allocate_pages(i, REG16(BX));
9707: REG8(AH) = 0x00;
9708: REG16(DX) = i;
9709: return;
9710: }
9711: }
9712: REG8(AH) = 0x85;
9713: } else {
1.1.1.22 root 9714: 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 9715: REG8(AH) = 0x8f;
1.1.1.19 root 9716: }
9717: }
9718:
9719: #ifdef SUPPORT_XMS
9720:
1.1.1.26 root 9721: inline void msdos_xms_init()
9722: {
9723: memset(xms_handles, 0, sizeof(xms_handles));
9724: xms_a20_local_enb_count = 0;
9725: }
9726:
1.1.1.19 root 9727: inline void msdos_call_xms_00h()
9728: {
9729: REG16(AX) = 0x0270; // V2.70
9730: REG16(BX) = 0x0000;
9731: // REG16(DX) = 0x0000; // hma does not exist
9732: REG16(DX) = 0x0001; // hma does exist
9733: }
9734:
9735: inline void msdos_call_xms_01h()
9736: {
9737: REG16(AX) = 0x0000;
9738: // REG8(BL) = 0x90; // hma does not exist
9739: REG8(BL) = 0x91; // hma is already used
9740: }
9741:
9742: inline void msdos_call_xms_02h()
9743: {
9744: REG16(AX) = 0x0000;
9745: // REG8(BL) = 0x90; // hma does not exist
9746: REG8(BL) = 0x91; // hma is already used
9747: }
9748:
9749: inline void msdos_call_xms_03h()
9750: {
9751: i386_set_a20_line(1);
9752: REG16(AX) = 0x0001;
9753: REG8(BL) = 0x00;
9754: }
9755:
9756: inline void msdos_call_xms_04h()
9757: {
1.1.1.21 root 9758: i386_set_a20_line(0);
9759: REG16(AX) = 0x0001;
9760: REG8(BL) = 0x00;
1.1.1.19 root 9761: }
9762:
9763: inline void msdos_call_xms_05h()
9764: {
9765: i386_set_a20_line(1);
9766: REG16(AX) = 0x0001;
9767: REG8(BL) = 0x00;
1.1.1.21 root 9768: xms_a20_local_enb_count++;
1.1.1.19 root 9769: }
9770:
9771: void msdos_call_xms_06h()
9772: {
1.1.1.21 root 9773: if(xms_a20_local_enb_count > 0) {
9774: xms_a20_local_enb_count--;
9775: }
9776: if(xms_a20_local_enb_count == 0) {
1.1.1.19 root 9777: i386_set_a20_line(0);
1.1.1.21 root 9778: }
9779: if((m_a20_mask >> 20) & 1) {
1.1.1.19 root 9780: REG16(AX) = 0x0000;
9781: REG8(BL) = 0x94;
1.1.1.21 root 9782: } else {
9783: REG16(AX) = 0x0001;
9784: REG8(BL) = 0x00;
1.1.1.19 root 9785: }
9786: }
9787:
9788: inline void msdos_call_xms_07h()
9789: {
9790: REG16(AX) = (m_a20_mask >> 20) & 1;
9791: REG8(BL) = 0x00;
9792: }
9793:
9794: inline void msdos_call_xms_08h()
9795: {
9796: REG16(AX) = REG16(DX) = 0x0000;
9797:
9798: int mcb_seg = EMB_TOP >> 4;
9799:
9800: while(1) {
9801: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
9802:
9803: if(mcb->psp == 0) {
9804: if(REG16(AX) < mcb->size_kb()) {
9805: REG16(AX) = mcb->size_kb();
9806: }
9807: REG16(DX) += mcb->size_kb();
9808: }
9809: if(mcb->mz == 'Z') {
9810: break;
9811: }
9812: mcb_seg += 1 + mcb->paragraphs();
9813: }
9814:
9815: if(REG16(AX) == 0 && REG16(DX) == 0) {
9816: REG8(BL) = 0xa0;
9817: } else {
9818: REG8(BL) = 0x00;
9819: }
9820: }
9821:
9822: inline void msdos_call_xms_09h()
9823: {
9824: for(int i = 1; i <= MAX_XMS_HANDLES; i++) {
9825: if(!xms_handles[i].allocated) {
9826: if((xms_handles[i].seg = msdos_mem_alloc(EMB_TOP >> 4, REG16(DX) * 64, 0)) != -1) {
9827: xms_handles[i].size_kb = REG16(DX);
9828: xms_handles[i].lock = 0;
9829: xms_handles[i].allocated = true;
9830:
9831: REG16(AX) = 0x0001;
9832: REG16(DX) = i;
9833: REG8(BL) = 0x00;
9834: } else {
9835: REG16(AX) = REG16(DX) = 0x0000;
9836: REG8(BL) = 0xa0;
9837: }
9838: return;
9839: }
9840: }
9841: REG16(AX) = REG16(DX) = 0x0000;
9842: REG8(BL) = 0xa1;
9843: }
9844:
9845: inline void msdos_call_xms_0ah()
9846: {
9847: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
9848: REG16(AX) = 0x0000;
9849: REG8(BL) = 0xa2;
9850: } else if(xms_handles[REG16(DX)].lock > 0) {
9851: REG16(AX) = 0x0000;
9852: REG8(BL) = 0xab;
9853: } else {
9854: msdos_mem_free(xms_handles[REG16(DX)].seg);
9855: xms_handles[REG16(DX)].allocated = false;
9856:
9857: REG16(AX) = 0x0001;
9858: REG8(BL) = 0x00;
9859: }
9860: }
9861:
9862: inline void msdos_call_xms_0bh()
9863: {
9864: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00);
9865: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04);
9866: UINT32 src_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06);
9867: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0a);
9868: UINT32 dest_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c);
9869:
9870: UINT8 *src_buffer, *dest_buffer;
9871: UINT32 src_addr_max, dest_addr_max;
9872:
9873: if(src_handle == 0) {
9874: src_buffer = mem;
9875: src_addr = (((src_addr >> 16) & 0xffff) << 4) + (src_addr & 0xffff);
9876: src_addr_max = MAX_MEM;
9877: } else {
9878: if(!(src_handle >= 1 && src_handle <= MAX_XMS_HANDLES && xms_handles[src_handle].allocated)) {
9879: REG16(AX) = 0x0000;
9880: REG8(BL) = 0xa3;
9881: return;
9882: }
9883: src_buffer = mem + (xms_handles[src_handle].seg << 4);
9884: src_addr_max = xms_handles[src_handle].size_kb * 1024;
9885: }
9886: if(dest_handle == 0) {
9887: dest_buffer = mem;
9888: dest_addr = (((dest_addr >> 16) & 0xffff) << 4) + (dest_addr & 0xffff);
9889: dest_addr_max = MAX_MEM;
9890: } else {
9891: if(!(dest_handle >= 1 && dest_handle <= MAX_XMS_HANDLES && xms_handles[dest_handle].allocated)) {
9892: REG16(AX) = 0x0000;
9893: REG8(BL) = 0xa5;
9894: return;
9895: }
9896: dest_buffer = mem + (xms_handles[dest_handle].seg << 4);
9897: dest_addr_max = xms_handles[dest_handle].size_kb * 1024;
9898: }
9899: for(int i = 0; i < copy_length; i++) {
9900: if(src_addr < src_addr_max && dest_addr < dest_addr_max) {
9901: dest_buffer[dest_addr++] = src_buffer[src_addr++];
9902: } else {
9903: break;
9904: }
9905: }
9906: REG16(AX) = 0x0001;
9907: REG8(BL) = 0x00;
9908: }
9909:
9910: inline void msdos_call_xms_0ch()
9911: {
9912: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
9913: REG16(AX) = 0x0000;
9914: REG8(BL) = 0xa2;
9915: } else {
9916: xms_handles[REG16(DX)].lock++;
9917: REG16(AX) = 0x0001;
9918: REG8(BL) = 0x00;
9919: UINT32 addr = xms_handles[REG16(DX)].seg << 4;
9920: REG16(DX) = (addr >> 16) & 0xffff;
9921: REG16(BX) = (addr ) & 0xffff;
9922: }
9923: }
9924:
9925: inline void msdos_call_xms_0dh()
9926: {
9927: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
9928: REG16(AX) = 0x0000;
9929: REG8(BL) = 0xa2;
9930: } else if(!(xms_handles[REG16(DX)].lock > 0)) {
9931: REG16(AX) = 0x0000;
9932: REG8(BL) = 0xaa;
9933: } else {
9934: xms_handles[REG16(DX)].lock--;
9935: REG16(AX) = 0x0001;
9936: REG8(BL) = 0x00;
9937: }
9938: }
9939:
9940: inline void msdos_call_xms_0eh()
9941: {
9942: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
9943: REG16(AX) = 0x0000;
9944: REG8(BL) = 0xa2;
9945: } else {
9946: REG16(AX) = 0x0001;
9947: REG8(BH) = xms_handles[REG16(DX)].lock;
9948: REG8(BL) = 0x00;
9949: for(int i = 1; i <= MAX_XMS_HANDLES; i++) {
9950: if(!xms_handles[i].allocated) {
9951: REG8(BL)++;
9952: }
9953: }
9954: REG16(DX) = xms_handles[REG16(DX)].size_kb;
9955: }
9956: }
9957:
9958: inline void msdos_call_xms_0fh()
9959: {
9960: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
9961: REG16(AX) = 0x0000;
9962: REG8(BL) = 0xa2;
9963: } else if(xms_handles[REG16(DX)].lock > 0) {
9964: REG16(AX) = 0x0000;
9965: REG8(BL) = 0xab;
9966: } else if(msdos_mem_realloc(xms_handles[REG16(DX)].seg, REG16(BX) * 64, NULL)) {
9967: REG16(AX) = 0x0000;
9968: REG8(BL) = 0xa0;
9969: } else {
9970: REG16(AX) = 0x0001;
9971: REG8(BL) = 0x00;
9972: }
9973: }
9974:
9975: inline void msdos_call_xms_10h()
9976: {
9977: int seg;
9978:
9979: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(DX), 0)) != -1) {
9980: REG16(AX) = 0x0001;
9981: REG16(BX) = seg;
9982: } else {
9983: REG16(AX) = 0x0000;
9984: REG8(BL) = 0xb0;
9985: REG16(DX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
9986: }
9987: }
9988:
9989: inline void msdos_call_xms_11h()
9990: {
9991: int mcb_seg = REG16(DX) - 1;
9992: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
9993:
9994: if(mcb->mz == 'M' || mcb->mz == 'Z') {
9995: msdos_mem_free(REG16(DX));
9996: REG16(AX) = 0x0001;
9997: REG8(BL) = 0x00;
9998: } else {
9999: REG16(AX) = 0x0000;
10000: REG8(BL) = 0xb2;
10001: }
10002: }
10003:
10004: inline void msdos_call_xms_12h()
10005: {
10006: int mcb_seg = REG16(DX) - 1;
10007: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
10008: int max_paragraphs;
10009:
10010: if(mcb->mz == 'M' || mcb->mz == 'Z') {
10011: if(!msdos_mem_realloc(REG16(DX), REG16(BX), &max_paragraphs)) {
10012: REG16(AX) = 0x0001;
10013: REG8(BL) = 0x00;
10014: } else {
10015: REG16(AX) = 0x0000;
10016: REG8(BL) = 0xb0;
10017: REG16(DX) = max_paragraphs;
10018: }
10019: } else {
10020: REG16(AX) = 0x0000;
10021: REG8(BL) = 0xb2;
10022: }
10023: }
10024:
10025: #endif
10026:
1.1.1.26 root 10027: UINT16 msdos_get_equipment()
10028: {
10029: static UINT16 equip = 0;
10030:
10031: if(equip == 0) {
10032: #ifdef SUPPORT_FPU
10033: equip |= (1 << 1); // 80x87 coprocessor installed
10034: #endif
10035: equip |= (1 << 2); // pointing device installed (PS/2)
10036: equip |= (2 << 4); // initial video mode (80x25 color)
10037: // equip |= (1 << 8); // 0 if DMA installed
10038: equip |= (2 << 9); // number of serial ports
10039: equip |= (3 << 14); // number of printer ports (NOTE: this number is 3 on Windows 98 SE though only LPT1 exists)
10040: }
10041: return(equip);
10042: }
10043:
1.1 root 10044: void msdos_syscall(unsigned num)
10045: {
1.1.1.22 root 10046: #ifdef ENABLE_DEBUG_SYSCALL
10047: if(num == 0x68) {
10048: // dummy interrupt for EMS (int 67h)
10049: 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));
10050: } else if(num == 0x69) {
10051: // dummy interrupt for XMS (call far)
10052: 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));
10053: } else if(num == 0x6a) {
10054: // dummy interrupt for case map routine pointed in the country info
10055: } else {
10056: 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));
10057: }
10058: #endif
1.1.1.26 root 10059: ctrl_c_pressed = ctrl_c_detected = false;
1.1.1.22 root 10060:
1.1 root 10061: switch(num) {
10062: case 0x00:
10063: error("division by zero\n");
10064: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
10065: break;
10066: case 0x04:
10067: error("overflow\n");
10068: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
10069: break;
10070: case 0x06:
10071: // NOTE: ish.com has illegal instruction...
1.1.1.14 root 10072: if(!ignore_illegal_insn) {
10073: error("illegal instruction\n");
10074: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
10075: } else {
10076: #if defined(HAS_I386)
10077: m_eip++;
10078: #else
10079: m_pc++;
10080: #endif
10081: }
1.1 root 10082: break;
1.1.1.8 root 10083: case 0x08:
1.1.1.14 root 10084: // pcbios_irq0(); // this causes too slow emulation...
1.1.1.8 root 10085: case 0x09:
10086: case 0x0a:
10087: case 0x0b:
10088: case 0x0c:
10089: case 0x0d:
10090: case 0x0e:
10091: case 0x0f:
10092: // EOI
10093: pic[0].isr &= ~(1 << (num - 0x08));
10094: pic_update();
10095: break;
1.1 root 10096: case 0x10:
10097: // PC BIOS - Video
1.1.1.14 root 10098: if(!restore_console_on_exit) {
1.1.1.15 root 10099: change_console_size(scr_width, scr_height);
1.1 root 10100: }
1.1.1.3 root 10101: m_CF = 0;
1.1 root 10102: switch(REG8(AH)) {
1.1.1.16 root 10103: case 0x00: pcbios_int_10h_00h(); break;
1.1 root 10104: case 0x01: pcbios_int_10h_01h(); break;
10105: case 0x02: pcbios_int_10h_02h(); break;
10106: case 0x03: pcbios_int_10h_03h(); break;
10107: case 0x05: pcbios_int_10h_05h(); break;
10108: case 0x06: pcbios_int_10h_06h(); break;
10109: case 0x07: pcbios_int_10h_07h(); break;
10110: case 0x08: pcbios_int_10h_08h(); break;
10111: case 0x09: pcbios_int_10h_09h(); break;
10112: case 0x0a: pcbios_int_10h_0ah(); break;
10113: case 0x0b: break;
10114: case 0x0c: break;
10115: case 0x0d: break;
10116: case 0x0e: pcbios_int_10h_0eh(); break;
10117: case 0x0f: pcbios_int_10h_0fh(); break;
10118: case 0x10: break;
1.1.1.14 root 10119: case 0x11: pcbios_int_10h_11h(); break;
10120: case 0x12: pcbios_int_10h_12h(); break;
1.1 root 10121: case 0x13: pcbios_int_10h_13h(); break;
10122: case 0x18: REG8(AL) = 0x86; break;
1.1.1.14 root 10123: case 0x1a: pcbios_int_10h_1ah(); break;
1.1.1.24 root 10124: case 0x1b: REG8(AL) = 0x00; break; // functionality/state information is not supported
10125: case 0x1c: REG8(AL) = 0x00; break; // save/restore video state is not supported
1.1 root 10126: case 0x1d: pcbios_int_10h_1dh(); break;
1.1.1.24 root 10127: case 0x1e: REG8(AL) = 0x00; break; // flat-panel functions are not supported
10128: case 0x1f: REG8(AL) = 0x00; break; // xga functions are not supported
1.1.1.22 root 10129: case 0x4f: pcbios_int_10h_4fh(); break;
10130: case 0x80: m_CF = 1; break; // unknown
10131: case 0x81: m_CF = 1; break; // unknown
1.1 root 10132: case 0x82: pcbios_int_10h_82h(); break;
1.1.1.22 root 10133: case 0x83: pcbios_int_10h_83h(); break;
10134: case 0x8b: break;
10135: case 0x8c: m_CF = 1; break; // unknown
10136: case 0x8d: m_CF = 1; break; // unknown
10137: case 0x8e: m_CF = 1; break; // unknown
10138: case 0x90: pcbios_int_10h_90h(); break;
10139: case 0x91: pcbios_int_10h_91h(); break;
10140: case 0x92: break;
10141: case 0x93: break;
10142: case 0xef: pcbios_int_10h_efh(); break;
1.1.1.24 root 10143: case 0xfa: break; // ega register interface library is not installed
1.1 root 10144: case 0xfe: pcbios_int_10h_feh(); break;
10145: case 0xff: pcbios_int_10h_ffh(); break;
10146: default:
1.1.1.22 root 10147: 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));
10148: m_CF = 1;
1.1 root 10149: break;
10150: }
10151: break;
10152: case 0x11:
10153: // PC BIOS - Get Equipment List
1.1.1.26 root 10154: REG16(AX) = msdos_get_equipment();
1.1 root 10155: break;
10156: case 0x12:
10157: // PC BIOS - Get Memory Size
10158: REG16(AX) = MEMORY_END / 1024;
10159: break;
10160: case 0x13:
10161: // PC BIOS - Disk
1.1.1.22 root 10162: // 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 10163: REG8(AH) = 0xff;
1.1.1.3 root 10164: m_CF = 1;
1.1 root 10165: break;
10166: case 0x14:
10167: // PC BIOS - Serial I/O
1.1.1.25 root 10168: switch(REG8(AH)) {
10169: case 0x00: pcbios_int_14h_00h(); break;
10170: case 0x01: pcbios_int_14h_01h(); break;
10171: case 0x02: pcbios_int_14h_02h(); break;
10172: case 0x03: pcbios_int_14h_03h(); break;
10173: case 0x04: pcbios_int_14h_04h(); break;
10174: case 0x05: pcbios_int_14h_05h(); break;
10175: default:
10176: unimplemented_14h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
10177: break;
10178: }
1.1 root 10179: break;
10180: case 0x15:
10181: // PC BIOS
1.1.1.3 root 10182: m_CF = 0;
1.1 root 10183: switch(REG8(AH)) {
1.1.1.14 root 10184: case 0x10: pcbios_int_15h_10h(); break;
1.1 root 10185: case 0x23: pcbios_int_15h_23h(); break;
10186: case 0x24: pcbios_int_15h_24h(); break;
1.1.1.24 root 10187: case 0x41: break;
1.1 root 10188: case 0x49: pcbios_int_15h_49h(); break;
1.1.1.22 root 10189: case 0x50: pcbios_int_15h_50h(); break;
1.1 root 10190: case 0x86: pcbios_int_15h_86h(); break;
10191: case 0x87: pcbios_int_15h_87h(); break;
10192: case 0x88: pcbios_int_15h_88h(); break;
10193: case 0x89: pcbios_int_15h_89h(); break;
1.1.1.21 root 10194: case 0x8a: pcbios_int_15h_8ah(); break;
1.1.1.22 root 10195: case 0xc0: // PS/2 ???
10196: case 0xc1:
10197: case 0xc2:
10198: REG8(AH) = 0x86;
10199: m_CF = 1;
10200: break;
1.1.1.3 root 10201: #if defined(HAS_I386)
1.1 root 10202: case 0xc9: pcbios_int_15h_c9h(); break;
1.1.1.3 root 10203: #endif
1.1 root 10204: case 0xca: pcbios_int_15h_cah(); break;
1.1.1.22 root 10205: case 0xe8: pcbios_int_15h_e8h(); break;
1.1 root 10206: default:
1.1.1.22 root 10207: 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));
10208: REG8(AH) = 0x86;
1.1.1.3 root 10209: m_CF = 1;
1.1 root 10210: break;
10211: }
10212: break;
10213: case 0x16:
10214: // PC BIOS - Keyboard
1.1.1.3 root 10215: m_CF = 0;
1.1 root 10216: switch(REG8(AH)) {
10217: case 0x00: pcbios_int_16h_00h(); break;
10218: case 0x01: pcbios_int_16h_01h(); break;
10219: case 0x02: pcbios_int_16h_02h(); break;
10220: case 0x03: pcbios_int_16h_03h(); break;
10221: case 0x05: pcbios_int_16h_05h(); break;
10222: case 0x10: pcbios_int_16h_00h(); break;
10223: case 0x11: pcbios_int_16h_01h(); break;
10224: case 0x12: pcbios_int_16h_12h(); break;
10225: case 0x13: pcbios_int_16h_13h(); break;
10226: case 0x14: pcbios_int_16h_14h(); break;
1.1.1.24 root 10227: case 0x55: pcbios_int_16h_55h(); break;
1.1.1.22 root 10228: case 0xda: break; // unknown
10229: case 0xff: break; // unknown
1.1 root 10230: default:
1.1.1.22 root 10231: 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 10232: break;
10233: }
10234: break;
10235: case 0x17:
10236: // PC BIOS - Printer
1.1.1.22 root 10237: // 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 10238: break;
10239: case 0x1a:
10240: // PC BIOS - Timer
1.1.1.3 root 10241: m_CF = 0;
1.1 root 10242: switch(REG8(AH)) {
10243: case 0x00: pcbios_int_1ah_00h(); break;
10244: case 0x01: break;
10245: case 0x02: pcbios_int_1ah_02h(); break;
10246: case 0x03: break;
10247: case 0x04: pcbios_int_1ah_04h(); break;
10248: case 0x05: break;
10249: case 0x0a: pcbios_int_1ah_0ah(); break;
10250: case 0x0b: break;
1.1.1.14 root 10251: case 0x35: break; // Word Perfect Third Party Interface?
10252: case 0x36: break; // Word Perfect Third Party Interface
10253: case 0x70: break; // SNAP? (Simple Network Application Protocol)
1.1 root 10254: default:
1.1.1.22 root 10255: 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 10256: break;
10257: }
10258: break;
10259: case 0x20:
1.1.1.3 root 10260: msdos_process_terminate(SREG(CS), retval, 1);
1.1 root 10261: break;
10262: case 0x21:
10263: // MS-DOS System Call
1.1.1.3 root 10264: m_CF = 0;
1.1 root 10265: switch(REG8(AH)) {
10266: case 0x00: msdos_int_21h_00h(); break;
10267: case 0x01: msdos_int_21h_01h(); break;
10268: case 0x02: msdos_int_21h_02h(); break;
10269: case 0x03: msdos_int_21h_03h(); break;
10270: case 0x04: msdos_int_21h_04h(); break;
10271: case 0x05: msdos_int_21h_05h(); break;
10272: case 0x06: msdos_int_21h_06h(); break;
10273: case 0x07: msdos_int_21h_07h(); break;
10274: case 0x08: msdos_int_21h_08h(); break;
10275: case 0x09: msdos_int_21h_09h(); break;
10276: case 0x0a: msdos_int_21h_0ah(); break;
10277: case 0x0b: msdos_int_21h_0bh(); break;
10278: case 0x0c: msdos_int_21h_0ch(); break;
10279: case 0x0d: msdos_int_21h_0dh(); break;
10280: case 0x0e: msdos_int_21h_0eh(); break;
1.1.1.14 root 10281: case 0x0f: msdos_int_21h_0fh(); break;
10282: case 0x10: msdos_int_21h_10h(); break;
1.1 root 10283: case 0x11: msdos_int_21h_11h(); break;
10284: case 0x12: msdos_int_21h_12h(); break;
10285: case 0x13: msdos_int_21h_13h(); break;
1.1.1.16 root 10286: case 0x14: msdos_int_21h_14h(); break;
10287: case 0x15: msdos_int_21h_15h(); break;
1.1.1.14 root 10288: case 0x16: msdos_int_21h_16h(); break;
1.1.1.16 root 10289: case 0x17: msdos_int_21h_17h(); break;
1.1 root 10290: case 0x18: msdos_int_21h_18h(); break;
10291: case 0x19: msdos_int_21h_19h(); break;
10292: case 0x1a: msdos_int_21h_1ah(); break;
10293: case 0x1b: msdos_int_21h_1bh(); break;
10294: case 0x1c: msdos_int_21h_1ch(); break;
10295: case 0x1d: msdos_int_21h_1dh(); break;
10296: case 0x1e: msdos_int_21h_1eh(); break;
10297: case 0x1f: msdos_int_21h_1fh(); break;
10298: case 0x20: msdos_int_21h_20h(); break;
1.1.1.14 root 10299: case 0x21: msdos_int_21h_21h(); break;
10300: case 0x22: msdos_int_21h_22h(); break;
1.1.1.16 root 10301: case 0x23: msdos_int_21h_23h(); break;
10302: case 0x24: msdos_int_21h_24h(); break;
1.1 root 10303: case 0x25: msdos_int_21h_25h(); break;
10304: case 0x26: msdos_int_21h_26h(); break;
1.1.1.16 root 10305: case 0x27: msdos_int_21h_27h(); break;
10306: case 0x28: msdos_int_21h_28h(); break;
1.1 root 10307: case 0x29: msdos_int_21h_29h(); break;
10308: case 0x2a: msdos_int_21h_2ah(); break;
10309: case 0x2b: msdos_int_21h_2bh(); break;
10310: case 0x2c: msdos_int_21h_2ch(); break;
10311: case 0x2d: msdos_int_21h_2dh(); break;
10312: case 0x2e: msdos_int_21h_2eh(); break;
10313: case 0x2f: msdos_int_21h_2fh(); break;
10314: case 0x30: msdos_int_21h_30h(); break;
10315: case 0x31: msdos_int_21h_31h(); break;
10316: case 0x32: msdos_int_21h_32h(); break;
10317: case 0x33: msdos_int_21h_33h(); break;
1.1.1.23 root 10318: case 0x34: msdos_int_21h_34h(); break;
1.1 root 10319: case 0x35: msdos_int_21h_35h(); break;
10320: case 0x36: msdos_int_21h_36h(); break;
10321: case 0x37: msdos_int_21h_37h(); break;
1.1.1.14 root 10322: case 0x38: msdos_int_21h_38h(); break;
1.1 root 10323: case 0x39: msdos_int_21h_39h(0); break;
10324: case 0x3a: msdos_int_21h_3ah(0); break;
10325: case 0x3b: msdos_int_21h_3bh(0); break;
10326: case 0x3c: msdos_int_21h_3ch(); break;
10327: case 0x3d: msdos_int_21h_3dh(); break;
10328: case 0x3e: msdos_int_21h_3eh(); break;
10329: case 0x3f: msdos_int_21h_3fh(); break;
10330: case 0x40: msdos_int_21h_40h(); break;
10331: case 0x41: msdos_int_21h_41h(0); break;
10332: case 0x42: msdos_int_21h_42h(); break;
10333: case 0x43: msdos_int_21h_43h(0); break;
10334: case 0x44: msdos_int_21h_44h(); break;
10335: case 0x45: msdos_int_21h_45h(); break;
10336: case 0x46: msdos_int_21h_46h(); break;
10337: case 0x47: msdos_int_21h_47h(0); break;
10338: case 0x48: msdos_int_21h_48h(); break;
10339: case 0x49: msdos_int_21h_49h(); break;
10340: case 0x4a: msdos_int_21h_4ah(); break;
10341: case 0x4b: msdos_int_21h_4bh(); break;
10342: case 0x4c: msdos_int_21h_4ch(); break;
10343: case 0x4d: msdos_int_21h_4dh(); break;
10344: case 0x4e: msdos_int_21h_4eh(); break;
10345: case 0x4f: msdos_int_21h_4fh(); break;
10346: case 0x50: msdos_int_21h_50h(); break;
10347: case 0x51: msdos_int_21h_51h(); break;
10348: case 0x52: msdos_int_21h_52h(); break;
10349: // 0x53: translate bios parameter block to drive param bock
10350: case 0x54: msdos_int_21h_54h(); break;
10351: case 0x55: msdos_int_21h_55h(); break;
10352: case 0x56: msdos_int_21h_56h(0); break;
10353: case 0x57: msdos_int_21h_57h(); break;
10354: case 0x58: msdos_int_21h_58h(); break;
10355: case 0x59: msdos_int_21h_59h(); break;
10356: case 0x5a: msdos_int_21h_5ah(); break;
10357: case 0x5b: msdos_int_21h_5bh(); break;
10358: case 0x5c: msdos_int_21h_5ch(); break;
1.1.1.22 root 10359: case 0x5d: msdos_int_21h_5dh(); break;
1.1 root 10360: // 0x5e: ms-network
10361: // 0x5f: ms-network
10362: case 0x60: msdos_int_21h_60h(0); break;
10363: case 0x61: msdos_int_21h_61h(); break;
10364: case 0x62: msdos_int_21h_62h(); break;
10365: case 0x63: msdos_int_21h_63h(); break;
10366: // 0x64: set device driver lockahead flag
10367: case 0x65: msdos_int_21h_65h(); break;
10368: case 0x66: msdos_int_21h_66h(); break;
10369: case 0x67: msdos_int_21h_67h(); break;
10370: case 0x68: msdos_int_21h_68h(); break;
10371: case 0x69: msdos_int_21h_69h(); break;
10372: case 0x6a: msdos_int_21h_6ah(); break;
10373: case 0x6b: msdos_int_21h_6bh(); break;
10374: case 0x6c: msdos_int_21h_6ch(0); break;
10375: // 0x6d: find first rom program
10376: // 0x6e: find next rom program
10377: // 0x6f: get/set rom scan start address
10378: // 0x70: windows95 get/set internationalization information
10379: case 0x71:
10380: // windows95 long filename functions
10381: switch(REG8(AL)) {
10382: case 0x0d: msdos_int_21h_710dh(); break;
10383: case 0x39: msdos_int_21h_39h(1); break;
10384: case 0x3a: msdos_int_21h_3ah(1); break;
10385: case 0x3b: msdos_int_21h_3bh(1); break;
1.1.1.17 root 10386: case 0x41: msdos_int_21h_7141h(1); break;
1.1 root 10387: case 0x43: msdos_int_21h_43h(1); break;
10388: case 0x47: msdos_int_21h_47h(1); break;
10389: case 0x4e: msdos_int_21h_714eh(); break;
10390: case 0x4f: msdos_int_21h_714fh(); break;
10391: case 0x56: msdos_int_21h_56h(1); break;
10392: case 0x60: msdos_int_21h_60h(1); break;
10393: case 0x6c: msdos_int_21h_6ch(1); break;
10394: case 0xa0: msdos_int_21h_71a0h(); break;
10395: case 0xa1: msdos_int_21h_71a1h(); break;
10396: case 0xa6: msdos_int_21h_71a6h(); break;
10397: case 0xa7: msdos_int_21h_71a7h(); break;
10398: case 0xa8: msdos_int_21h_71a8h(); break;
10399: // 0xa9: server create/open file
1.1.1.22 root 10400: case 0xaa: msdos_int_21h_71aah(); break;
1.1 root 10401: default:
1.1.1.22 root 10402: 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 10403: REG16(AX) = 0x7100;
1.1.1.3 root 10404: m_CF = 1;
1.1 root 10405: break;
10406: }
10407: break;
10408: // 0x72: Windows95 beta - LFN FindClose
10409: case 0x73:
10410: // windows95 fat32 functions
10411: switch(REG8(AL)) {
1.1.1.14 root 10412: case 0x00: msdos_int_21h_7300h(); break;
10413: // 0x01: set drive locking ???
10414: case 0x02: msdos_int_21h_7302h(); break;
1.1 root 10415: case 0x03: msdos_int_21h_7303h(); break;
10416: // 0x04: set dpb to use for formatting
1.1.1.25 root 10417: // 0x05: extended absolute disk read/write
1.1 root 10418: default:
1.1.1.22 root 10419: 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 10420: REG16(AX) = 0x7300;
1.1.1.3 root 10421: m_CF = 1;
1.1 root 10422: break;
10423: }
10424: break;
10425: default:
1.1.1.22 root 10426: 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 10427: REG16(AX) = 0x01;
1.1.1.3 root 10428: m_CF = 1;
1.1 root 10429: break;
10430: }
1.1.1.3 root 10431: if(m_CF) {
1.1.1.23 root 10432: sda_t *sda = (sda_t *)(mem + SDA_TOP);
10433: sda->extended_error_code = REG16(AX);
10434: switch(sda->extended_error_code) {
10435: case 4: // Too many open files
10436: case 8: // Insufficient memory
10437: sda->error_class = 1; // Out of resource
10438: break;
10439: case 5: // Access denied
10440: sda->error_class = 3; // Authorization
10441: break;
10442: case 7: // Memory control block destroyed
10443: sda->error_class = 4; // Internal
10444: break;
10445: case 2: // File not found
10446: case 3: // Path not found
10447: case 15: // Invaid drive specified
10448: case 18: // No more files
10449: sda->error_class = 8; // Not found
10450: break;
10451: case 32: // Sharing violation
10452: case 33: // Lock violation
10453: sda->error_class = 10; // Locked
10454: break;
10455: // case 16: // Removal of current directory attempted
10456: case 19: // Attempted write on protected disk
10457: case 21: // Drive not ready
10458: // case 29: // Write failure
10459: // case 30: // Read failure
10460: // case 82: // Cannot create subdirectory
10461: sda->error_class = 11; // Media
10462: break;
10463: case 80: // File already exists
10464: sda->error_class = 12; // Already exist
10465: break;
10466: default:
10467: sda->error_class = 13; // Unknown
10468: break;
10469: }
10470: sda->suggested_action = 1; // Retry
10471: sda->locus_of_last_error = 1; // Unknown
1.1 root 10472: }
1.1.1.26 root 10473: if(ctrl_c_checking && ctrl_c_detected) {
10474: // raise int 23h
10475: #if defined(HAS_I386)
10476: m_ext = 0; // not an external interrupt
10477: i386_trap(0x23, 1, 0);
10478: m_ext = 1;
10479: #else
10480: PREFIX86(_interrupt)(0x23);
10481: #endif
10482: }
1.1 root 10483: break;
10484: case 0x22:
10485: fatalerror("int 22h (terminate address)\n");
10486: case 0x23:
10487: msdos_process_terminate(current_psp, (retval & 0xff) | 0x100, 1);
10488: break;
10489: case 0x24:
10490: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
10491: break;
10492: case 0x25:
10493: msdos_int_25h();
10494: break;
10495: case 0x26:
10496: msdos_int_26h();
10497: break;
10498: case 0x27:
10499: msdos_int_27h();
10500: break;
10501: case 0x28:
10502: Sleep(10);
10503: break;
10504: case 0x29:
10505: msdos_int_29h();
10506: break;
10507: case 0x2e:
10508: msdos_int_2eh();
10509: break;
10510: case 0x2f:
10511: // multiplex interrupt
10512: switch(REG8(AH)) {
1.1.1.22 root 10513: case 0x00: break;
10514: case 0x01: msdos_int_2fh_01h(); break;
10515: case 0x05: msdos_int_2fh_05h(); break;
10516: case 0x06: msdos_int_2fh_06h(); break;
10517: case 0x08: msdos_int_2fh_08h(); break;
10518: case 0x10: msdos_int_2fh_10h(); break;
10519: case 0x11: msdos_int_2fh_11h(); break;
1.1.1.21 root 10520: case 0x12: msdos_int_2fh_12h(); break;
1.1.1.22 root 10521: case 0x14: msdos_int_2fh_14h(); break;
10522: case 0x15: msdos_int_2fh_15h(); break;
1.1 root 10523: case 0x16: msdos_int_2fh_16h(); break;
1.1.1.22 root 10524: case 0x19: msdos_int_2fh_19h(); break;
1.1 root 10525: case 0x1a: msdos_int_2fh_1ah(); break;
1.1.1.22 root 10526: case 0x1b: msdos_int_2fh_1bh(); break;
1.1 root 10527: case 0x43: msdos_int_2fh_43h(); break;
1.1.1.22 root 10528: case 0x46: msdos_int_2fh_46h(); break;
10529: case 0x48: msdos_int_2fh_48h(); break;
1.1 root 10530: case 0x4a: msdos_int_2fh_4ah(); break;
1.1.1.22 root 10531: case 0x4b: msdos_int_2fh_4bh(); break;
10532: case 0x4c: break; // unknown
10533: case 0x4d: break; // unknown
10534: case 0x4e: break; // unknown
1.1 root 10535: case 0x4f: msdos_int_2fh_4fh(); break;
1.1.1.22 root 10536: case 0x55: msdos_int_2fh_55h(); break;
10537: case 0x58: break; // unknown
10538: case 0x74: break; // unknown
1.1.1.24 root 10539: case 0xad: msdos_int_2fh_adh(); break;
1.1 root 10540: case 0xae: msdos_int_2fh_aeh(); break;
10541: case 0xb7: msdos_int_2fh_b7h(); break;
1.1.1.22 root 10542: case 0xe9: break; // unknown
10543: case 0xfe: break; // norton utilities ???
10544: default:
10545: 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));
10546: break;
1.1 root 10547: }
10548: break;
1.1.1.24 root 10549: case 0x33:
10550: switch(REG8(AH)) {
10551: case 0x00:
10552: // Mouse
10553: switch(REG8(AL)) {
10554: case 0x00: msdos_int_33h_0000h(); break;
10555: case 0x01: msdos_int_33h_0001h(); break;
10556: case 0x02: msdos_int_33h_0002h(); break;
10557: case 0x03: msdos_int_33h_0003h(); break;
10558: case 0x04: break; // position mouse cursor
10559: case 0x05: msdos_int_33h_0005h(); break;
10560: case 0x06: msdos_int_33h_0006h(); break;
10561: case 0x07: msdos_int_33h_0007h(); break;
10562: case 0x08: msdos_int_33h_0008h(); break;
10563: case 0x09: msdos_int_33h_0009h(); break;
10564: case 0x0a: break; // define text cursor
10565: case 0x0b: msdos_int_33h_000bh(); break;
10566: case 0x0c: msdos_int_33h_000ch(); break;
10567: case 0x0d: break; // light pen emulation on
10568: case 0x0e: break; // light pen emulation off
10569: case 0x0f: msdos_int_33h_000fh(); break;
10570: case 0x10: break; // define screen region for updating
10571: case 0x11: msdos_int_33h_0011h(); break;
10572: case 0x12: REG16(AX) = 0xffff; break; // set large graphics cursor block
10573: case 0x13: break; // define double-speed threshold
10574: case 0x14: msdos_int_33h_0014h(); break;
10575: case 0x15: msdos_int_33h_0015h(); break;
10576: case 0x16: msdos_int_33h_0016h(); break;
10577: case 0x17: msdos_int_33h_0017h(); break;
10578: case 0x1a: msdos_int_33h_001ah(); break;
10579: case 0x1b: msdos_int_33h_001bh(); break;
10580: case 0x1d: msdos_int_33h_001dh(); break;
10581: case 0x1e: msdos_int_33h_001eh(); break;
10582: case 0x21: msdos_int_33h_0021h(); break;
10583: case 0x22: msdos_int_33h_0022h(); break;
10584: case 0x23: msdos_int_33h_0023h(); break;
10585: case 0x24: msdos_int_33h_0024h(); break;
10586: case 0x26: msdos_int_33h_0026h(); break;
10587: case 0x2a: msdos_int_33h_002ah(); break;
10588: case 0x2f: break; // mouse hardware reset
10589: case 0x31: msdos_int_33h_0031h(); break;
10590: case 0x32: msdos_int_33h_0032h(); break;
10591: default:
10592: unimplemented_33h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
10593: break;
10594: }
10595: break;
10596: default:
10597: unimplemented_33h("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
10598: break;
10599: }
10600: break;
1.1.1.19 root 10601: case 0x68:
10602: // dummy interrupt for EMS (int 67h)
10603: switch(REG8(AH)) {
10604: case 0x40: msdos_int_67h_40h(); break;
10605: case 0x41: msdos_int_67h_41h(); break;
10606: case 0x42: msdos_int_67h_42h(); break;
10607: case 0x43: msdos_int_67h_43h(); break;
10608: case 0x44: msdos_int_67h_44h(); break;
10609: case 0x45: msdos_int_67h_45h(); break;
10610: case 0x46: msdos_int_67h_46h(); break;
10611: case 0x47: msdos_int_67h_47h(); break;
10612: case 0x48: msdos_int_67h_48h(); break;
1.1.1.20 root 10613: // 0x49: LIM EMS - Reserved - Get I/O Port Address (Undocumented in EMS 3.2)
10614: // 0x4a: LIM EMS - Reserved - Get Translation Array (Undocumented in EMS 3.2)
1.1.1.19 root 10615: case 0x4b: msdos_int_67h_4bh(); break;
10616: case 0x4c: msdos_int_67h_4ch(); break;
10617: case 0x4d: msdos_int_67h_4dh(); break;
1.1.1.20 root 10618: case 0x4e: msdos_int_67h_4eh(); break;
1.1.1.21 root 10619: case 0x4f: msdos_int_67h_4fh(); break;
1.1.1.20 root 10620: case 0x50: msdos_int_67h_50h(); break;
1.1.1.19 root 10621: case 0x51: msdos_int_67h_51h(); break;
1.1.1.20 root 10622: case 0x52: msdos_int_67h_52h(); break;
1.1.1.19 root 10623: case 0x53: msdos_int_67h_53h(); break;
10624: case 0x54: msdos_int_67h_54h(); break;
1.1.1.20 root 10625: // 0x55: LIM EMS 4.0 - Alter Page Map And JUMP
10626: // 0x56: LIM EMS 4.0 - Alter Page Map And CALL
10627: case 0x57: msdos_int_67h_57h(); break;
10628: case 0x58: msdos_int_67h_58h(); break;
10629: // 0x59: LIM EMS 4.0 - Get Expanded Memory Hardware Information (for DOS Kernel)
10630: case 0x5a: msdos_int_67h_5ah(); break;
10631: // 0x5b: LIM EMS 4.0 - Alternate Map Register Set (for DOS Kernel)
10632: // 0x5c: LIM EMS 4.0 - Prepate Expanded Memory Hardware For Warm Boot
10633: // 0x5d: LIM EMS 4.0 - Enable/Disable OS Function Set Functions (for DOS Kernel)
1.1.1.19 root 10634: default:
1.1.1.22 root 10635: 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 10636: REG8(AH) = 0x84;
10637: break;
10638: }
10639: break;
10640: #ifdef SUPPORT_XMS
10641: case 0x69:
10642: // dummy interrupt for XMS (call far)
10643: switch(REG8(AH)) {
10644: case 0x00: msdos_call_xms_00h(); break;
10645: case 0x01: msdos_call_xms_01h(); break;
10646: case 0x02: msdos_call_xms_02h(); break;
10647: case 0x03: msdos_call_xms_03h(); break;
10648: case 0x04: msdos_call_xms_04h(); break;
10649: case 0x05: msdos_call_xms_05h(); break;
10650: case 0x06: msdos_call_xms_06h(); break;
10651: case 0x07: msdos_call_xms_07h(); break;
10652: case 0x08: msdos_call_xms_08h(); break;
10653: case 0x09: msdos_call_xms_09h(); break;
10654: case 0x0a: msdos_call_xms_0ah(); break;
10655: case 0x0b: msdos_call_xms_0bh(); break;
10656: case 0x0c: msdos_call_xms_0ch(); break;
10657: case 0x0d: msdos_call_xms_0dh(); break;
10658: case 0x0e: msdos_call_xms_0eh(); break;
10659: case 0x0f: msdos_call_xms_0fh(); break;
10660: case 0x10: msdos_call_xms_10h(); break;
10661: case 0x11: msdos_call_xms_11h(); break;
10662: case 0x12: msdos_call_xms_12h(); break;
10663: // 0x88: XMS 3.0 - Query free extended memory
10664: // 0x89: XMS 3.0 - Allocate any extended memory
10665: // 0x8e: XMS 3.0 - Get extended EMB handle information
10666: // 0x8f: XMS 3.0 - Reallocate any extended memory block
10667: default:
1.1.1.22 root 10668: 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 10669: REG16(AX) = 0x0000;
10670: REG8(BL) = 0x80;
10671: break;
10672: }
10673: break;
10674: #endif
10675: case 0x6a:
1.1.1.24 root 10676: // irq12 (mouse)
10677: mouse_push_ax = REG16(AX);
10678: mouse_push_bx = REG16(BX);
10679: mouse_push_cx = REG16(CX);
10680: mouse_push_dx = REG16(DX);
10681: mouse_push_si = REG16(SI);
10682: mouse_push_di = REG16(DI);
10683:
10684: if(mouse.active && mouse.call_addr.dw != 0) {
10685: REG16(AX) = mouse.status_irq;
10686: REG16(BX) = mouse.get_buttons();
10687: REG16(CX) = max(mouse.min_position.x, min(mouse.max_position.x, mouse.position.x));
10688: REG16(DX) = max(mouse.min_position.y, min(mouse.max_position.y, mouse.position.y));
10689: REG16(SI) = REG16(CX) * mouse.mickey.x / 8;
10690: REG16(DI) = REG16(DX) * mouse.mickey.y / 8;
10691:
10692: mem[0xfffd0 + 0x02] = 0x9a; // call far
10693: mem[0xfffd0 + 0x03] = mouse.call_addr.w.l & 0xff;
10694: mem[0xfffd0 + 0x04] = mouse.call_addr.w.l >> 8;
10695: mem[0xfffd0 + 0x05] = mouse.call_addr.w.h & 0xff;
10696: mem[0xfffd0 + 0x06] = mouse.call_addr.w.h >> 8;
10697: } else {
10698: mem[0xfffd0 + 0x02] = 0x90; // nop
10699: mem[0xfffd0 + 0x03] = 0x90; // nop
10700: mem[0xfffd0 + 0x04] = 0x90; // nop
10701: mem[0xfffd0 + 0x05] = 0x90; // nop
10702: mem[0xfffd0 + 0x06] = 0x90; // nop
10703: }
10704: break;
10705: case 0x6b:
10706: // end of irq12 (mouse)
10707: REG16(AX) = mouse_push_ax;
10708: REG16(BX) = mouse_push_bx;
10709: REG16(CX) = mouse_push_cx;
10710: REG16(DX) = mouse_push_dx;
10711: REG16(SI) = mouse_push_si;
10712: REG16(DI) = mouse_push_di;
10713:
10714: // EOI
10715: if((pic[1].isr &= ~(1 << 4)) == 0) {
10716: pic[0].isr &= ~(1 << 2); // master
10717: }
10718: pic_update();
10719: break;
10720: case 0x6c:
1.1.1.19 root 10721: // dummy interrupt for case map routine pointed in the country info
10722: if(REG8(AL) >= 0x80) {
10723: char tmp[2] = {0};
10724: tmp[0] = REG8(AL);
10725: my_strupr(tmp);
10726: REG8(AL) = tmp[0];
10727: }
10728: break;
1.1.1.27! root 10729: case 0x6d:
! 10730: // dummy interrupt for font read routine pointed by int 15h, ax=5000h
! 10731: REG8(AL) = 0x86; // not supported
! 10732: m_CF = 1;
! 10733: break;
1.1.1.8 root 10734: case 0x70:
10735: case 0x71:
10736: case 0x72:
10737: case 0x73:
10738: case 0x74:
10739: case 0x75:
10740: case 0x76:
10741: case 0x77:
10742: // EOI
10743: if((pic[1].isr &= ~(1 << (num - 0x70))) == 0) {
10744: pic[0].isr &= ~(1 << 2); // master
10745: }
10746: pic_update();
10747: break;
1.1 root 10748: default:
1.1.1.22 root 10749: // 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 10750: break;
10751: }
10752:
10753: // update cursor position
10754: if(cursor_moved) {
10755: CONSOLE_SCREEN_BUFFER_INFO csbi;
1.1.1.23 root 10756: GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
1.1.1.15 root 10757: if(!restore_console_on_exit) {
10758: scr_top = csbi.srWindow.Top;
10759: }
1.1 root 10760: mem[0x450 + mem[0x462] * 2] = csbi.dwCursorPosition.X;
1.1.1.14 root 10761: mem[0x451 + mem[0x462] * 2] = csbi.dwCursorPosition.Y - scr_top;
1.1 root 10762: cursor_moved = false;
10763: }
10764: }
10765:
10766: // init
10767:
10768: int msdos_init(int argc, char *argv[], char *envp[], int standard_env)
10769: {
10770: // init file handler
10771: memset(file_handler, 0, sizeof(file_handler));
10772: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
10773: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
10774: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
1.1.1.21 root 10775: #ifdef MAP_AUX_DEVICE_TO_FILE
1.1 root 10776: if(_open("stdaux.txt", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
1.1.1.21 root 10777: #else
10778: if(_open("NUL", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
10779: #endif
10780: msdos_file_handler_open(3, "STDAUX", 0, 2, 0x80c0, 0);
1.1 root 10781: }
1.1.1.21 root 10782: #ifdef MAP_PRN_DEVICE_TO_FILE
1.1 root 10783: if(_open("stdprn.txt", _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 4) {
1.1.1.21 root 10784: #else
10785: if(_open("NUL", _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 4) {
1.1 root 10786: #endif
1.1.1.21 root 10787: msdos_file_handler_open(4, "STDPRN", 0, 1, 0xa8c0, 0);
10788: }
1.1 root 10789: _dup2(0, DUP_STDIN);
10790: _dup2(1, DUP_STDOUT);
10791: _dup2(2, DUP_STDERR);
1.1.1.21 root 10792: _dup2(3, DUP_STDAUX);
10793: _dup2(4, DUP_STDPRN);
1.1 root 10794:
1.1.1.24 root 10795: // init mouse
10796: memset(&mouse, 0, sizeof(mouse));
10797: mouse.max_position.x = 8 * scr_width - 1;
10798: mouse.max_position.y = 8 * scr_height - 1;
10799: mouse.mickey.x = 8;
10800: mouse.mickey.y = 16;
10801:
1.1.1.26 root 10802: #ifdef SUPPORT_XMS
10803: // init xms
10804: msdos_xms_init();
10805: #endif
10806:
1.1 root 10807: // init process
10808: memset(process, 0, sizeof(process));
10809:
1.1.1.13 root 10810: // init dtainfo
10811: msdos_dta_info_init();
10812:
1.1 root 10813: // init memory
10814: memset(mem, 0, sizeof(mem));
10815:
10816: // bios data area
1.1.1.23 root 10817: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 10818: CONSOLE_SCREEN_BUFFER_INFO csbi;
10819: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 10820: CONSOLE_FONT_INFO cfi;
10821: GetCurrentConsoleFont(hStdout, FALSE, &cfi);
10822:
10823: int regen = min(scr_width * scr_height * 2, 0x8000);
10824: text_vram_top_address = TEXT_VRAM_TOP;
10825: text_vram_end_address = text_vram_top_address + regen;
10826: shadow_buffer_top_address = SHADOW_BUF_TOP;
10827: shadow_buffer_end_address = shadow_buffer_top_address + regen;
10828:
10829: if(regen > 0x4000) {
10830: regen = 0x8000;
10831: vram_pages = 1;
10832: } else if(regen > 0x2000) {
10833: regen = 0x4000;
10834: vram_pages = 2;
10835: } else if(regen > 0x1000) {
10836: regen = 0x2000;
10837: vram_pages = 4;
10838: } else {
10839: regen = 0x1000;
10840: vram_pages = 8;
10841: }
1.1 root 10842:
1.1.1.25 root 10843: *(UINT16 *)(mem + 0x400) = 0x3f8; // com1 port address
10844: *(UINT16 *)(mem + 0x402) = 0x2f8; // com2 port address
10845: // *(UINT16 *)(mem + 0x404) = 0x3e8; // com3 port address
10846: // *(UINT16 *)(mem + 0x406) = 0x2e8; // com4 port address
10847: *(UINT16 *)(mem + 0x408) = 0x378; // lpt1 port address
1.1.1.26 root 10848: // *(UINT16 *)(mem + 0x40a) = 0x278; // lpt2 port address
1.1.1.25 root 10849: // *(UINT16 *)(mem + 0x40c) = 0x3bc; // lpt3 port address
10850: *(UINT16 *)(mem + 0x40e) = EXT_BIOS_TOP >> 4;
1.1.1.26 root 10851: *(UINT16 *)(mem + 0x410) = msdos_get_equipment();
1.1 root 10852: *(UINT16 *)(mem + 0x413) = MEMORY_END / 1024;
10853: *(UINT8 *)(mem + 0x449) = 0x03;//0x73;
1.1.1.14 root 10854: *(UINT16 *)(mem + 0x44a) = csbi.dwSize.X;
10855: *(UINT16 *)(mem + 0x44c) = regen;
1.1 root 10856: *(UINT16 *)(mem + 0x44e) = 0;
10857: *(UINT8 *)(mem + 0x450) = csbi.dwCursorPosition.X;
1.1.1.14 root 10858: *(UINT8 *)(mem + 0x451) = csbi.dwCursorPosition.Y - scr_top;
1.1 root 10859: *(UINT8 *)(mem + 0x460) = 7;
10860: *(UINT8 *)(mem + 0x461) = 7;
10861: *(UINT8 *)(mem + 0x462) = 0;
10862: *(UINT16 *)(mem + 0x463) = 0x3d4;
1.1.1.19 root 10863: *(UINT8 *)(mem + 0x465) = 0x09;
10864: *(UINT32 *)(mem + 0x46c) = get_ticks_since_midnight(timeGetTime());
1.1.1.14 root 10865: *(UINT8 *)(mem + 0x484) = csbi.srWindow.Bottom - csbi.srWindow.Top;
10866: *(UINT8 *)(mem + 0x485) = cfi.dwFontSize.Y;
10867: *(UINT8 *)(mem + 0x487) = 0x60;
10868: *(UINT8 *)(mem + 0x496) = 0x10; // enhanced keyboard installed
1.1.1.25 root 10869: *(UINT16 *)(mem + EXT_BIOS_TOP) = 1;
1.1.1.14 root 10870:
10871: // initial screen
10872: SMALL_RECT rect;
10873: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
10874: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
10875: for(int y = 0, ofs1 = TEXT_VRAM_TOP, ofs2 = SHADOW_BUF_TOP; y < scr_height; y++) {
10876: for(int x = 0; x < scr_width; x++) {
10877: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Char.AsciiChar;
10878: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Attributes;
10879: }
10880: }
1.1 root 10881:
1.1.1.19 root 10882: // init mcb
1.1 root 10883: int seg = MEMORY_TOP >> 4;
1.1.1.19 root 10884:
10885: // iret table
10886: // note: int 2eh vector should address the routine in command.com,
10887: // and some softwares invite (int 2eh vector segment) - 1 must address the mcb of command.com.
10888: // so move iret table into allocated memory block
10889: // http://www5c.biglobe.ne.jp/~ecb/assembler2/2_6.html
10890: msdos_mcb_create(seg++, 'M', -1, IRET_SIZE >> 4);
10891: IRET_TOP = seg << 4;
10892: seg += IRET_SIZE >> 4;
1.1.1.25 root 10893: memset(mem + IRET_TOP, 0xcf, IRET_SIZE); // iret
1.1.1.19 root 10894:
10895: // dummy xms/ems device
10896: msdos_mcb_create(seg++, 'M', -1, XMS_SIZE >> 4);
10897: XMS_TOP = seg << 4;
10898: seg += XMS_SIZE >> 4;
10899:
10900: // environment
1.1 root 10901: msdos_mcb_create(seg++, 'M', -1, ENV_SIZE >> 4);
10902: int env_seg = seg;
10903: int ofs = 0;
1.1.1.24 root 10904: char env_path[8192] = "", *path, temp_path[MAX_PATH] = {0};
1.1 root 10905:
10906: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1.1.14 root 10907: if(_strnicmp(*p, "MSDOS_PATH=", 11) == 0) {
10908: sprintf(env_path, "%s;", *p + 11);
10909: break;
10910: }
10911: }
10912: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1.1.9 root 10913: if(_strnicmp(*p, "PATH=", 5) == 0) {
1.1.1.14 root 10914: strcat(env_path, *p + 5);
1.1.1.9 root 10915: break;
10916: }
10917: }
1.1.1.18 root 10918: if((path = getenv("MSDOS_COMSPEC")) != NULL ||
10919: (path = msdos_search_command_com(argv[0], env_path)) != NULL) {
1.1.1.15 root 10920: strcpy(comspec_path, path);
10921: }
1.1.1.24 root 10922: if((path = getenv("MSDOS_TEMP")) != NULL) {
10923: if(GetShortPathName(path, temp_path, MAX_PATH) == 0) {
10924: strcpy(temp_path, path);
10925: }
10926: }
1.1.1.15 root 10927:
1.1.1.9 root 10928: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1 root 10929: // lower to upper
10930: char tmp[ENV_SIZE], name[ENV_SIZE], value[ENV_SIZE];
10931: int value_pos = 0;
10932: strcpy(tmp, *p);
10933: for(int i = 0;; i++) {
10934: if(tmp[i] == '=') {
10935: tmp[i] = '\0';
10936: sprintf(name, ";%s;", tmp);
1.1.1.25 root 10937: my_strupr(name);
1.1 root 10938: strcpy(value, tmp + (value_pos = i + 1));
10939: tmp[i] = '=';
10940: break;
10941: } else if(tmp[i] >= 'a' && tmp[i] <= 'z') {
10942: tmp[i] = tmp[i] - 'a' + 'A';
10943: }
10944: }
1.1.1.18 root 10945: if(strncmp(tmp, "MSDOS_COMSPEC=", 14) == 0) {
10946: // ignore MSDOS_COMSPEC
1.1.1.24 root 10947: } else if(strncmp(tmp, "MSDOS_TEMP=", 11) == 0) {
10948: // ignore MSDOS_TEMP
1.1.1.18 root 10949: } else if(standard_env && strstr(";COMSPEC;INCLUDE;LIB;PATH;PROMPT;TEMP;TMP;TZ;", name) == NULL) {
10950: // ignore non standard environments
10951: } else {
1.1 root 10952: if(strncmp(tmp, "COMSPEC=", 8) == 0) {
1.1.1.14 root 10953: strcpy(tmp, "COMSPEC=C:\\COMMAND.COM");
1.1.1.24 root 10954: } else if(strncmp(tmp, "TEMP=", 5) == 0 && temp_path[0] != '\0') {
10955: sprintf(tmp, "TEMP=%s", temp_path);
10956: } else if(strncmp(tmp, "TMP=", 4) == 0 && temp_path[0] != '\0') {
10957: sprintf(tmp, "TMP=%s", temp_path);
1.1 root 10958: } else if(strncmp(tmp, "PATH=", 5) == 0 || strncmp(tmp, "TEMP=", 5) == 0 || strncmp(tmp, "TMP=", 4) == 0) {
10959: tmp[value_pos] = '\0';
10960: char *token = my_strtok(value, ";");
10961: while(token != NULL) {
10962: if(strlen(token) != 0) {
1.1.1.24 root 10963: char *path = msdos_remove_double_quote(token), short_path[MAX_PATH];
1.1.1.8 root 10964: if(strlen(path) != 0) {
1.1.1.24 root 10965: if(GetShortPathName(path, short_path, MAX_PATH) == 0) {
10966: strcat(tmp, path);
10967: } else {
10968: strcat(tmp, short_path);
10969: }
1.1.1.8 root 10970: strcat(tmp, ";");
1.1 root 10971: }
10972: }
10973: token = my_strtok(NULL, ";");
10974: }
10975: tmp[strlen(tmp) - 1] = '\0';
10976: my_strupr(tmp);
10977: }
10978: int len = strlen(tmp);
1.1.1.14 root 10979: if(ofs + len + 1 + (2 + (8 + 1 + 3)) + 2 > ENV_SIZE) {
1.1 root 10980: fatalerror("too many environments\n");
10981: }
10982: memcpy(mem + (seg << 4) + ofs, tmp, len);
10983: ofs += len + 1;
10984: }
10985: }
10986: seg += (ENV_SIZE >> 4);
10987:
10988: // psp
10989: msdos_mcb_create(seg++, 'M', -1, PSP_SIZE >> 4);
10990: current_psp = seg;
1.1.1.14 root 10991: msdos_psp_create(seg, seg + (PSP_SIZE >> 4), -1, env_seg);
1.1 root 10992: seg += (PSP_SIZE >> 4);
10993:
1.1.1.19 root 10994: // first free mcb in conventional memory
10995: msdos_mcb_create(seg, 'Z', 0, (MEMORY_END >> 4) - seg - 2);
1.1.1.8 root 10996: first_mcb = seg;
10997:
1.1.1.19 root 10998: // dummy mcb to link to umb
10999: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', -1, (UMB_TOP >> 4) - (MEMORY_END >> 4));
11000:
11001: // first free mcb in upper memory block
1.1.1.8 root 11002: msdos_mcb_create(UMB_TOP >> 4, 'Z', 0, (UMB_END >> 4) - (UMB_TOP >> 4) - 1);
1.1 root 11003:
1.1.1.19 root 11004: #ifdef SUPPORT_XMS
11005: // first free mcb in extended memory block
11006: msdos_mcb_create(EMB_TOP >> 4, 'Z', 0, (EMB_END >> 4) - (EMB_TOP >> 4) - 1);
11007: #endif
11008:
1.1.1.26 root 11009: // interrupt vector
11010: for(int i = 0; i < 0x80; i++) {
11011: *(UINT16 *)(mem + 4 * i + 0) = i;
11012: *(UINT16 *)(mem + 4 * i + 2) = (IRET_TOP >> 4);
11013: }
11014: *(UINT16 *)(mem + 4 * 0x08 + 0) = 0x0010; // fffd:0010 irq0 (system timer)
11015: *(UINT16 *)(mem + 4 * 0x08 + 2) = 0xfffd;
11016: *(UINT16 *)(mem + 4 * 0x22 + 0) = 0x0000; // ffff:0000 boot
11017: *(UINT16 *)(mem + 4 * 0x22 + 2) = 0xffff;
11018: *(UINT16 *)(mem + 4 * 0x67 + 0) = 0x0012; // xxxx:0012 ems
11019: *(UINT16 *)(mem + 4 * 0x67 + 2) = XMS_TOP >> 4;
11020: *(UINT16 *)(mem + 4 * 0x74 + 0) = 0x0000; // fffd:0000 irq12 (mouse)
11021: *(UINT16 *)(mem + 4 * 0x74 + 2) = 0xfffd;
11022:
11023: // dummy devices (CON -> ... -> CONFIG$ -> NUL -> EMMXXXX0)
11024: static const struct {
11025: UINT16 attributes;
11026: char *dev_name;
11027: } dummy_devices[] = {
11028: {0x8013, "CON "},
11029: {0x8000, "AUX "},
11030: {0xa0c0, "PRN "},
11031: {0x8008, "CLOCK$ "},
11032: {0x8000, "COM1 "},
11033: {0xa0c0, "LPT1 "},
11034: {0xa0c0, "LPT2 "},
11035: {0xa0c0, "LPT3 "},
11036: {0x8000, "COM2 "},
11037: {0x8000, "COM3 "},
11038: {0x8000, "COM4 "},
11039: {0xc000, "CONFIG$ "},
11040: };
11041: static const UINT8 dummy_device_routine[] = {
11042: // from NUL device of Windows 98 SE
11043: // or word ptr ES:[BX+03],0100
11044: 0x26, 0x81, 0x4f, 0x03, 0x00, 0x01,
11045: // retf
11046: 0xcb,
11047: };
11048: for(int i = 0; i < 12; i++) {
11049: device_t *device = (device_t *)(mem + DEVICE_TOP + 22 + 18 * i);
11050: if(i == 11) {
11051: device->next_driver.w.l = offsetof(dos_info_t, nul_device);
11052: device->next_driver.w.h = DOS_INFO_TOP >> 4;
11053: } else {
11054: device->next_driver.w.l = 22 + 18 * (i + 1);
11055: device->next_driver.w.h = DEVICE_TOP >> 4;
11056: }
11057: device->attributes = dummy_devices[i].attributes;
11058: device->strategy = 22 + 18 * 12;
11059: device->interrupt = 22 + 18 * 12 + 6;
11060: memcpy(device->dev_name, dummy_devices[i].dev_name, 8);
11061: }
11062: memcpy(mem + DEVICE_TOP + 22 + 18 * 12, dummy_device_routine, sizeof(dummy_device_routine));
11063:
1.1.1.25 root 11064: // dos info
11065: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
11066: dos_info->magic_word = 1;
11067: dos_info->first_mcb = MEMORY_TOP >> 4;
11068: dos_info->first_dpb.w.l = 0;
11069: dos_info->first_dpb.w.h = DPB_TOP >> 4;
11070: dos_info->first_sft.w.l = 0;
11071: dos_info->first_sft.w.h = SFT_TOP >> 4;
1.1.1.26 root 11072: dos_info->clock_device.w.l = 22 + 18 * 3; // CLOCK$ is the 3rd device in IO.SYS
1.1.1.25 root 11073: dos_info->clock_device.w.h = DEVICE_TOP >> 4;
1.1.1.26 root 11074: dos_info->con_device.w.l = 22 + 18 * 0; // CON is the 1st device in IO.SYS
1.1.1.25 root 11075: dos_info->con_device.w.h = DEVICE_TOP >> 4;
11076: dos_info->max_sector_len = 512;
11077: dos_info->disk_buf_info.w.l = offsetof(dos_info_t, disk_buf_heads);
11078: dos_info->disk_buf_info.w.h = DOS_INFO_TOP >> 4;
11079: dos_info->cds.w.l = 0;
11080: dos_info->cds.w.h = CDS_TOP >> 4;
11081: dos_info->fcb_table.w.l = 0;
11082: dos_info->fcb_table.w.h = FCB_TABLE_TOP >> 4;
11083: dos_info->last_drive = 'Z' - 'A' + 1;
11084: dos_info->buffers_x = 20;
11085: dos_info->buffers_y = 0;
11086: dos_info->boot_drive = 'C' - 'A' + 1;
11087: dos_info->nul_device.next_driver.w.l = 0;
11088: dos_info->nul_device.next_driver.w.h = XMS_TOP >> 4;
11089: dos_info->nul_device.attributes = 0x8004;
1.1.1.26 root 11090: dos_info->nul_device.strategy = offsetof(dos_info_t, nul_device_routine);
11091: dos_info->nul_device.interrupt = offsetof(dos_info_t, nul_device_routine) + 6;
1.1.1.25 root 11092: memcpy(dos_info->nul_device.dev_name, "NUL ", 8);
11093: dos_info->disk_buf_heads.w.l = 0;
11094: dos_info->disk_buf_heads.w.h = DISK_BUF_TOP >> 4;
11095: dos_info->first_umb_fcb = UMB_TOP >> 4;
11096: dos_info->first_mcb_2 = MEMORY_TOP >> 4;
1.1.1.26 root 11097: memcpy(dos_info->nul_device_routine, dummy_device_routine, sizeof(dummy_device_routine));
1.1.1.25 root 11098:
11099: char *env;
11100: if((env = getenv("LASTDRIVE")) != NULL) {
11101: if(env[0] >= 'A' && env[0] <= 'Z') {
11102: dos_info->last_drive = env[0] - 'A' + 1;
11103: } else if(env[0] >= 'a' && env[0] <= 'z') {
11104: dos_info->last_drive = env[0] - 'a' + 1;
11105: }
11106: }
11107: if((env = getenv("windir")) != NULL) {
11108: if(env[0] >= 'A' && env[0] <= 'Z') {
11109: dos_info->boot_drive = env[0] - 'A' + 1;
11110: } else if(env[0] >= 'a' && env[0] <= 'z') {
11111: dos_info->boot_drive = env[0] - 'a' + 1;
11112: }
11113: }
11114: #if defined(HAS_I386)
11115: dos_info->i386_or_later = 1;
11116: #else
11117: dos_info->i386_or_later = 0;
11118: #endif
11119: dos_info->ext_mem_size = (min(MAX_MEM, 0x4000000) - 0x100000) >> 10;
11120:
1.1.1.27! root 11121: // ems (int 67h) and xms
1.1.1.25 root 11122: device_t *xms_device = (device_t *)(mem + XMS_TOP);
11123: xms_device->next_driver.w.l = 0xffff;
11124: xms_device->next_driver.w.h = 0xffff;
11125: xms_device->attributes = 0xc000;
1.1.1.26 root 11126: xms_device->strategy = 0x18;
11127: xms_device->interrupt = 0x18 + 6;
1.1.1.25 root 11128: memcpy(xms_device->dev_name, "EMMXXXX0", 8);
11129:
1.1.1.26 root 11130: mem[XMS_TOP + 0x12] = 0xcd; // int 68h (dummy)
11131: mem[XMS_TOP + 0x13] = 0x68;
11132: mem[XMS_TOP + 0x14] = 0xcf; // iret
1.1.1.19 root 11133: #ifdef SUPPORT_XMS
11134: if(support_xms) {
1.1.1.26 root 11135: mem[XMS_TOP + 0x15] = 0xcd; // int 69h (dummy)
11136: mem[XMS_TOP + 0x16] = 0x69;
11137: mem[XMS_TOP + 0x17] = 0xcb; // retf
1.1.1.19 root 11138: } else
11139: #endif
1.1.1.26 root 11140: mem[XMS_TOP + 0x15] = 0xcb; // retf
11141: memcpy(mem + XMS_TOP + 0x18, dummy_device_routine, sizeof(dummy_device_routine));
1.1.1.19 root 11142:
1.1.1.26 root 11143: // irq12 routine (mouse)
1.1.1.24 root 11144: mem[0xfffd0 + 0x00] = 0xcd; // int 6ah (dummy)
11145: mem[0xfffd0 + 0x01] = 0x6a;
11146: mem[0xfffd0 + 0x02] = 0x9a; // call far mouse
11147: mem[0xfffd0 + 0x03] = 0xff;
11148: mem[0xfffd0 + 0x04] = 0xff;
11149: mem[0xfffd0 + 0x05] = 0xff;
11150: mem[0xfffd0 + 0x06] = 0xff;
11151: mem[0xfffd0 + 0x07] = 0xcd; // int 6bh (dummy)
11152: mem[0xfffd0 + 0x08] = 0x6b;
11153: mem[0xfffd0 + 0x09] = 0xcf; // iret
11154:
1.1.1.27! root 11155: // case map routine
! 11156: mem[0xfffd0 + 0x0a] = 0xcd; // int 6ch (dummy)
! 11157: mem[0xfffd0 + 0x0b] = 0x6c;
! 11158: mem[0xfffd0 + 0x0c] = 0xcb; // retf
! 11159:
! 11160: // font read routine
! 11161: mem[0xfffd0 + 0x0d] = 0xcd; // int 6dh (dummy)
! 11162: mem[0xfffd0 + 0x0e] = 0x6d;
! 11163: mem[0xfffd0 + 0x0f] = 0xcb; // retf
1.1.1.19 root 11164:
1.1.1.26 root 11165: // irq0 routine (system time)
1.1.1.24 root 11166: mem[0xfffd0 + 0x10] = 0xcd; // int 1ch
11167: mem[0xfffd0 + 0x11] = 0x1c;
11168: mem[0xfffd0 + 0x12] = 0xea; // jmp far (IRET_TOP >> 4):0008
11169: mem[0xfffd0 + 0x13] = 0x08;
11170: mem[0xfffd0 + 0x14] = 0x00;
11171: mem[0xfffd0 + 0x15] = ((IRET_TOP >> 4) ) & 0xff;
11172: mem[0xfffd0 + 0x16] = ((IRET_TOP >> 4) >> 8) & 0xff;
1.1.1.14 root 11173:
1.1.1.26 root 11174: // boot routine
1.1 root 11175: mem[0xffff0] = 0xf4; // halt
11176: mem[0xffff1] = 0xcd; // int 21h
11177: mem[0xffff2] = 0x21;
11178: mem[0xffff3] = 0xcb; // retf
11179:
1.1.1.24 root 11180: mem[0xffff5] = '0'; // rom date
11181: mem[0xffff6] = '2';
11182: mem[0xffff7] = '/';
11183: mem[0xffff8] = '2';
11184: mem[0xffff9] = '2';
11185: mem[0xffffa] = '/';
11186: mem[0xffffb] = '0';
11187: mem[0xffffc] = '6';
11188: mem[0xffffe] = 0xfc; // machine id
11189: mem[0xfffff] = 0x00;
11190:
1.1 root 11191: // param block
11192: // + 0: param block (22bytes)
11193: // +24: fcb1/2 (20bytes)
11194: // +44: command tail (128bytes)
11195: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
11196: param->env_seg = 0;
11197: param->cmd_line.w.l = 44;
11198: param->cmd_line.w.h = (WORK_TOP >> 4);
11199: param->fcb1.w.l = 24;
11200: param->fcb1.w.h = (WORK_TOP >> 4);
11201: param->fcb2.w.l = 24;
11202: param->fcb2.w.h = (WORK_TOP >> 4);
11203:
11204: memset(mem + WORK_TOP + 24, 0x20, 20);
11205:
11206: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
11207: if(argc > 1) {
11208: sprintf(cmd_line->cmd, " %s", argv[1]);
11209: for(int i = 2; i < argc; i++) {
11210: char tmp[128];
11211: sprintf(tmp, "%s %s", cmd_line->cmd, argv[i]);
11212: strcpy(cmd_line->cmd, tmp);
11213: }
11214: cmd_line->len = (UINT8)strlen(cmd_line->cmd);
11215: } else {
11216: cmd_line->len = 0;
11217: }
11218: cmd_line->cmd[cmd_line->len] = 0x0d;
11219:
11220: // system file table
1.1.1.21 root 11221: *(UINT32 *)(mem + SFT_TOP + 0) = 0xffffffff;
11222: *(UINT16 *)(mem + SFT_TOP + 4) = 20;
1.1 root 11223:
1.1.1.19 root 11224: // disk buffer header (from DOSBox)
11225: *(UINT16 *)(mem + DISK_BUF_TOP + 0) = 0xffff; // forward ptr
11226: *(UINT16 *)(mem + DISK_BUF_TOP + 2) = 0xffff; // backward ptr
11227: *(UINT8 *)(mem + DISK_BUF_TOP + 4) = 0xff; // not in use
11228: *(UINT8 *)(mem + DISK_BUF_TOP + 10) = 0x01; // number of FATs
11229: *(UINT32 *)(mem + DISK_BUF_TOP + 13) = 0xffffffff; // pointer to DPB
11230:
1.1 root 11231: // current directory structure
11232: msdos_cds_update(_getdrive() - 1);
11233:
11234: // fcb table
11235: *(UINT32 *)(mem + FCB_TABLE_TOP + 0) = 0xffffffff;
1.1.1.14 root 11236: *(UINT16 *)(mem + FCB_TABLE_TOP + 4) = 0;
1.1 root 11237:
1.1.1.22 root 11238: // error table
11239: *(UINT8 *)(mem + ERR_TABLE_TOP + 0) = 0xff;
11240: *(UINT8 *)(mem + ERR_TABLE_TOP + 1) = 0x04;
11241: *(UINT8 *)(mem + ERR_TABLE_TOP + 2) = 0x00;
11242: *(UINT8 *)(mem + ERR_TABLE_TOP + 3) = 0x00;
11243:
1.1.1.17 root 11244: // nls stuff
11245: msdos_nls_tables_init();
1.1 root 11246:
11247: // execute command
11248: if(msdos_process_exec(argv[0], param, 0)) {
11249: fatalerror("'%s' not found\n", argv[0]);
11250: }
11251: retval = 0;
11252: return(0);
11253: }
11254:
11255: #define remove_std_file(path) { \
11256: int fd = _open(path, _O_RDONLY | _O_BINARY); \
11257: if(fd != -1) { \
11258: _lseek(fd, 0, SEEK_END); \
11259: int size = _tell(fd); \
11260: _close(fd); \
11261: if(size == 0) { \
11262: remove(path); \
11263: } \
11264: } \
11265: }
11266:
11267: void msdos_finish()
11268: {
11269: for(int i = 0; i < MAX_FILES; i++) {
11270: if(file_handler[i].valid) {
11271: _close(i);
11272: }
11273: }
1.1.1.21 root 11274: #ifdef MAP_AUX_DEVICE_TO_FILE
1.1 root 11275: remove_std_file("stdaux.txt");
1.1.1.21 root 11276: #endif
11277: #ifdef MAP_PRN_DEVICE_TO_FILE
1.1 root 11278: remove_std_file("stdprn.txt");
11279: #endif
11280: msdos_dbcs_table_finish();
11281: }
11282:
11283: /* ----------------------------------------------------------------------------
11284: PC/AT hardware emulation
11285: ---------------------------------------------------------------------------- */
11286:
11287: void hardware_init()
11288: {
1.1.1.3 root 11289: CPU_INIT_CALL(CPU_MODEL);
1.1 root 11290: CPU_RESET_CALL(CPU_MODEL);
1.1.1.14 root 11291: m_IF = 1;
1.1.1.3 root 11292: #if defined(HAS_I386)
1.1 root 11293: cpu_type = (REG32(EDX) >> 8) & 0x0f;
11294: cpu_step = (REG32(EDX) >> 0) & 0x0f;
1.1.1.3 root 11295: #endif
11296: i386_set_a20_line(0);
1.1.1.14 root 11297:
1.1.1.19 root 11298: ems_init();
1.1.1.25 root 11299: dma_init();
1.1 root 11300: pic_init();
1.1.1.25 root 11301: pio_init();
1.1.1.8 root 11302: #ifdef PIT_ALWAYS_RUNNING
11303: pit_init();
11304: #else
1.1 root 11305: pit_active = 0;
11306: #endif
1.1.1.25 root 11307: sio_init();
1.1.1.8 root 11308: cmos_init();
11309: kbd_init();
1.1 root 11310: }
11311:
1.1.1.10 root 11312: void hardware_finish()
11313: {
11314: #if defined(HAS_I386)
11315: vtlb_free(m_vtlb);
11316: #endif
1.1.1.19 root 11317: ems_finish();
1.1.1.25 root 11318: sio_finish();
1.1.1.10 root 11319: }
11320:
1.1 root 11321: void hardware_run()
11322: {
11323: int ops = 0;
11324:
1.1.1.22 root 11325: #ifdef EXPORT_DEBUG_TO_FILE
11326: fdebug = fopen("debug.log", "w");
11327: #endif
1.1.1.3 root 11328: while(!m_halted) {
1.1.1.22 root 11329: #ifdef ENABLE_DEBUG_DASM
11330: if(dasm > 0) {
1.1 root 11331: char buffer[256];
1.1.1.3 root 11332: #if defined(HAS_I386)
1.1.1.22 root 11333: UINT32 flags = get_flags();
1.1.1.19 root 11334: UINT32 eip = m_eip;
1.1.1.3 root 11335: #else
1.1.1.22 root 11336: UINT32 flags = CompressFlags();
1.1.1.19 root 11337: UINT32 eip = m_pc - SREG_BASE(CS);
1.1.1.3 root 11338: #endif
11339: UINT8 *oprom = mem + SREG_BASE(CS) + eip;
1.1 root 11340:
1.1.1.3 root 11341: #if defined(HAS_I386)
11342: if(m_operand_size) {
1.1 root 11343: CPU_DISASSEMBLE_CALL(x86_32);
1.1.1.3 root 11344: } else
11345: #endif
11346: CPU_DISASSEMBLE_CALL(x86_16);
1.1.1.22 root 11347:
11348: 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",
11349: 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,
11350: #if defined(HAS_I386)
11351: PROTECTED_MODE ? "PE" : "--",
11352: #else
11353: "--",
11354: #endif
11355: (flags & 0x40000) ? 'A' : '-',
11356: (flags & 0x20000) ? 'V' : '-',
11357: (flags & 0x10000) ? 'R' : '-',
11358: (flags & 0x04000) ? 'N' : '-',
11359: (flags & 0x02000) ? '1' : '0',
11360: (flags & 0x01000) ? '1' : '0',
11361: (flags & 0x00800) ? 'O' : '-',
11362: (flags & 0x00400) ? 'D' : '-',
11363: (flags & 0x00200) ? 'I' : '-',
11364: (flags & 0x00100) ? 'T' : '-',
11365: (flags & 0x00080) ? 'S' : '-',
11366: (flags & 0x00040) ? 'Z' : '-',
11367: (flags & 0x00010) ? 'A' : '-',
11368: (flags & 0x00004) ? 'P' : '-',
11369: (flags & 0x00001) ? 'C' : '-');
11370: fprintf(fdebug, "%04X:%04X\t%s\n", SREG(CS), (unsigned)eip, buffer);
11371: dasm--;
1.1 root 11372: }
11373: #endif
1.1.1.3 root 11374: #if defined(HAS_I386)
11375: m_cycles = 1;
1.1 root 11376: CPU_EXECUTE_CALL(i386);
1.1.1.3 root 11377: #else
11378: CPU_EXECUTE_CALL(CPU_MODEL);
11379: #endif
1.1.1.14 root 11380: #if defined(HAS_I386)
11381: if(m_eip != m_prev_eip) {
11382: #else
11383: if(m_pc != m_prevpc) {
11384: #endif
11385: iops++;
11386: }
1.1.1.8 root 11387: if(++ops == 16384) {
1.1 root 11388: hardware_update();
11389: ops = 0;
11390: }
11391: }
1.1.1.22 root 11392: #ifdef EXPORT_DEBUG_TO_FILE
11393: fclose(fdebug);
11394: #endif
1.1 root 11395: }
11396:
11397: void hardware_update()
11398: {
1.1.1.8 root 11399: static UINT32 prev_time = 0;
11400: UINT32 cur_time = timeGetTime();
11401:
11402: if(prev_time != cur_time) {
11403: // update pit and raise irq0
11404: #ifndef PIT_ALWAYS_RUNNING
11405: if(pit_active)
11406: #endif
11407: {
11408: if(pit_run(0, cur_time)) {
11409: pic_req(0, 0, 1);
11410: }
11411: pit_run(1, cur_time);
11412: pit_run(2, cur_time);
11413: }
1.1.1.24 root 11414:
1.1.1.25 root 11415: // update sio and raise irq4/3
11416: for(int c = 0; c < 2; c++) {
11417: sio_update(c);
11418: }
11419:
1.1.1.24 root 11420: // update keyboard and mouse
1.1.1.14 root 11421: static UINT32 prev_tick = 0;
11422: UINT32 cur_tick = cur_time / 32;
1.1.1.25 root 11423:
1.1.1.14 root 11424: if(prev_tick != cur_tick) {
11425: // update keyboard flags
11426: UINT8 state;
1.1.1.24 root 11427: state = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
11428: state |= (GetAsyncKeyState(VK_CAPITAL ) & 0x0001) ? 0x40 : 0;
11429: state |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x0001) ? 0x20 : 0;
11430: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
11431: state |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
11432: state |= (GetAsyncKeyState(VK_CONTROL ) & 0x8000) ? 0x04 : 0;
11433: state |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
11434: state |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
1.1.1.14 root 11435: mem[0x417] = state;
11436: state = (GetAsyncKeyState(VK_INSERT ) & 0x8000) ? 0x80 : 0;
11437: state |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
11438: state |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
11439: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
1.1.1.24 root 11440: // state |= (GetAsyncKeyState(VK_PAUSE ) & 0x0001) ? 0x08 : 0;
11441: // state |= (GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x04 : 0;
1.1.1.14 root 11442: state |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
11443: state |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
11444: mem[0x418] = state;
11445:
1.1.1.24 root 11446: // update console input if needed
11447: if(!key_changed || mouse.active) {
11448: update_console_input();
11449: }
11450:
11451: // raise irq1 if key is pressed/released
11452: if(key_changed) {
1.1.1.8 root 11453: pic_req(0, 1, 1);
1.1.1.24 root 11454: key_changed = false;
11455: }
11456:
11457: // raise irq12 if mouse status is changed
11458: if(mouse.status & mouse.call_mask) {
11459: if(mouse.active) {
11460: pic_req(1, 4, 1);
11461: mouse.status_irq = mouse.status & mouse.call_mask;
11462: }
11463: mouse.status &= ~mouse.call_mask;
1.1.1.8 root 11464: }
1.1.1.24 root 11465:
1.1.1.14 root 11466: prev_tick = cur_tick;
1.1.1.8 root 11467: }
1.1.1.24 root 11468:
1.1.1.19 root 11469: // update daily timer counter
11470: pcbios_update_daily_timer_counter(cur_time);
1.1.1.25 root 11471:
1.1.1.8 root 11472: prev_time = cur_time;
1.1 root 11473: }
11474: }
11475:
1.1.1.19 root 11476: // ems
11477:
11478: void ems_init()
11479: {
11480: memset(ems_handles, 0, sizeof(ems_handles));
11481: memset(ems_pages, 0, sizeof(ems_pages));
11482: free_ems_pages = MAX_EMS_PAGES;
11483: }
11484:
11485: void ems_finish()
11486: {
11487: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
11488: if(ems_handles[i].buffer) {
11489: free(ems_handles[i].buffer);
11490: ems_handles[i].buffer = NULL;
11491: }
11492: }
11493: }
11494:
11495: void ems_allocate_pages(int handle, int pages)
11496: {
11497: if(pages > 0) {
11498: ems_handles[handle].buffer = (UINT8 *)calloc(1, 0x4000 * pages);
11499: } else {
11500: ems_handles[handle].buffer = NULL;
11501: }
11502: ems_handles[handle].pages = pages;
11503: ems_handles[handle].allocated = true;
11504: free_ems_pages -= pages;
11505: }
11506:
11507: void ems_reallocate_pages(int handle, int pages)
11508: {
11509: if(ems_handles[handle].allocated) {
11510: if(ems_handles[handle].pages != pages) {
11511: UINT8 *new_buffer = NULL;
11512:
11513: if(pages > 0) {
11514: new_buffer = (UINT8 *)calloc(1, 0x4000 * pages);
11515: }
11516: if(ems_handles[handle].buffer) {
11517: if(new_buffer) {
11518: if(pages > ems_handles[handle].pages) {
11519: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * ems_handles[handle].pages);
11520: } else {
11521: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * pages);
11522: }
11523: }
11524: free(ems_handles[handle].buffer);
11525: ems_handles[handle].buffer = NULL;
11526: }
11527: free_ems_pages += ems_handles[handle].pages;
11528:
11529: ems_handles[handle].buffer = new_buffer;
11530: ems_handles[handle].pages = pages;
11531: free_ems_pages -= pages;
11532: }
11533: } else {
11534: ems_allocate_pages(handle, pages);
11535: }
11536: }
11537:
11538: void ems_release_pages(int handle)
11539: {
11540: if(ems_handles[handle].allocated) {
11541: if(ems_handles[handle].buffer) {
11542: free(ems_handles[handle].buffer);
11543: ems_handles[handle].buffer = NULL;
11544: }
11545: free_ems_pages += ems_handles[handle].pages;
11546: ems_handles[handle].allocated = false;
11547: }
11548: }
11549:
11550: void ems_map_page(int physical, int handle, int logical)
11551: {
11552: if(ems_pages[physical].mapped) {
11553: if(ems_pages[physical].handle == handle && ems_pages[physical].page == logical) {
11554: return;
11555: }
11556: ems_unmap_page(physical);
11557: }
11558: if(ems_handles[handle].allocated && ems_handles[handle].buffer && logical < ems_handles[handle].pages) {
11559: memcpy(mem + EMS_TOP + 0x4000 * physical, ems_handles[handle].buffer + 0x4000 * logical, 0x4000);
11560: }
11561: ems_pages[physical].handle = handle;
11562: ems_pages[physical].page = logical;
11563: ems_pages[physical].mapped = true;
11564: }
11565:
11566: void ems_unmap_page(int physical)
11567: {
11568: if(ems_pages[physical].mapped) {
11569: int handle = ems_pages[physical].handle;
11570: int logical = ems_pages[physical].page;
11571:
11572: if(ems_handles[handle].allocated && ems_handles[handle].buffer && logical < ems_handles[handle].pages) {
11573: memcpy(ems_handles[handle].buffer + 0x4000 * logical, mem + EMS_TOP + 0x4000 * physical, 0x4000);
11574: }
11575: ems_pages[physical].mapped = false;
11576: }
11577: }
11578:
1.1.1.25 root 11579: // dma
1.1 root 11580:
1.1.1.25 root 11581: void dma_init()
1.1 root 11582: {
1.1.1.26 root 11583: memset(dma, 0, sizeof(dma));
1.1.1.25 root 11584: for(int c = 0; c < 2; c++) {
1.1.1.26 root 11585: // for(int ch = 0; ch < 4; ch++) {
11586: // dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w = 0xffff;
11587: // }
1.1.1.25 root 11588: dma_reset(c);
11589: }
1.1 root 11590: }
11591:
1.1.1.25 root 11592: void dma_reset(int c)
1.1 root 11593: {
1.1.1.25 root 11594: dma[c].low_high = false;
11595: dma[c].cmd = dma[c].req = dma[c].tc = 0;
11596: dma[c].mask = 0xff;
11597: }
11598:
11599: void dma_write(int c, UINT32 addr, UINT8 data)
11600: {
11601: int ch = (addr >> 1) & 3;
11602: UINT8 bit = 1 << (data & 3);
11603:
11604: switch(addr & 0x0f) {
11605: case 0x00: case 0x02: case 0x04: case 0x06:
11606: if(dma[c].low_high) {
11607: dma[c].ch[ch].bareg.b.h = data;
1.1 root 11608: } else {
1.1.1.25 root 11609: dma[c].ch[ch].bareg.b.l = data;
11610: }
11611: dma[c].ch[ch].areg.w = dma[c].ch[ch].bareg.w;
11612: dma[c].low_high = !dma[c].low_high;
11613: break;
11614: case 0x01: case 0x03: case 0x05: case 0x07:
11615: if(dma[c].low_high) {
11616: dma[c].ch[ch].bcreg.b.h = data;
11617: } else {
11618: dma[c].ch[ch].bcreg.b.l = data;
11619: }
11620: dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w;
11621: dma[c].low_high = !dma[c].low_high;
11622: break;
11623: case 0x08:
11624: // command register
11625: dma[c].cmd = data;
11626: break;
11627: case 0x09:
11628: // dma[c].request register
11629: if(data & 4) {
11630: if(!(dma[c].req & bit)) {
11631: dma[c].req |= bit;
11632: // dma_run(c, ch);
11633: }
11634: } else {
11635: dma[c].req &= ~bit;
11636: }
11637: break;
11638: case 0x0a:
11639: // single mask register
11640: if(data & 4) {
11641: dma[c].mask |= bit;
11642: } else {
11643: dma[c].mask &= ~bit;
11644: }
11645: break;
11646: case 0x0b:
11647: // mode register
11648: dma[c].ch[data & 3].mode = data;
11649: break;
11650: case 0x0c:
11651: dma[c].low_high = false;
11652: break;
11653: case 0x0d:
11654: // clear master
11655: dma_reset(c);
11656: break;
11657: case 0x0e:
11658: // clear mask register
11659: dma[c].mask = 0;
11660: break;
11661: case 0x0f:
11662: // all mask register
11663: dma[c].mask = data & 0x0f;
11664: break;
11665: }
11666: }
11667:
11668: UINT8 dma_read(int c, UINT32 addr)
11669: {
11670: int ch = (addr >> 1) & 3;
11671: UINT8 val = 0xff;
11672:
11673: switch(addr & 0x0f) {
11674: case 0x00: case 0x02: case 0x04: case 0x06:
11675: if(dma[c].low_high) {
11676: val = dma[c].ch[ch].areg.b.h;
11677: } else {
11678: val = dma[c].ch[ch].areg.b.l;
11679: }
11680: dma[c].low_high = !dma[c].low_high;
11681: return(val);
11682: case 0x01: case 0x03: case 0x05: case 0x07:
11683: if(dma[c].low_high) {
11684: val = dma[c].ch[ch].creg.b.h;
11685: } else {
11686: val = dma[c].ch[ch].creg.b.l;
11687: }
11688: dma[c].low_high = !dma[c].low_high;
11689: return(val);
11690: case 0x08:
11691: // status register
11692: val = (dma[c].req << 4) | dma[c].tc;
11693: dma[c].tc = 0;
11694: return(val);
11695: case 0x0d:
1.1.1.26 root 11696: // temporary register (intel 82374 does not support)
1.1.1.25 root 11697: return(dma[c].tmp & 0xff);
1.1.1.26 root 11698: case 0x0f:
11699: // mask register (intel 82374 does support)
11700: return(dma[c].mask);
1.1.1.25 root 11701: }
11702: return(0xff);
11703: }
11704:
11705: void dma_page_write(int c, int ch, UINT8 data)
11706: {
11707: dma[c].ch[ch].pagereg = data;
11708: }
11709:
11710: UINT8 dma_page_read(int c, int ch)
11711: {
11712: return(dma[c].ch[ch].pagereg);
11713: }
11714:
11715: void dma_run(int c, int ch)
11716: {
11717: UINT8 bit = 1 << ch;
11718:
11719: if((dma[c].req & bit) && !(dma[c].mask & bit)) {
11720: // execute dma
11721: while(dma[c].req & bit) {
11722: if(ch == 0 && (dma[c].cmd & 0x01)) {
11723: // memory -> memory
11724: UINT32 saddr = dma[c].ch[0].areg.w | (dma[c].ch[0].pagereg << 16);
11725: UINT32 daddr = dma[c].ch[1].areg.w | (dma[c].ch[1].pagereg << 16);
11726:
11727: if(c == 0) {
11728: dma[c].tmp = read_byte(saddr);
11729: write_byte(daddr, dma[c].tmp);
11730: } else {
11731: dma[c].tmp = read_word(saddr << 1);
11732: write_word(daddr << 1, dma[c].tmp);
11733: }
11734: if(!(dma[c].cmd & 0x02)) {
11735: if(dma[c].ch[0].mode & 0x20) {
11736: dma[c].ch[0].areg.w--;
11737: if(dma[c].ch[0].areg.w == 0xffff) {
11738: dma[c].ch[0].pagereg--;
11739: }
11740: } else {
11741: dma[c].ch[0].areg.w++;
11742: if(dma[c].ch[0].areg.w == 0) {
11743: dma[c].ch[0].pagereg++;
11744: }
11745: }
11746: }
11747: if(dma[c].ch[1].mode & 0x20) {
11748: dma[c].ch[1].areg.w--;
11749: if(dma[c].ch[1].areg.w == 0xffff) {
11750: dma[c].ch[1].pagereg--;
11751: }
11752: } else {
11753: dma[c].ch[1].areg.w++;
11754: if(dma[c].ch[1].areg.w == 0) {
11755: dma[c].ch[1].pagereg++;
11756: }
11757: }
11758:
11759: // check dma condition
11760: if(dma[c].ch[0].creg.w-- == 0) {
11761: if(dma[c].ch[0].mode & 0x10) {
11762: // self initialize
11763: dma[c].ch[0].areg.w = dma[c].ch[0].bareg.w;
11764: dma[c].ch[0].creg.w = dma[c].ch[0].bcreg.w;
11765: } else {
11766: // dma[c].mask |= bit;
11767: }
11768: }
11769: if(dma[c].ch[1].creg.w-- == 0) {
11770: // terminal count
11771: if(dma[c].ch[1].mode & 0x10) {
11772: // self initialize
11773: dma[c].ch[1].areg.w = dma[c].ch[1].bareg.w;
11774: dma[c].ch[1].creg.w = dma[c].ch[1].bcreg.w;
11775: } else {
11776: dma[c].mask |= bit;
11777: }
11778: dma[c].req &= ~bit;
11779: dma[c].tc |= bit;
11780: }
11781: } else {
11782: UINT32 addr = dma[c].ch[ch].areg.w | (dma[c].ch[ch].pagereg << 16);
11783:
11784: if((dma[c].ch[ch].mode & 0x0c) == 0x00) {
11785: // verify
11786: } else if((dma[c].ch[ch].mode & 0x0c) == 0x04) {
11787: // io -> memory
11788: if(c == 0) {
11789: dma[c].tmp = read_io_byte(dma[c].ch[ch].port);
11790: write_byte(addr, dma[c].tmp);
11791: } else {
11792: dma[c].tmp = read_io_word(dma[c].ch[ch].port);
11793: write_word(addr << 1, dma[c].tmp);
11794: }
11795: } else if((dma[c].ch[ch].mode & 0x0c) == 0x08) {
11796: // memory -> io
11797: if(c == 0) {
11798: dma[c].tmp = read_byte(addr);
11799: write_io_byte(dma[c].ch[ch].port, dma[c].tmp);
11800: } else {
11801: dma[c].tmp = read_word(addr << 1);
11802: write_io_word(dma[c].ch[ch].port, dma[c].tmp);
11803: }
11804: }
11805: if(dma[c].ch[ch].mode & 0x20) {
11806: dma[c].ch[ch].areg.w--;
11807: if(dma[c].ch[ch].areg.w == 0xffff) {
11808: dma[c].ch[ch].pagereg--;
11809: }
11810: } else {
11811: dma[c].ch[ch].areg.w++;
11812: if(dma[c].ch[ch].areg.w == 0) {
11813: dma[c].ch[ch].pagereg++;
11814: }
11815: }
11816:
11817: // check dma condition
11818: if(dma[c].ch[ch].creg.w-- == 0) {
11819: // terminal count
11820: if(dma[c].ch[ch].mode & 0x10) {
11821: // self initialize
11822: dma[c].ch[ch].areg.w = dma[c].ch[ch].bareg.w;
11823: dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w;
11824: } else {
11825: dma[c].mask |= bit;
11826: }
11827: dma[c].req &= ~bit;
11828: dma[c].tc |= bit;
11829: } else if((dma[c].ch[ch].mode & 0xc0) == 0x40) {
11830: // single mode
11831: break;
11832: }
11833: }
11834: }
11835: }
11836: }
11837:
11838: // pic
11839:
11840: void pic_init()
11841: {
11842: memset(pic, 0, sizeof(pic));
11843: pic[0].imr = pic[1].imr = 0xff;
11844:
11845: // from bochs bios
11846: pic_write(0, 0, 0x11); // icw1 = 11h
11847: pic_write(0, 1, 0x08); // icw2 = 08h
11848: pic_write(0, 1, 0x04); // icw3 = 04h
11849: pic_write(0, 1, 0x01); // icw4 = 01h
11850: pic_write(0, 1, 0xb8); // ocw1 = b8h
11851: pic_write(1, 0, 0x11); // icw1 = 11h
11852: pic_write(1, 1, 0x70); // icw2 = 70h
11853: pic_write(1, 1, 0x02); // icw3 = 02h
11854: pic_write(1, 1, 0x01); // icw4 = 01h
11855: }
11856:
11857: void pic_write(int c, UINT32 addr, UINT8 data)
11858: {
11859: if(addr & 1) {
11860: if(pic[c].icw2_r) {
11861: // icw2
11862: pic[c].icw2 = data;
11863: pic[c].icw2_r = 0;
11864: } else if(pic[c].icw3_r) {
11865: // icw3
11866: pic[c].icw3 = data;
11867: pic[c].icw3_r = 0;
11868: } else if(pic[c].icw4_r) {
11869: // icw4
11870: pic[c].icw4 = data;
11871: pic[c].icw4_r = 0;
11872: } else {
11873: // ocw1
1.1 root 11874: pic[c].imr = data;
11875: }
11876: } else {
11877: if(data & 0x10) {
11878: // icw1
11879: pic[c].icw1 = data;
11880: pic[c].icw2_r = 1;
11881: pic[c].icw3_r = (data & 2) ? 0 : 1;
11882: pic[c].icw4_r = data & 1;
11883: pic[c].irr = 0;
11884: pic[c].isr = 0;
11885: pic[c].imr = 0;
11886: pic[c].prio = 0;
11887: if(!(pic[c].icw1 & 1)) {
11888: pic[c].icw4 = 0;
11889: }
11890: pic[c].ocw3 = 0;
11891: } else if(data & 8) {
11892: // ocw3
11893: if(!(data & 2)) {
11894: data = (data & ~1) | (pic[c].ocw3 & 1);
11895: }
11896: if(!(data & 0x40)) {
11897: data = (data & ~0x20) | (pic[c].ocw3 & 0x20);
11898: }
11899: pic[c].ocw3 = data;
11900: } else {
11901: // ocw2
11902: int level = 0;
11903: if(data & 0x40) {
11904: level = data & 7;
11905: } else {
11906: if(!pic[c].isr) {
11907: return;
11908: }
11909: level = pic[c].prio;
11910: while(!(pic[c].isr & (1 << level))) {
11911: level = (level + 1) & 7;
11912: }
11913: }
11914: if(data & 0x80) {
11915: pic[c].prio = (level + 1) & 7;
11916: }
11917: if(data & 0x20) {
11918: pic[c].isr &= ~(1 << level);
11919: }
11920: }
11921: }
11922: pic_update();
11923: }
11924:
11925: UINT8 pic_read(int c, UINT32 addr)
11926: {
11927: if(addr & 1) {
11928: return(pic[c].imr);
11929: } else {
11930: // polling mode is not supported...
11931: //if(pic[c].ocw3 & 4) {
11932: // return ???;
11933: //}
11934: if(pic[c].ocw3 & 1) {
11935: return(pic[c].isr);
11936: } else {
11937: return(pic[c].irr);
11938: }
11939: }
11940: }
11941:
11942: void pic_req(int c, int level, int signal)
11943: {
11944: if(signal) {
11945: pic[c].irr |= (1 << level);
11946: } else {
11947: pic[c].irr &= ~(1 << level);
11948: }
11949: pic_update();
11950: }
11951:
11952: int pic_ack()
11953: {
11954: // ack (INTA=L)
11955: pic[pic_req_chip].isr |= pic_req_bit;
11956: pic[pic_req_chip].irr &= ~pic_req_bit;
11957: if(pic_req_chip > 0) {
11958: // update isr and irr of master
11959: UINT8 slave = 1 << (pic[pic_req_chip].icw3 & 7);
11960: pic[pic_req_chip - 1].isr |= slave;
11961: pic[pic_req_chip - 1].irr &= ~slave;
11962: }
11963: //if(pic[pic_req_chip].icw4 & 1) {
11964: // 8086 mode
11965: int vector = (pic[pic_req_chip].icw2 & 0xf8) | pic_req_level;
11966: //} else {
11967: // // 8080 mode
11968: // UINT16 addr = (UINT16)pic[pic_req_chip].icw2 << 8;
11969: // if(pic[pic_req_chip].icw1 & 4) {
11970: // addr |= (pic[pic_req_chip].icw1 & 0xe0) | (pic_req_level << 2);
11971: // } else {
11972: // addr |= (pic[pic_req_chip].icw1 & 0xc0) | (pic_req_level << 3);
11973: // }
11974: // vector = 0xcd | (addr << 8);
11975: //}
11976: if(pic[pic_req_chip].icw4 & 2) {
11977: // auto eoi
11978: pic[pic_req_chip].isr &= ~pic_req_bit;
11979: }
11980: return(vector);
11981: }
11982:
11983: void pic_update()
11984: {
11985: for(int c = 0; c < 2; c++) {
11986: UINT8 irr = pic[c].irr;
11987: if(c + 1 < 2) {
11988: // this is master
11989: if(pic[c + 1].irr & (~pic[c + 1].imr)) {
11990: // request from slave
11991: irr |= 1 << (pic[c + 1].icw3 & 7);
11992: }
11993: }
11994: irr &= (~pic[c].imr);
11995: if(!irr) {
11996: break;
11997: }
11998: if(!(pic[c].ocw3 & 0x20)) {
11999: irr |= pic[c].isr;
12000: }
12001: int level = pic[c].prio;
12002: UINT8 bit = 1 << level;
12003: while(!(irr & bit)) {
12004: level = (level + 1) & 7;
12005: bit = 1 << level;
12006: }
12007: if((c + 1 < 2) && (pic[c].icw3 & bit)) {
12008: // check slave
12009: continue;
12010: }
12011: if(pic[c].isr & bit) {
12012: break;
12013: }
12014: // interrupt request
12015: pic_req_chip = c;
12016: pic_req_level = level;
12017: pic_req_bit = bit;
1.1.1.3 root 12018: i386_set_irq_line(INPUT_LINE_IRQ, HOLD_LINE);
1.1 root 12019: return;
12020: }
1.1.1.3 root 12021: i386_set_irq_line(INPUT_LINE_IRQ, CLEAR_LINE);
1.1.1.2 root 12022: }
1.1 root 12023:
1.1.1.25 root 12024: // pio
12025:
12026: void pio_init()
12027: {
1.1.1.26 root 12028: memset(pio, 0, sizeof(pio));
1.1.1.25 root 12029: for(int c = 0; c < 2; c++) {
12030: pio[c].stat = 0xde;
12031: pio[c].ctrl = 0x0c;
12032: }
12033: }
12034:
12035: void pio_write(int c, UINT32 addr, UINT8 data)
12036: {
12037: switch(addr & 3) {
12038: case 0:
12039: pio[c].data = data;
12040: break;
12041: case 2:
12042: pio[c].ctrl = data;
12043: break;
12044: }
12045: }
12046:
12047: UINT8 pio_read(int c, UINT32 addr)
12048: {
12049: switch(addr & 3) {
12050: case 0:
12051: return(pio[c].data);
12052: case 1:
12053: return(pio[c].stat);
12054: case 2:
12055: return(pio[c].ctrl);
12056: }
12057: return(0xff);
12058: }
12059:
1.1 root 12060: // pit
12061:
1.1.1.22 root 12062: #define PIT_FREQ 1193182ULL
1.1 root 12063: #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)
12064:
12065: void pit_init()
12066: {
1.1.1.8 root 12067: memset(pit, 0, sizeof(pit));
1.1 root 12068: for(int ch = 0; ch < 3; ch++) {
12069: pit[ch].count = 0x10000;
12070: pit[ch].ctrl_reg = 0x34;
12071: pit[ch].mode = 3;
12072: }
12073:
12074: // from bochs bios
12075: pit_write(3, 0x34);
12076: pit_write(0, 0x00);
12077: pit_write(0, 0x00);
12078: }
12079:
12080: void pit_write(int ch, UINT8 val)
12081: {
1.1.1.8 root 12082: #ifndef PIT_ALWAYS_RUNNING
1.1 root 12083: if(!pit_active) {
12084: pit_active = 1;
12085: pit_init();
12086: }
1.1.1.8 root 12087: #endif
1.1 root 12088: switch(ch) {
12089: case 0:
12090: case 1:
12091: case 2:
12092: // write count register
12093: if(!pit[ch].low_write && !pit[ch].high_write) {
12094: if(pit[ch].ctrl_reg & 0x10) {
12095: pit[ch].low_write = 1;
12096: }
12097: if(pit[ch].ctrl_reg & 0x20) {
12098: pit[ch].high_write = 1;
12099: }
12100: }
12101: if(pit[ch].low_write) {
12102: pit[ch].count_reg = val;
12103: pit[ch].low_write = 0;
12104: } else if(pit[ch].high_write) {
12105: if((pit[ch].ctrl_reg & 0x30) == 0x20) {
12106: pit[ch].count_reg = val << 8;
12107: } else {
12108: pit[ch].count_reg |= val << 8;
12109: }
12110: pit[ch].high_write = 0;
12111: }
12112: // start count
1.1.1.8 root 12113: if(!pit[ch].low_write && !pit[ch].high_write) {
12114: if(pit[ch].mode == 0 || pit[ch].mode == 4 || pit[ch].prev_time == 0) {
12115: pit[ch].count = PIT_COUNT_VALUE(ch);
12116: pit[ch].prev_time = timeGetTime();
12117: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 12118: }
12119: }
12120: break;
12121: case 3: // ctrl reg
12122: if((val & 0xc0) == 0xc0) {
12123: // i8254 read-back command
12124: for(ch = 0; ch < 3; ch++) {
12125: if(!(val & 0x10) && !pit[ch].status_latched) {
12126: pit[ch].status = pit[ch].ctrl_reg & 0x3f;
12127: pit[ch].status_latched = 1;
12128: }
12129: if(!(val & 0x20) && !pit[ch].count_latched) {
12130: pit_latch_count(ch);
12131: }
12132: }
12133: break;
12134: }
12135: ch = (val >> 6) & 3;
12136: if(val & 0x30) {
12137: static int modes[8] = {0, 1, 2, 3, 4, 5, 2, 3};
12138: pit[ch].mode = modes[(val >> 1) & 7];
12139: pit[ch].count_latched = 0;
12140: pit[ch].low_read = pit[ch].high_read = 0;
12141: pit[ch].low_write = pit[ch].high_write = 0;
12142: pit[ch].ctrl_reg = val;
12143: // stop count
1.1.1.8 root 12144: pit[ch].prev_time = pit[ch].expired_time = 0;
1.1 root 12145: pit[ch].count_reg = 0;
12146: } else if(!pit[ch].count_latched) {
12147: pit_latch_count(ch);
12148: }
12149: break;
12150: }
12151: }
12152:
12153: UINT8 pit_read(int ch)
12154: {
1.1.1.8 root 12155: #ifndef PIT_ALWAYS_RUNNING
1.1 root 12156: if(!pit_active) {
12157: pit_active = 1;
12158: pit_init();
12159: }
1.1.1.8 root 12160: #endif
1.1 root 12161: switch(ch) {
12162: case 0:
12163: case 1:
12164: case 2:
12165: if(pit[ch].status_latched) {
12166: pit[ch].status_latched = 0;
12167: return(pit[ch].status);
12168: }
12169: // if not latched, through current count
12170: if(!pit[ch].count_latched) {
12171: if(!pit[ch].low_read && !pit[ch].high_read) {
12172: pit_latch_count(ch);
12173: }
12174: }
12175: // return latched count
12176: if(pit[ch].low_read) {
12177: pit[ch].low_read = 0;
12178: if(!pit[ch].high_read) {
12179: pit[ch].count_latched = 0;
12180: }
12181: return(pit[ch].latch & 0xff);
12182: } else if(pit[ch].high_read) {
12183: pit[ch].high_read = 0;
12184: pit[ch].count_latched = 0;
12185: return((pit[ch].latch >> 8) & 0xff);
12186: }
12187: }
12188: return(0xff);
12189: }
12190:
1.1.1.8 root 12191: int pit_run(int ch, UINT32 cur_time)
1.1 root 12192: {
1.1.1.8 root 12193: if(pit[ch].expired_time != 0 && cur_time >= pit[ch].expired_time) {
1.1 root 12194: pit[ch].count = PIT_COUNT_VALUE(ch);
1.1.1.8 root 12195: pit[ch].prev_time = pit[ch].expired_time;
12196: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
12197: if(cur_time >= pit[ch].expired_time) {
12198: pit[ch].prev_time = cur_time;
12199: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 12200: }
1.1.1.8 root 12201: return(1);
1.1 root 12202: }
1.1.1.8 root 12203: return(0);
1.1 root 12204: }
12205:
12206: void pit_latch_count(int ch)
12207: {
1.1.1.8 root 12208: if(pit[ch].expired_time != 0) {
1.1.1.26 root 12209: UINT32 cur_time = timeGetTime();
1.1.1.8 root 12210: pit_run(ch, cur_time);
12211: UINT32 tmp = (pit[ch].count * (pit[ch].expired_time - cur_time)) / (pit[ch].expired_time - pit[ch].prev_time);
1.1.1.26 root 12212: UINT16 latch = (tmp != 0) ? (UINT16)tmp : 1;
12213:
12214: if(pit[ch].prev_latch == latch && pit[ch].expired_time > cur_time) {
12215: // decrement counter in 1msec period
12216: if(pit[ch].next_latch == 0) {
12217: tmp = (pit[ch].count * (pit[ch].expired_time - cur_time - 1)) / (pit[ch].expired_time - pit[ch].prev_time);
12218: pit[ch].next_latch = (tmp != 0) ? (UINT16)tmp : 1;
12219: }
12220: if(pit[ch].latch > pit[ch].next_latch) {
12221: pit[ch].latch--;
12222: }
12223: } else {
12224: pit[ch].prev_latch = pit[ch].latch = latch;
12225: pit[ch].next_latch = 0;
12226: }
1.1.1.8 root 12227: } else {
12228: pit[ch].latch = (UINT16)pit[ch].count;
1.1.1.26 root 12229: pit[ch].prev_latch = pit[ch].next_latch = 0;
1.1 root 12230: }
12231: pit[ch].count_latched = 1;
12232: if((pit[ch].ctrl_reg & 0x30) == 0x10) {
12233: // lower byte
12234: pit[ch].low_read = 1;
12235: pit[ch].high_read = 0;
12236: } else if((pit[ch].ctrl_reg & 0x30) == 0x20) {
12237: // upper byte
12238: pit[ch].low_read = 0;
12239: pit[ch].high_read = 1;
12240: } else {
12241: // lower -> upper
1.1.1.14 root 12242: pit[ch].low_read = pit[ch].high_read = 1;
1.1 root 12243: }
12244: }
12245:
1.1.1.8 root 12246: int pit_get_expired_time(int ch)
1.1 root 12247: {
1.1.1.22 root 12248: pit[ch].accum += 1024ULL * 1000ULL * (UINT64)pit[ch].count / PIT_FREQ;
12249: UINT64 val = pit[ch].accum >> 10;
12250: pit[ch].accum -= val << 10;
12251: return((val != 0) ? val : 1);
1.1.1.8 root 12252: }
12253:
1.1.1.25 root 12254: // sio
12255:
12256: void sio_init()
12257: {
1.1.1.26 root 12258: memset(sio, 0, sizeof(sio));
12259: memset(sio_mt, 0, sizeof(sio_mt));
12260:
1.1.1.25 root 12261: for(int c = 0; c < 2; c++) {
12262: sio[c].send_buffer = new FIFO(SIO_BUFFER_SIZE);
12263: sio[c].recv_buffer = new FIFO(SIO_BUFFER_SIZE);
12264:
12265: sio[c].divisor.w = 12; // 115200Hz / 9600Baud
12266: sio[c].line_ctrl = 0x03; // 8bit, stop 1bit, non parity
1.1.1.26 root 12267: sio[c].modem_ctrl = 0x03; // rts=on, dtr=on
12268: sio[c].set_rts = sio[c].set_dtr = true;
1.1.1.25 root 12269: sio[c].line_stat_buf = 0x60; // send/recv buffers are empty
12270: sio[c].irq_identify = 0x01; // no pending irq
12271:
12272: InitializeCriticalSection(&sio_mt[c].csSendData);
12273: InitializeCriticalSection(&sio_mt[c].csRecvData);
12274: InitializeCriticalSection(&sio_mt[c].csLineCtrl);
12275: InitializeCriticalSection(&sio_mt[c].csLineStat);
12276: InitializeCriticalSection(&sio_mt[c].csModemCtrl);
12277: InitializeCriticalSection(&sio_mt[c].csModemStat);
12278:
1.1.1.26 root 12279: if(sio_port_number[c] != 0) {
1.1.1.25 root 12280: sio[c].channel = c;
12281: sio_mt[c].hThread = CreateThread(NULL, 0, sio_thread, &sio[c], 0, NULL);
12282: }
12283: }
12284: }
12285:
12286: void sio_finish()
12287: {
12288: for(int c = 0; c < 2; c++) {
12289: if(sio_mt[c].hThread != NULL) {
12290: WaitForSingleObject(sio_mt[c].hThread, INFINITE);
12291: CloseHandle(sio_mt[c].hThread);
12292: }
12293: DeleteCriticalSection(&sio_mt[c].csSendData);
12294: DeleteCriticalSection(&sio_mt[c].csRecvData);
12295: DeleteCriticalSection(&sio_mt[c].csLineCtrl);
12296: DeleteCriticalSection(&sio_mt[c].csLineStat);
12297: DeleteCriticalSection(&sio_mt[c].csModemCtrl);
12298: DeleteCriticalSection(&sio_mt[c].csModemStat);
12299:
12300: sio[c].send_buffer->release();
12301: delete sio[c].send_buffer;
12302: sio[c].recv_buffer->release();
12303: delete sio[c].recv_buffer;
12304: }
12305: }
12306:
12307: void sio_write(int c, UINT32 addr, UINT8 data)
12308: {
12309: switch(addr & 7) {
12310: case 0:
12311: if(sio[c].selector & 0x80) {
12312: if(sio[c].divisor.b.l != data) {
12313: EnterCriticalSection(&sio_mt[c].csLineCtrl);
12314: sio[c].divisor.b.l = data;
12315: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
12316: }
12317: } else {
12318: EnterCriticalSection(&sio_mt[c].csSendData);
12319: sio[c].send_buffer->write(data);
12320: // transmitter holding/shift registers are not empty
12321: sio[c].line_stat_buf &= ~0x60;
12322: LeaveCriticalSection(&sio_mt[c].csSendData);
12323:
12324: if(sio[c].irq_enable & 0x02) {
12325: sio_update_irq(c);
12326: }
12327: }
12328: break;
12329: case 1:
12330: if(sio[c].selector & 0x80) {
12331: if(sio[c].divisor.b.h != data) {
12332: EnterCriticalSection(&sio_mt[c].csLineCtrl);
12333: sio[c].divisor.b.h = data;
12334: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
12335: }
12336: } else {
12337: if(sio[c].irq_enable != data) {
12338: sio[c].irq_enable = data;
12339: sio_update_irq(c);
12340: }
12341: }
12342: break;
12343: case 3:
12344: {
12345: UINT8 line_ctrl = data & 0x3f;
12346: bool set_brk = ((data & 0x40) != 0);
12347:
12348: if(sio[c].line_ctrl != line_ctrl) {
12349: EnterCriticalSection(&sio_mt[c].csLineCtrl);
12350: sio[c].line_ctrl = line_ctrl;
12351: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
12352: }
12353: if(sio[c].set_brk != set_brk) {
12354: EnterCriticalSection(&sio_mt[c].csModemCtrl);
12355: sio[c].set_brk = set_brk;
12356: LeaveCriticalSection(&sio_mt[c].csModemCtrl);
12357: }
12358: }
12359: sio[c].selector = data;
12360: break;
12361: case 4:
12362: {
12363: bool set_dtr = ((data & 0x01) != 0);
12364: bool set_rts = ((data & 0x02) != 0);
12365:
12366: if(sio[c].set_dtr != set_dtr || sio[c].set_rts != set_rts) {
1.1.1.26 root 12367: // EnterCriticalSection(&sio_mt[c].csModemCtrl);
1.1.1.25 root 12368: sio[c].set_dtr = set_dtr;
12369: sio[c].set_rts = set_rts;
1.1.1.26 root 12370: // LeaveCriticalSection(&sio_mt[c].csModemCtrl);
12371:
12372: bool state_changed = false;
12373:
12374: EnterCriticalSection(&sio_mt[c].csModemStat);
12375: if(set_dtr) {
12376: sio[c].modem_stat |= 0x20; // dsr on
12377: } else {
12378: sio[c].modem_stat &= ~0x20; // dsr off
12379: }
12380: if(set_rts) {
12381: sio[c].modem_stat |= 0x10; // cts on
12382: } else {
12383: sio[c].modem_stat &= ~0x10; // cts off
12384: }
12385: if((sio[c].prev_modem_stat & 0x20) != (sio[c].modem_stat & 0x20)) {
12386: if(!(sio[c].modem_stat & 0x02)) {
12387: if(sio[c].irq_enable & 0x08) {
12388: state_changed = true;
12389: }
12390: sio[c].modem_stat |= 0x02;
12391: }
12392: }
12393: if((sio[c].prev_modem_stat & 0x10) != (sio[c].modem_stat & 0x10)) {
12394: if(!(sio[c].modem_stat & 0x01)) {
12395: if(sio[c].irq_enable & 0x08) {
12396: state_changed = true;
12397: }
12398: sio[c].modem_stat |= 0x01;
12399: }
12400: }
12401: LeaveCriticalSection(&sio_mt[c].csModemStat);
12402:
12403: if(state_changed) {
12404: sio_update_irq(c);
12405: }
1.1.1.25 root 12406: }
12407: }
12408: sio[c].modem_ctrl = data;
12409: break;
12410: case 7:
12411: sio[c].scratch = data;
12412: break;
12413: }
12414: }
12415:
12416: UINT8 sio_read(int c, UINT32 addr)
12417: {
12418: switch(addr & 7) {
12419: case 0:
12420: if(sio[c].selector & 0x80) {
12421: return(sio[c].divisor.b.l);
12422: } else {
12423: EnterCriticalSection(&sio_mt[c].csRecvData);
12424: UINT8 data = sio[c].recv_buffer->read();
12425: // data is not ready
12426: sio[c].line_stat_buf &= ~0x01;
12427: LeaveCriticalSection(&sio_mt[c].csRecvData);
12428:
12429: if(sio[c].irq_enable & 0x01) {
12430: sio_update_irq(c);
12431: }
12432: return(data);
12433: }
12434: case 1:
12435: if(sio[c].selector & 0x80) {
12436: return(sio[c].divisor.b.h);
12437: } else {
12438: return(sio[c].irq_enable);
12439: }
12440: case 2:
12441: return(sio[c].irq_identify);
12442: case 3:
12443: return(sio[c].selector);
12444: case 4:
12445: return(sio[c].modem_ctrl);
12446: case 5:
12447: {
12448: EnterCriticalSection(&sio_mt[c].csLineStat);
12449: UINT8 val = sio[c].line_stat_err | sio[c].line_stat_buf;
12450: sio[c].line_stat_err = 0x00;
12451: LeaveCriticalSection(&sio_mt[c].csLineStat);
12452:
12453: bool state_changed = false;
12454:
12455: if((sio[c].line_stat_buf & 0x60) == 0x00) {
12456: EnterCriticalSection(&sio_mt[c].csSendData);
12457: if(!sio[c].send_buffer->full()) {
12458: // transmitter holding register will be empty first
12459: if(sio[c].irq_enable & 0x02) {
12460: state_changed = true;
12461: }
12462: sio[c].line_stat_buf |= 0x20;
12463: }
12464: LeaveCriticalSection(&sio_mt[c].csSendData);
12465: } else if((sio[c].line_stat_buf & 0x60) == 0x20) {
12466: // transmitter shift register will be empty later
12467: sio[c].line_stat_buf |= 0x40;
12468: }
12469: if(!(sio[c].line_stat_buf & 0x01)) {
12470: EnterCriticalSection(&sio_mt[c].csRecvData);
12471: if(!sio[c].recv_buffer->empty()) {
12472: // data is ready
12473: if(sio[c].irq_enable & 0x01) {
12474: state_changed = true;
12475: }
12476: sio[c].line_stat_buf |= 0x01;
12477: }
12478: LeaveCriticalSection(&sio_mt[c].csRecvData);
12479: }
12480: if(state_changed) {
12481: sio_update_irq(c);
12482: }
12483: return(val);
12484: }
12485: case 6:
12486: {
12487: EnterCriticalSection(&sio_mt[c].csModemStat);
12488: UINT8 val = sio[c].modem_stat;
12489: sio[c].modem_stat &= 0xf0;
12490: sio[c].prev_modem_stat = sio[c].modem_stat;
12491: LeaveCriticalSection(&sio_mt[c].csModemStat);
12492:
12493: if(sio[c].modem_ctrl & 0x10) {
12494: // loop-back
12495: val &= 0x0f;
12496: val |= (sio[c].modem_ctrl & 0x0c) << 4;
12497: val |= (sio[c].modem_ctrl & 0x01) << 5;
12498: val |= (sio[c].modem_ctrl & 0x02) << 3;
12499: }
12500: return(val);
12501: }
12502: case 7:
12503: return(sio[c].scratch);
12504: }
12505: return(0xff);
12506: }
12507:
12508: void sio_update(int c)
12509: {
12510: if((sio[c].line_stat_buf & 0x60) == 0x00) {
12511: EnterCriticalSection(&sio_mt[c].csSendData);
12512: if(!sio[c].send_buffer->full()) {
12513: // transmitter holding/shift registers will be empty
12514: sio[c].line_stat_buf |= 0x60;
12515: }
12516: LeaveCriticalSection(&sio_mt[c].csSendData);
12517: } else if((sio[c].line_stat_buf & 0x60) == 0x20) {
12518: // transmitter shift register will be empty
12519: sio[c].line_stat_buf |= 0x40;
12520: }
12521: if(!(sio[c].line_stat_buf & 0x01)) {
12522: EnterCriticalSection(&sio_mt[c].csRecvData);
12523: if(!sio[c].recv_buffer->empty()) {
12524: // data is ready
12525: sio[c].line_stat_buf |= 0x01;
12526: }
12527: LeaveCriticalSection(&sio_mt[c].csRecvData);
12528: }
12529: sio_update_irq(c);
12530: }
12531:
12532: void sio_update_irq(int c)
12533: {
12534: int level = -1;
12535:
12536: if(sio[c].irq_enable & 0x08) {
12537: EnterCriticalSection(&sio_mt[c].csModemStat);
12538: if((sio[c].modem_stat & 0x0f) != 0) {
12539: level = 0;
12540: }
12541: EnterCriticalSection(&sio_mt[c].csModemStat);
12542: }
12543: if(sio[c].irq_enable & 0x02) {
12544: if(sio[c].line_stat_buf & 0x20) {
12545: level = 1;
12546: }
12547: }
12548: if(sio[c].irq_enable & 0x01) {
12549: if(sio[c].line_stat_buf & 0x01) {
12550: level = 2;
12551: }
12552: }
12553: if(sio[c].irq_enable & 0x04) {
12554: EnterCriticalSection(&sio_mt[c].csLineStat);
12555: if(sio[c].line_stat_err != 0) {
12556: level = 3;
12557: }
12558: LeaveCriticalSection(&sio_mt[c].csLineStat);
12559: }
12560: if(level != -1) {
12561: sio[c].irq_identify = level << 1;
12562: pic_req(0, (c == 0) ? 4 : 3, 1);
12563: } else {
12564: sio[c].irq_identify = 1;
12565: pic_req(0, (c == 0) ? 4 : 3, 0);
12566: }
12567: }
12568:
12569: DWORD WINAPI sio_thread(void *lpx)
12570: {
12571: volatile sio_t *p = (sio_t *)lpx;
12572: sio_mt_t *q = &sio_mt[p->channel];
12573:
12574: char name[] = "COM1";
1.1.1.26 root 12575: name[3] = '0' + sio_port_number[p->channel];
12576: HANDLE hComm = NULL;
12577: COMMPROP commProp;
12578: DCB dcb;
12579: DWORD dwSettableBaud = 0xffb; // 75, 110, 150, 300, 600, 1200, 1800, 2400, 4800, 7200, and 9600bps
12580: BYTE bytBuffer[SIO_BUFFER_SIZE];
12581:
12582: if((hComm = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE) {
12583: if(GetCommProperties(hComm, &commProp)) {
12584: dwSettableBaud = commProp.dwSettableBaud;
12585: }
1.1.1.25 root 12586: EscapeCommFunction(hComm, CLRBREAK);
1.1.1.26 root 12587: // EscapeCommFunction(hComm, SETRTS);
12588: // EscapeCommFunction(hComm, SETDTR);
1.1.1.25 root 12589:
12590: while(!m_halted) {
12591: // setup comm port
12592: bool comm_state_changed = false;
12593:
12594: EnterCriticalSection(&q->csLineCtrl);
12595: if((p->prev_divisor != p->divisor.w || p->prev_line_ctrl != p->line_ctrl) && p->divisor.w != 0) {
12596: p->prev_divisor = p->divisor.w;
12597: p->prev_line_ctrl = p->line_ctrl;
12598: comm_state_changed = true;
12599: }
12600: LeaveCriticalSection(&q->csLineCtrl);
12601:
12602: if(comm_state_changed) {
1.1.1.26 root 12603: if(GetCommState(hComm, &dcb)) {
12604: // dcb.BaudRate = min(9600, 115200 / p->prev_divisor);
12605: DWORD baud = 115200 / p->prev_divisor;
12606: dcb.BaudRate = 9600; // default
12607:
12608: if((dwSettableBaud & BAUD_075 ) && baud >= 75 ) dcb.BaudRate = 75;
12609: if((dwSettableBaud & BAUD_110 ) && baud >= 110 ) dcb.BaudRate = 110;
12610: // 134.5bps is not supported ???
12611: // if((dwSettableBaud & BAUD_134_5) && baud >= 134.5) dcb.BaudRate = 134.5;
12612: if((dwSettableBaud & BAUD_150 ) && baud >= 150 ) dcb.BaudRate = 150;
12613: if((dwSettableBaud & BAUD_300 ) && baud >= 300 ) dcb.BaudRate = 300;
12614: if((dwSettableBaud & BAUD_600 ) && baud >= 600 ) dcb.BaudRate = 600;
12615: if((dwSettableBaud & BAUD_1200 ) && baud >= 1200 ) dcb.BaudRate = 1200;
12616: if((dwSettableBaud & BAUD_1800 ) && baud >= 1800 ) dcb.BaudRate = 1800;
12617: if((dwSettableBaud & BAUD_2400 ) && baud >= 2400 ) dcb.BaudRate = 2400;
12618: if((dwSettableBaud & BAUD_4800 ) && baud >= 4800 ) dcb.BaudRate = 4800;
12619: if((dwSettableBaud & BAUD_7200 ) && baud >= 7200 ) dcb.BaudRate = 7200;
12620: if((dwSettableBaud & BAUD_9600 ) && baud >= 9600 ) dcb.BaudRate = 9600;
12621: // if((dwSettableBaud & BAUD_14400) && baud >= 14400) dcb.BaudRate = 14400;
12622: // if((dwSettableBaud & BAUD_19200) && baud >= 19200) dcb.BaudRate = 19200;
12623: // if((dwSettableBaud & BAUD_38400) && baud >= 38400) dcb.BaudRate = 38400;
12624:
12625: switch(p->prev_line_ctrl & 0x03) {
12626: case 0x00: dcb.ByteSize = 5; break;
12627: case 0x01: dcb.ByteSize = 6; break;
12628: case 0x02: dcb.ByteSize = 7; break;
12629: case 0x03: dcb.ByteSize = 8; break;
12630: }
12631: switch(p->prev_line_ctrl & 0x04) {
12632: case 0x00: dcb.StopBits = ONESTOPBIT; break;
12633: case 0x04: dcb.StopBits = (dcb.ByteSize == 5) ? ONE5STOPBITS : TWOSTOPBITS; break;
12634: }
12635: switch(p->prev_line_ctrl & 0x38) {
12636: case 0x08: dcb.Parity = ODDPARITY; break;
12637: case 0x18: dcb.Parity = EVENPARITY; break;
12638: case 0x28: dcb.Parity = MARKPARITY; break;
12639: case 0x38: dcb.Parity = SPACEPARITY; break;
12640: default: dcb.Parity = NOPARITY; break;
12641: }
12642: dcb.fBinary = TRUE;
12643: dcb.fParity = (dcb.Parity != NOPARITY);
12644: dcb.fOutxCtsFlow = dcb.fOutxDsrFlow = TRUE;
12645: dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
12646: dcb.fDsrSensitivity = FALSE;//TRUE;
12647: dcb.fTXContinueOnXoff = TRUE;
12648: dcb.fOutX = dcb.fInX = FALSE;
12649: dcb.fErrorChar = FALSE;
12650: dcb.fNull = FALSE;
12651: dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
12652: dcb.fAbortOnError = FALSE;
12653:
12654: SetCommState(hComm, &dcb);
1.1.1.25 root 12655: }
12656:
12657: // check again to apply all comm state changes
12658: Sleep(10);
12659: continue;
12660: }
12661:
12662: // set comm pins
12663: bool change_brk = false;
1.1.1.26 root 12664: // bool change_rts = false;
12665: // bool change_dtr = false;
1.1.1.25 root 12666:
12667: EnterCriticalSection(&q->csModemCtrl);
12668: if(p->prev_set_brk != p->set_brk) {
12669: p->prev_set_brk = p->set_brk;
12670: change_brk = true;
12671: }
1.1.1.26 root 12672: // if(p->prev_set_rts != p->set_rts) {
12673: // p->prev_set_rts = p->set_rts;
12674: // change_rts = true;
12675: // }
12676: // if(p->prev_set_dtr != p->set_dtr) {
12677: // p->prev_set_dtr = p->set_dtr;
12678: // change_dtr = true;
12679: // }
1.1.1.25 root 12680: LeaveCriticalSection(&q->csModemCtrl);
12681:
12682: if(change_brk) {
1.1.1.26 root 12683: static UINT32 clear_time = 0;
12684: if(p->prev_set_brk) {
12685: EscapeCommFunction(hComm, SETBREAK);
12686: clear_time = timeGetTime() + 200;
12687: } else {
12688: // keep break for at least 200msec
12689: UINT32 cur_time = timeGetTime();
12690: if(clear_time > cur_time) {
12691: Sleep(clear_time - cur_time);
12692: }
12693: EscapeCommFunction(hComm, CLRBREAK);
12694: }
1.1.1.25 root 12695: }
1.1.1.26 root 12696: // if(change_rts) {
12697: // if(p->prev_set_rts) {
12698: // EscapeCommFunction(hComm, SETRTS);
12699: // } else {
12700: // EscapeCommFunction(hComm, CLRRTS);
12701: // }
12702: // }
12703: // if(change_dtr) {
12704: // if(p->prev_set_dtr) {
12705: // EscapeCommFunction(hComm, SETDTR);
12706: // } else {
12707: // EscapeCommFunction(hComm, CLRDTR);
12708: // }
12709: // }
1.1.1.25 root 12710:
12711: // get comm pins
12712: DWORD dwModemStat = 0;
12713:
12714: if(GetCommModemStatus(hComm, &dwModemStat)) {
12715: EnterCriticalSection(&q->csModemStat);
12716: if(dwModemStat & MS_RLSD_ON) {
12717: p->modem_stat |= 0x80;
12718: } else {
12719: p->modem_stat &= ~0x80;
12720: }
12721: if(dwModemStat & MS_RING_ON) {
12722: p->modem_stat |= 0x40;
12723: } else {
12724: p->modem_stat &= ~0x40;
12725: }
1.1.1.26 root 12726: // if(dwModemStat & MS_DSR_ON) {
12727: // p->modem_stat |= 0x20;
12728: // } else {
12729: // p->modem_stat &= ~0x20;
12730: // }
12731: // if(dwModemStat & MS_CTS_ON) {
12732: // p->modem_stat |= 0x10;
12733: // } else {
12734: // p->modem_stat &= ~0x10;
12735: // }
1.1.1.25 root 12736: if((p->prev_modem_stat & 0x80) != (p->modem_stat & 0x80)) {
12737: p->modem_stat |= 0x08;
12738: }
12739: if((p->prev_modem_stat & 0x40) && !(p->modem_stat & 0x40)) {
12740: p->modem_stat |= 0x04;
12741: }
1.1.1.26 root 12742: // if((p->prev_modem_stat & 0x20) != (p->modem_stat & 0x20)) {
12743: // p->modem_stat |= 0x02;
12744: // }
12745: // if((p->prev_modem_stat & 0x10) != (p->modem_stat & 0x10)) {
12746: // p->modem_stat |= 0x01;
12747: // }
1.1.1.25 root 12748: LeaveCriticalSection(&q->csModemStat);
12749: }
12750:
12751: // send data
12752: DWORD dwSend = 0;
12753:
12754: EnterCriticalSection(&q->csSendData);
12755: while(!p->send_buffer->empty()) {
12756: bytBuffer[dwSend++] = p->send_buffer->read();
12757: }
12758: LeaveCriticalSection(&q->csSendData);
12759:
12760: if(dwSend != 0) {
12761: DWORD dwWritten = 0;
12762: WriteFile(hComm, bytBuffer, dwSend, &dwWritten, NULL);
12763: }
12764:
12765: // get line status and recv data
12766: DWORD dwLineStat = 0;
12767: COMSTAT comStat;
12768:
12769: if(ClearCommError(hComm, &dwLineStat, &comStat)) {
12770: EnterCriticalSection(&q->csLineStat);
12771: if(dwLineStat & CE_BREAK) {
12772: p->line_stat_err |= 0x10;
12773: }
12774: if(dwLineStat & CE_FRAME) {
12775: p->line_stat_err |= 0x08;
12776: }
12777: if(dwLineStat & CE_RXPARITY) {
12778: p->line_stat_err |= 0x04;
12779: }
12780: if(dwLineStat & CE_OVERRUN) {
12781: p->line_stat_err |= 0x02;
12782: }
12783: LeaveCriticalSection(&q->csLineStat);
12784:
12785: if(comStat.cbInQue != 0) {
12786: EnterCriticalSection(&q->csRecvData);
12787: DWORD dwRecv = min(comStat.cbInQue, p->recv_buffer->remain());
12788: LeaveCriticalSection(&q->csRecvData);
12789:
12790: if(dwRecv != 0) {
12791: DWORD dwRead = 0;
12792: if(ReadFile(hComm, bytBuffer, dwRecv, &dwRead, NULL) && dwRead != 0) {
12793: EnterCriticalSection(&q->csRecvData);
12794: for(int i = 0; i < dwRead; i++) {
12795: p->recv_buffer->write(bytBuffer[i]);
12796: }
12797: LeaveCriticalSection(&q->csRecvData);
12798: }
12799: }
12800: }
12801: }
12802: Sleep(10);
12803: }
12804: CloseHandle(hComm);
12805: }
12806: return 0;
12807: }
12808:
1.1.1.8 root 12809: // cmos
12810:
12811: void cmos_init()
12812: {
12813: memset(cmos, 0, sizeof(cmos));
12814: cmos_addr = 0;
1.1 root 12815:
1.1.1.8 root 12816: // from DOSBox
12817: cmos_write(0x0a, 0x26);
12818: cmos_write(0x0b, 0x02);
12819: cmos_write(0x0d, 0x80);
1.1 root 12820: }
12821:
1.1.1.8 root 12822: void cmos_write(int addr, UINT8 val)
1.1 root 12823: {
1.1.1.8 root 12824: cmos[addr & 0x7f] = val;
12825: }
12826:
12827: #define CMOS_GET_TIME() { \
12828: UINT32 cur_sec = timeGetTime() / 1000 ; \
12829: if(prev_sec != cur_sec) { \
12830: GetLocalTime(&time); \
12831: prev_sec = cur_sec; \
12832: } \
1.1 root 12833: }
1.1.1.8 root 12834: #define CMOS_BCD(v) ((cmos[0x0b] & 4) ? (v) : to_bcd(v))
1.1 root 12835:
1.1.1.8 root 12836: UINT8 cmos_read(int addr)
1.1 root 12837: {
1.1.1.8 root 12838: static SYSTEMTIME time;
12839: static UINT32 prev_sec = 0;
1.1 root 12840:
1.1.1.8 root 12841: switch(addr & 0x7f) {
12842: case 0x00: CMOS_GET_TIME(); return(CMOS_BCD(time.wSecond));
12843: case 0x02: CMOS_GET_TIME(); return(CMOS_BCD(time.wMinute));
12844: case 0x04: CMOS_GET_TIME(); return(CMOS_BCD(time.wHour));
12845: case 0x06: CMOS_GET_TIME(); return(time.wDayOfWeek + 1);
12846: case 0x07: CMOS_GET_TIME(); return(CMOS_BCD(time.wDay));
12847: case 0x08: CMOS_GET_TIME(); return(CMOS_BCD(time.wMonth));
12848: case 0x09: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear));
12849: // case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 2 ? 0x80 : 0)); // 2msec
12850: case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 20 ? 0x80 : 0)); // precision of timeGetTime() may not be 1msec
12851: case 0x15: return((MEMORY_END >> 10) & 0xff);
12852: case 0x16: return((MEMORY_END >> 18) & 0xff);
12853: case 0x17: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
12854: case 0x18: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
12855: case 0x30: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
12856: case 0x31: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
12857: case 0x32: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear / 100));
1.1 root 12858: }
1.1.1.8 root 12859: return(cmos[addr & 0x7f]);
1.1 root 12860: }
12861:
1.1.1.7 root 12862: // kbd (a20)
12863:
12864: void kbd_init()
12865: {
1.1.1.8 root 12866: kbd_data = kbd_command = 0;
1.1.1.7 root 12867: kbd_status = 0x18;
12868: }
12869:
12870: UINT8 kbd_read_data()
12871: {
1.1.1.8 root 12872: kbd_status &= ~1;
1.1.1.7 root 12873: return(kbd_data);
12874: }
12875:
12876: void kbd_write_data(UINT8 val)
12877: {
12878: switch(kbd_command) {
12879: case 0xd1:
12880: i386_set_a20_line((val >> 1) & 1);
12881: break;
12882: }
12883: kbd_command = 0;
1.1.1.8 root 12884: kbd_status &= ~8;
1.1.1.7 root 12885: }
12886:
12887: UINT8 kbd_read_status()
12888: {
12889: return(kbd_status);
12890: }
12891:
12892: void kbd_write_command(UINT8 val)
12893: {
12894: switch(val) {
12895: case 0xd0:
12896: kbd_data = ((m_a20_mask >> 19) & 2) | 1;
1.1.1.8 root 12897: kbd_status |= 1;
1.1.1.7 root 12898: break;
12899: case 0xdd:
12900: i386_set_a20_line(0);
12901: break;
12902: case 0xdf:
12903: i386_set_a20_line(1);
12904: break;
1.1.1.26 root 12905: case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
12906: case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
1.1.1.7 root 12907: if(!(val & 1)) {
1.1.1.8 root 12908: if((cmos[0x0f] & 0x7f) == 5) {
1.1.1.7 root 12909: // reset pic
12910: pic_init();
12911: pic[0].irr = pic[1].irr = 0x00;
12912: pic[0].imr = pic[1].imr = 0xff;
12913: }
12914: CPU_RESET_CALL(CPU_MODEL);
12915: i386_jmp_far(0x40, 0x67);
12916: }
12917: i386_set_a20_line((val >> 1) & 1);
12918: break;
12919: }
12920: kbd_command = val;
1.1.1.8 root 12921: kbd_status |= 8;
1.1.1.7 root 12922: }
12923:
1.1.1.9 root 12924: // vga
12925:
12926: UINT8 vga_read_status()
12927: {
12928: // 60hz
12929: static const int period[3] = {16, 17, 17};
12930: static int index = 0;
12931: UINT32 time = timeGetTime() % period[index];
12932:
12933: index = (index + 1) % 3;
1.1.1.14 root 12934: return((time < 4 ? 0x08 : 0) | (time == 0 ? 0 : 0x01));
1.1.1.9 root 12935: }
12936:
1.1 root 12937: // i/o bus
12938:
1.1.1.25 root 12939: #ifdef ENABLE_DEBUG_IOPORT
12940: UINT8 read_io_byte_debug(offs_t addr);
12941:
12942: UINT8 read_io_byte(offs_t addr)
12943: {
12944: UINT8 val = read_io_byte_debug(addr);
12945: if(fdebug != NULL) {
12946: fprintf(fdebug, "inb %04X, %02X\n", addr, val);
12947: }
12948: return(val);
12949: }
12950:
12951: UINT8 read_io_byte_debug(offs_t addr)
12952: #else
1.1 root 12953: UINT8 read_io_byte(offs_t addr)
1.1.1.25 root 12954: #endif
1.1 root 12955: {
12956: switch(addr) {
1.1.1.25 root 12957: case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
12958: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
12959: return(dma_read(0, addr));
12960: case 0x20: case 0x21:
1.1 root 12961: return(pic_read(0, addr));
1.1.1.25 root 12962: case 0x40: case 0x41: case 0x42: case 0x43:
1.1 root 12963: return(pit_read(addr & 0x03));
1.1.1.7 root 12964: case 0x60:
12965: return(kbd_read_data());
1.1.1.9 root 12966: case 0x61:
12967: return(system_port);
1.1.1.7 root 12968: case 0x64:
12969: return(kbd_read_status());
1.1 root 12970: case 0x71:
1.1.1.8 root 12971: return(cmos_read(cmos_addr));
1.1.1.25 root 12972: case 0x81:
12973: return(dma_page_read(0, 2));
12974: case 0x82:
12975: return(dma_page_read(0, 3));
12976: case 0x83:
12977: return(dma_page_read(0, 1));
12978: case 0x87:
12979: return(dma_page_read(0, 0));
12980: case 0x89:
12981: return(dma_page_read(1, 2));
12982: case 0x8a:
12983: return(dma_page_read(1, 3));
12984: case 0x8b:
12985: return(dma_page_read(1, 1));
12986: case 0x8f:
12987: return(dma_page_read(1, 0));
1.1 root 12988: case 0x92:
1.1.1.3 root 12989: return((m_a20_mask >> 19) & 2);
1.1.1.25 root 12990: case 0xa0: case 0xa1:
1.1 root 12991: return(pic_read(1, addr));
1.1.1.25 root 12992: case 0xc0: case 0xc2: case 0xc4: case 0xc6: case 0xc8: case 0xca: case 0xcc: case 0xce:
12993: case 0xd0: case 0xd2: case 0xd4: case 0xd6: case 0xd8: case 0xda: case 0xdc: case 0xde:
1.1.1.26 root 12994: return(dma_read(1, (addr - 0xc0) >> 1));
12995: // case 0x278: case 0x279: case 0x27a:
12996: // return(pio_read(1, addr));
1.1.1.25 root 12997: case 0x2f8: case 0x2f9: case 0x2fa: case 0x2fb: case 0x2fc: case 0x2fd: case 0x2fe: case 0x2ff:
12998: return(sio_read(1, addr));
12999: case 0x378: case 0x379: case 0x37a:
13000: return(pio_read(0, addr));
13001: case 0x3ba: case 0x3da:
1.1.1.9 root 13002: return(vga_read_status());
1.1.1.25 root 13003: case 0x3f8: case 0x3f9: case 0x3fa: case 0x3fb: case 0x3fc: case 0x3fd: case 0x3fe: case 0x3ff:
13004: return(sio_read(0, addr));
1.1 root 13005: default:
13006: // error("inb %4x\n", addr);
13007: break;
13008: }
13009: return(0xff);
13010: }
13011:
13012: UINT16 read_io_word(offs_t addr)
13013: {
13014: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8));
13015: }
13016:
13017: UINT32 read_io_dword(offs_t addr)
13018: {
13019: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8) | (read_io_byte(addr + 2) << 16) | (read_io_byte(addr + 3) << 24));
13020: }
13021:
13022: void write_io_byte(offs_t addr, UINT8 val)
13023: {
1.1.1.25 root 13024: #ifdef ENABLE_DEBUG_IOPORT
13025: if(fdebug != NULL) {
13026: fprintf(fdebug, "outb %04X, %02X\n", addr, val);
13027: }
13028: #endif
1.1 root 13029: switch(addr) {
1.1.1.25 root 13030: case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
13031: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
13032: dma_write(0, addr, val);
13033: break;
13034: case 0x20: case 0x21:
1.1 root 13035: pic_write(0, addr, val);
13036: break;
1.1.1.25 root 13037: case 0x40: case 0x41: case 0x42: case 0x43:
1.1 root 13038: pit_write(addr & 0x03, val);
13039: break;
1.1.1.7 root 13040: case 0x60:
13041: kbd_write_data(val);
13042: break;
1.1.1.9 root 13043: case 0x61:
13044: if((system_port & 3) != 3 && (val & 3) == 3) {
13045: // beep on
13046: // MessageBeep(-1);
13047: } else if((system_port & 3) == 3 && (val & 3) != 3) {
13048: // beep off
13049: }
13050: system_port = val;
13051: break;
1.1 root 13052: case 0x64:
1.1.1.7 root 13053: kbd_write_command(val);
1.1 root 13054: break;
13055: case 0x70:
13056: cmos_addr = val;
13057: break;
13058: case 0x71:
1.1.1.8 root 13059: cmos_write(cmos_addr, val);
1.1 root 13060: break;
1.1.1.25 root 13061: case 0x81:
13062: dma_page_write(0, 2, val);
13063: case 0x82:
13064: dma_page_write(0, 3, val);
13065: case 0x83:
13066: dma_page_write(0, 1, val);
13067: case 0x87:
13068: dma_page_write(0, 0, val);
13069: case 0x89:
13070: dma_page_write(1, 2, val);
13071: case 0x8a:
13072: dma_page_write(1, 3, val);
13073: case 0x8b:
13074: dma_page_write(1, 1, val);
13075: case 0x8f:
13076: dma_page_write(1, 0, val);
1.1 root 13077: case 0x92:
1.1.1.7 root 13078: i386_set_a20_line((val >> 1) & 1);
1.1 root 13079: break;
1.1.1.25 root 13080: case 0xa0: case 0xa1:
1.1 root 13081: pic_write(1, addr, val);
13082: break;
1.1.1.25 root 13083: case 0xc0: case 0xc2: case 0xc4: case 0xc6: case 0xc8: case 0xca: case 0xcc: case 0xce:
13084: case 0xd0: case 0xd2: case 0xd4: case 0xd6: case 0xd8: case 0xda: case 0xdc: case 0xde:
1.1.1.26 root 13085: dma_write(1, (addr - 0xc0) >> 1, val);
1.1.1.25 root 13086: break;
1.1.1.26 root 13087: // case 0x278: case 0x279: case 0x27a:
13088: // pio_write(1, addr, val);
13089: // break;
1.1.1.25 root 13090: case 0x2f8: case 0x2f9: case 0x2fa: case 0x2fb: case 0x2fc: case 0x2fd: case 0x2fe: case 0x2ff:
13091: sio_write(1, addr, val);
13092: break;
13093: case 0x378: case 0x379: case 0x37a:
13094: pio_write(0, addr, val);
13095: break;
13096: case 0x3f8: case 0x3f9: case 0x3fa: case 0x3fb: case 0x3fc: case 0x3fd: case 0x3fe: case 0x3ff:
13097: sio_write(0, addr, val);
13098: break;
1.1 root 13099: default:
13100: // error("outb %4x,%2x\n", addr, val);
13101: break;
13102: }
13103: }
13104:
13105: void write_io_word(offs_t addr, UINT16 val)
13106: {
13107: write_io_byte(addr + 0, (val >> 0) & 0xff);
13108: write_io_byte(addr + 1, (val >> 8) & 0xff);
13109: }
13110:
13111: void write_io_dword(offs_t addr, UINT32 val)
13112: {
13113: write_io_byte(addr + 0, (val >> 0) & 0xff);
13114: write_io_byte(addr + 1, (val >> 8) & 0xff);
13115: write_io_byte(addr + 2, (val >> 16) & 0xff);
13116: write_io_byte(addr + 3, (val >> 24) & 0xff);
13117: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.