|
|
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 root 783: int main(int argc, char *argv[], char *envp[])
784: {
1.1.1.9 root 785: int arg_offset = 0;
786: int standard_env = 0;
1.1.1.14 root 787: int buf_width = 0, buf_height = 0;
1.1.1.15 root 788: BOOL bSuccess, bChangeScreenSize = FALSE;
1.1 root 789:
1.1.1.9 root 790: for(int i = 1; i < argc; i++) {
1.1.1.25 root 791: if(_strnicmp(argv[i], "-b", 2) == 0) {
792: stay_busy = true;
793: arg_offset++;
794: } else if(_strnicmp(argv[i], "-d", 2) == 0) {
795: no_windows = true;
796: arg_offset++;
797: } else if(_strnicmp(argv[i], "-e", 2) == 0) {
1.1.1.9 root 798: standard_env = 1;
799: arg_offset++;
1.1.1.14 root 800: } else if(_strnicmp(argv[i], "-i", 2) == 0) {
801: ignore_illegal_insn = true;
802: arg_offset++;
803: } else if(_strnicmp(argv[i], "-m", 2) == 0) {
804: limit_max_memory = true;
805: arg_offset++;
806: } else if(_strnicmp(argv[i], "-n", 2) == 0) {
1.1.1.17 root 807: if(sscanf(argv[1] + 2, "%d,%d", &buf_height, &buf_width) != 2) {
808: buf_width = buf_height = 0;
809: }
810: if(buf_width <= 0 || buf_width > 0x7fff) {
811: buf_width = 80;
812: }
813: if(buf_height <= 0 || buf_height > 0x7fff) {
814: buf_height = 25;
815: }
1.1.1.14 root 816: arg_offset++;
1.1.1.25 root 817: } else if(_strnicmp(argv[i], "-s", 2) == 0) {
818: if(strlen(argv[i]) > 2) {
819: char *p1 = &argv[i][2], *p2;
820: if((p2 = strchr(p1, ',')) != NULL) {
1.1.1.26! root 821: sio_port_number[1] = atoi(p2 + 1);
1.1.1.25 root 822: }
1.1.1.26! root 823: sio_port_number[0] = atoi(p1);
1.1.1.25 root 824: }
1.1.1.26! root 825: if(sio_port_number[0] == 0 || sio_port_number[1] == 0) {
1.1.1.25 root 826: SP_DEVINFO_DATA DeviceInfoData = {sizeof(SP_DEVINFO_DATA)};
827: HDEVINFO hDevInfo = 0;
828: HKEY hKey = 0;
829: if((hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_COMPORT, NULL, NULL, (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE))) != 0) {
830: for(int i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData); i++) {
831: if((hKey = SetupDiOpenDevRegKey(hDevInfo, &DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE)) != INVALID_HANDLE_VALUE) {
832: char chData[256];
833: DWORD dwType = 0;
834: DWORD dwSize = sizeof(chData);
835: int port_number = 0;
836:
837: if(RegQueryValueEx(hKey, _T("PortName"), NULL, &dwType, (BYTE *)chData, &dwSize) == ERROR_SUCCESS) {
838: if(_strnicmp(chData, "COM", 3) == 0) {
839: port_number = atoi(chData + 3);
840: }
841: }
842: RegCloseKey(hKey);
843:
1.1.1.26! root 844: if(sio_port_number[0] == port_number || sio_port_number[1] == port_number) {
1.1.1.25 root 845: continue;
846: }
1.1.1.26! root 847: if(sio_port_number[0] == 0) {
! 848: sio_port_number[0] = port_number;
! 849: } else if(sio_port_number[1] == 0) {
! 850: sio_port_number[1] = port_number;
1.1.1.25 root 851: }
1.1.1.26! root 852: if(sio_port_number[0] != 0 && sio_port_number[1] != 0) {
1.1.1.25 root 853: break;
854: }
855: }
856: }
857: }
858: }
859: arg_offset++;
1.1.1.9 root 860: } else if(_strnicmp(argv[i], "-v", 2) == 0) {
1.1.1.17 root 861: 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 862: major_version = argv[i][2] - '0';
1.1.1.17 root 863: minor_version = (argv[i][4] - '0') * 10 + (argv[i][5] ? (argv[i][5] - '0') : 0);
1.1.1.9 root 864: }
865: arg_offset++;
1.1.1.25 root 866: } else if(_strnicmp(argv[i], "-x", 2) == 0) {
867: UMB_TOP = EMS_TOP + EMS_SIZE;
868: support_ems = true;
869: #ifdef SUPPORT_XMS
870: support_xms = true;
871: #endif
872: arg_offset++;
1.1.1.9 root 873: } else {
874: break;
875: }
876: }
877:
878: if(argc < 2 + arg_offset) {
1.1 root 879: #ifdef _WIN64
1.1.1.14 root 880: fprintf(stderr, "MS-DOS Player (" CPU_MODEL_NAME(CPU_MODEL) ") for Win32-x64 console\n\n");
1.1 root 881: #else
1.1.1.14 root 882: fprintf(stderr, "MS-DOS Player (" CPU_MODEL_NAME(CPU_MODEL) ") for Win32 console\n\n");
1.1 root 883: #endif
1.1.1.25 root 884: fprintf(stderr,
885: "Usage: MSDOS [-b] [-d] [-e] [-i] [-m] [-n[L[,C]]] [-s[P1[,P2]]] [-vX.XX] [-x]\n"
886: " (command file) [options]\n"
887: "\n"
888: "\t-b\tstay busy during keyboard polling\n"
889: "\t-d\tpretend running under straight DOS, not Windows\n"
890: "\t-e\tuse a reduced environment block\n"
891: "\t-i\tignore invalid instructions\n"
892: "\t-m\trestrict free memory to 0x7FFF paragraphs\n"
893: "\t-n\tcreate a new buffer (25 lines, 80 columns by default)\n"
894: "\t-s\tenable serial I/O and set host's COM port numbers\n"
895: "\t-v\tset the DOS version\n"
1.1.1.19 root 896: #ifdef SUPPORT_XMS
1.1.1.25 root 897: "\t-x\tenable XMS/EMS\n"
1.1.1.19 root 898: #else
1.1.1.25 root 899: "\t-x\tenable EMS\n"
1.1.1.19 root 900: #endif
901: );
1.1.1.10 root 902:
903: if(!is_started_from_command_prompt()) {
904: fprintf(stderr, "\nStart this program from a command prompt!\n\nHit any key to quit...");
905: while(!_kbhit()) {
906: Sleep(10);
907: }
908: }
1.1.1.20 root 909: #ifdef _DEBUG
910: _CrtDumpMemoryLeaks();
911: #endif
1.1 root 912: return(EXIT_FAILURE);
913: }
914:
1.1.1.14 root 915: is_vista_or_later = is_greater_windows_version(6, 0, 0, 0);
916:
1.1.1.23 root 917: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 918: CONSOLE_SCREEN_BUFFER_INFO csbi;
1.1.1.14 root 919: CONSOLE_CURSOR_INFO ci;
1.1.1.23 root 920:
1.1.1.12 root 921: bSuccess = GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 922: GetConsoleCursorInfo(hStdout, &ci);
1.1.1.24 root 923: GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &dwConsoleMode);
1.1 root 924:
1.1.1.14 root 925: for(int y = 0; y < SCR_BUF_WIDTH; y++) {
926: for(int x = 0; x < SCR_BUF_HEIGHT; x++) {
927: SCR_BUF(y,x).Char.AsciiChar = ' ';
928: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
1.1 root 929: }
930: }
1.1.1.12 root 931: if(bSuccess) {
932: scr_width = csbi.dwSize.X;
1.1.1.14 root 933: scr_height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
934:
935: // v-text shadow buffer size is 0x7ff0
936: if((scr_width > SCR_BUF_WIDTH) || (scr_height > SCR_BUF_HEIGHT) || (scr_width * scr_height * 2 > 0x7ff0) ||
937: (buf_width != 0 && buf_width != scr_width) || (buf_height != 0 && buf_height != scr_height)) {
938: scr_width = min(buf_width != 0 ? buf_width : scr_width, SCR_BUF_WIDTH);
939: scr_height = min(buf_height != 0 ? buf_height : scr_height, SCR_BUF_HEIGHT);
940: if(scr_width * scr_height * 2 > 0x7ff0) {
941: scr_width = 80;
942: scr_height = 25;
943: }
1.1.1.15 root 944: bChangeScreenSize = TRUE;
1.1.1.14 root 945: }
1.1.1.12 root 946: } else {
947: // for a proof (not a console)
948: scr_width = 80;
949: scr_height = 25;
950: }
1.1.1.14 root 951: scr_buf_size.X = scr_width;
952: scr_buf_size.Y = scr_height;
953: scr_buf_pos.X = scr_buf_pos.Y = 0;
954: scr_top = csbi.srWindow.Top;
1.1 root 955: cursor_moved = false;
956:
1.1.1.25 root 957: key_buf_char = new FIFO(256);
958: key_buf_scan = new FIFO(256);
1.1 root 959:
960: hardware_init();
961:
1.1.1.9 root 962: if(msdos_init(argc - (arg_offset + 1), argv + (arg_offset + 1), envp, standard_env)) {
1.1 root 963: retval = EXIT_FAILURE;
964: } else {
1.1.1.14 root 965: #if defined(_MSC_VER) && _MSC_VER >= 1400
966: _set_invalid_parameter_handler((_invalid_parameter_handler)ignore_invalid_parameters);
967: #endif
968: SetConsoleCtrlHandler(ctrl_handler, TRUE);
969:
1.1.1.24 root 970: if(bChangeScreenSize) {
971: change_console_size(scr_width, scr_height);
972: }
1.1.1.8 root 973: TIMECAPS caps;
974: timeGetDevCaps(&caps, sizeof(TIMECAPS));
975: timeBeginPeriod(caps.wPeriodMin);
1.1.1.14 root 976: #ifdef USE_THREAD
977: InitializeCriticalSection(&vram_crit_sect);
978: CloseHandle(CreateThread(NULL, 4096, vram_thread, NULL, 0, NULL));
979: #endif
1.1 root 980: hardware_run();
1.1.1.14 root 981: #ifdef USE_THREAD
982: vram_flush();
983: DeleteCriticalSection(&vram_crit_sect);
984: #endif
1.1.1.24 root 985: timeEndPeriod(caps.wPeriodMin);
1.1.1.14 root 986:
1.1.1.24 root 987: // hStdin/hStdout (and all handles) will be closed in msdos_finish()...
1.1.1.12 root 988: if(bSuccess) {
1.1.1.23 root 989: hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.12 root 990: if(restore_console_on_exit) {
1.1.1.14 root 991: // window can't be bigger than buffer,
992: // buffer can't be smaller than window,
993: // so make a tiny window,
994: // set the required buffer,
995: // then set the required window
996: SMALL_RECT rect;
997: SET_RECT(rect, 0, csbi.srWindow.Top, 0, csbi.srWindow.Top);
998: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1.1.1.12 root 999: SetConsoleScreenBufferSize(hStdout, csbi.dwSize);
1.1.1.14 root 1000: SET_RECT(rect, 0, 0, csbi.srWindow.Right - csbi.srWindow.Left, csbi.srWindow.Bottom - csbi.srWindow.Top);
1.1.1.12 root 1001: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1002: }
1.1.1.14 root 1003: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
1004: SetConsoleCursorInfo(hStdout, &ci);
1.1.1.12 root 1005: }
1.1.1.24 root 1006: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode);
1007:
1.1 root 1008: msdos_finish();
1.1.1.14 root 1009:
1010: SetConsoleCtrlHandler(ctrl_handler, FALSE);
1.1 root 1011: }
1012:
1.1.1.10 root 1013: hardware_finish();
1014:
1.1.1.25 root 1015: key_buf_char->release();
1.1 root 1016: delete key_buf_char;
1.1.1.25 root 1017: key_buf_scan->release();
1.1 root 1018: delete key_buf_scan;
1019:
1.1.1.12 root 1020: // SetConsoleTextAttribute(hStdout, csbi.wAttributes);
1.1 root 1021:
1.1.1.20 root 1022: #ifdef _DEBUG
1023: _CrtDumpMemoryLeaks();
1024: #endif
1.1 root 1025: return(retval);
1026: }
1027:
1.1.1.20 root 1028: /* ----------------------------------------------------------------------------
1029: console
1030: ---------------------------------------------------------------------------- */
1031:
1.1.1.14 root 1032: void change_console_size(int width, int height)
1.1.1.12 root 1033: {
1.1.1.23 root 1034: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.12 root 1035: CONSOLE_SCREEN_BUFFER_INFO csbi;
1036: SMALL_RECT rect;
1037: COORD co;
1038:
1039: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 1040: if(csbi.srWindow.Top != 0 || csbi.dwCursorPosition.Y > height - 1) {
1041: if(csbi.srWindow.Right - csbi.srWindow.Left + 1 == width && csbi.srWindow.Bottom - csbi.srWindow.Top + 1 == height) {
1042: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &csbi.srWindow);
1043: SET_RECT(rect, 0, 0, width - 1, height - 1);
1044: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1045: } else if(csbi.dwCursorPosition.Y > height - 1) {
1046: SET_RECT(rect, 0, csbi.dwCursorPosition.Y - (height - 1), width - 1, csbi.dwCursorPosition.Y);
1047: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1048: SET_RECT(rect, 0, 0, width - 1, height - 1);
1049: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1.1.12 root 1050: }
1051: }
1.1.1.14 root 1052: if(csbi.dwCursorPosition.Y > height - 1) {
1.1.1.12 root 1053: co.X = csbi.dwCursorPosition.X;
1.1.1.14 root 1054: co.Y = min(height - 1, csbi.dwCursorPosition.Y - csbi.srWindow.Top);
1.1.1.12 root 1055: SetConsoleCursorPosition(hStdout, co);
1056: cursor_moved = true;
1057: }
1.1.1.14 root 1058:
1059: // window can't be bigger than buffer,
1060: // buffer can't be smaller than window,
1061: // so make a tiny window,
1062: // set the required buffer,
1063: // then set the required window
1064: SET_RECT(rect, 0, csbi.srWindow.Top, 0, csbi.srWindow.Top);
1.1.1.12 root 1065: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1.1.1.14 root 1066: co.X = width;
1067: co.Y = height;
1.1.1.12 root 1068: SetConsoleScreenBufferSize(hStdout, co);
1.1.1.14 root 1069: SET_RECT(rect, 0, 0, width - 1, height - 1);
1070: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1071:
1072: scr_width = scr_buf_size.X = width;
1073: scr_height = scr_buf_size.Y = height;
1074: scr_top = 0;
1075:
1076: clear_scr_buffer(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
1077:
1078: int regen = min(scr_width * scr_height * 2, 0x8000);
1.1.1.15 root 1079: text_vram_end_address = text_vram_top_address + regen;
1080: shadow_buffer_end_address = shadow_buffer_top_address + regen;
1081:
1.1.1.14 root 1082: if(regen > 0x4000) {
1083: regen = 0x8000;
1084: vram_pages = 1;
1085: } else if(regen > 0x2000) {
1086: regen = 0x4000;
1087: vram_pages = 2;
1088: } else if(regen > 0x1000) {
1089: regen = 0x2000;
1090: vram_pages = 4;
1091: } else {
1092: regen = 0x1000;
1093: vram_pages = 8;
1094: }
1.1.1.15 root 1095: *(UINT16 *)(mem + 0x44a) = scr_width;
1096: *(UINT16 *)(mem + 0x44c) = regen;
1097: *(UINT8 *)(mem + 0x484) = scr_height - 1;
1098:
1.1.1.24 root 1099: mouse.min_position.x = 0;
1100: mouse.min_position.y = 0;
1101: mouse.max_position.x = 8 * scr_width - 1;
1102: mouse.max_position.y = 8 * scr_height - 1;
1103:
1.1.1.15 root 1104: restore_console_on_exit = true;
1.1.1.14 root 1105: }
1106:
1107: void clear_scr_buffer(WORD attr)
1108: {
1109: for(int y = 0; y < scr_height; y++) {
1110: for(int x = 0; x < scr_width; x++) {
1111: SCR_BUF(y,x).Char.AsciiChar = ' ';
1112: SCR_BUF(y,x).Attributes = attr;
1113: }
1114: }
1.1.1.12 root 1115: }
1116:
1.1.1.24 root 1117: bool update_console_input()
1.1 root 1118: {
1.1.1.23 root 1119: HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
1.1.1.8 root 1120: DWORD dwNumberOfEvents = 0;
1.1 root 1121: DWORD dwRead;
1122: INPUT_RECORD ir[16];
1.1.1.24 root 1123: CONSOLE_SCREEN_BUFFER_INFO csbi = {0};
1124: bool result = false;
1.1 root 1125:
1.1.1.8 root 1126: if(GetNumberOfConsoleInputEvents(hStdin, &dwNumberOfEvents) && dwNumberOfEvents != 0) {
1127: if(ReadConsoleInputA(hStdin, ir, 16, &dwRead)) {
1128: for(int i = 0; i < dwRead; i++) {
1.1.1.24 root 1129: if(ir[i].EventType & MOUSE_EVENT) {
1130: if(mouse.active) {
1131: if(ir[i].Event.MouseEvent.dwEventFlags == 0) {
1132: for(int i = 0; i < MAX_MOUSE_BUTTONS; i++) {
1133: static const DWORD bits[] = {
1134: FROM_LEFT_1ST_BUTTON_PRESSED, // left
1135: RIGHTMOST_BUTTON_PRESSED, // right
1136: FROM_LEFT_2ND_BUTTON_PRESSED, // middle
1.1.1.14 root 1137: };
1.1.1.24 root 1138: bool prev_status = mouse.buttons[i].status;
1139: mouse.buttons[i].status = ((ir[i].Event.MouseEvent.dwButtonState & bits[i]) != 0);
1140:
1141: if(!prev_status && mouse.buttons[i].status) {
1142: mouse.buttons[i].pressed_times++;
1143: mouse.buttons[i].pressed_position.x = mouse.position.x;
1144: mouse.buttons[i].pressed_position.y = mouse.position.y;
1145: mouse.status |= 2 << (i * 2);
1146: } else if(prev_status && !mouse.buttons[i].status) {
1147: mouse.buttons[i].released_times++;
1148: mouse.buttons[i].released_position.x = mouse.position.x;
1149: mouse.buttons[i].released_position.y = mouse.position.y;
1150: mouse.status |= 4 << (i * 2);
1151: }
1.1.1.14 root 1152: }
1.1.1.24 root 1153: } else if(ir[i].Event.MouseEvent.dwEventFlags & MOUSE_MOVED) {
1154: // NOTE: if restore_console_on_exit, console is not scrolled
1155: if(!restore_console_on_exit && csbi.srWindow.Bottom == 0) {
1156: GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
1.1.1.14 root 1157: }
1.1.1.24 root 1158: // FIXME: character is always 8x8 ???
1159: int x = 8 * (ir[i].Event.MouseEvent.dwMousePosition.X);
1160: int y = 8 * (ir[i].Event.MouseEvent.dwMousePosition.Y - csbi.srWindow.Top);
1161: if(mouse.position.x != x || mouse.position.y != y) {
1162: mouse.position.x = x;
1163: mouse.position.y = y;
1164: mouse.status |= 1;
1.1.1.14 root 1165: }
1166: }
1167: }
1.1.1.24 root 1168: } else if(ir[i].EventType & KEY_EVENT) {
1169: kbd_data = ir[i].Event.KeyEvent.wVirtualScanCode;
1.1.1.14 root 1170: if(!ir[i].Event.KeyEvent.bKeyDown) {
1171: kbd_data |= 0x80;
1.1.1.24 root 1172: } else {
1173: kbd_data &= 0x7f;
1174:
1175: // update dos key buffer
1176: UINT8 chr = ir[i].Event.KeyEvent.uChar.AsciiChar;
1177: UINT8 scn = ir[i].Event.KeyEvent.wVirtualScanCode & 0xff;
1178:
1179: if(chr == 0) {
1180: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
1181: if(scn >= 0x3b && scn <= 0x44) {
1182: scn += 0x68 - 0x3b; // F1 to F10
1183: } else if(scn == 0x57 || scn == 0x58) {
1184: scn += 0x8b - 0x57; // F11 & F12
1185: } else if(scn >= 0x47 && scn <= 0x53) {
1186: scn += 0x97 - 0x47; // edit/arrow clusters
1187: } else if(scn == 0x35) {
1188: scn = 0xa4; // keypad /
1189: }
1190: } else if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
1191: if(scn == 0x07) {
1192: chr = 0x1e; // Ctrl+^
1193: } else if(scn == 0x0c) {
1194: chr = 0x1f; // Ctrl+_
1195: } else if(scn >= 0x35 && scn <= 0x58) {
1196: static const UINT8 ctrl_map[] = {
1197: 0x95, // keypad /
1198: 0,
1199: 0x96, // keypad *
1200: 0, 0, 0,
1201: 0x5e, // F1
1202: 0x5f, // F2
1203: 0x60, // F3
1204: 0x61, // F4
1205: 0x62, // F5
1206: 0x63, // F6
1207: 0x64, // F7
1208: 0x65, // F8
1209: 0x66, // F9
1210: 0x67, // F10
1211: 0,
1212: 0,
1213: 0x77, // Home
1214: 0x8d, // Up
1215: 0x84, // PgUp
1216: 0x8e, // keypad -
1217: 0x73, // Left
1218: 0x8f, // keypad center
1219: 0x74, // Right
1220: 0x90, // keyapd +
1221: 0x75, // End
1222: 0x91, // Down
1223: 0x76, // PgDn
1224: 0x92, // Insert
1225: 0x93, // Delete
1226: 0, 0, 0,
1227: 0x89, // F11
1228: 0x8a, // F12
1229: };
1230: scn = ctrl_map[scn - 0x35];
1231: }
1232: } else if(ir[i].Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
1233: if(scn >= 0x3b && scn <= 0x44) {
1234: scn += 0x54 - 0x3b; // F1 to F10
1235: } else if(scn == 0x57 || scn == 0x58) {
1236: scn += 0x87 - 0x57; // F11 & F12
1237: }
1238: } else if(scn == 0x57 || scn == 0x58) {
1239: scn += 0x85 - 0x57;
1240: }
1241: // ignore shift, ctrl, alt, win and menu keys
1242: if(scn != 0x1d && scn != 0x2a && scn != 0x36 && scn != 0x38 && (scn < 0x5b || scn > 0x5e)) {
1243: if(chr == 0) {
1244: key_buf_char->write(0x00);
1245: key_buf_scan->write(ir[i].Event.KeyEvent.dwControlKeyState & ENHANCED_KEY ? 0xe0 : 0x00);
1246: }
1247: key_buf_char->write(chr);
1248: key_buf_scan->write(scn);
1249: }
1250: } else {
1251: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
1252: chr = 0;
1253: if(scn >= 0x02 && scn <= 0x0e) {
1254: scn += 0x78 - 0x02; // 1 to 0 - =
1255: }
1256: }
1257: key_buf_char->write(chr);
1258: key_buf_scan->write(scn);
1259: }
1.1 root 1260: }
1.1.1.24 root 1261: result = key_changed = true;
1.1 root 1262: }
1263: }
1264: }
1265: }
1.1.1.24 root 1266: return(result);
1.1.1.8 root 1267: }
1268:
1.1.1.14 root 1269: bool update_key_buffer()
1.1.1.8 root 1270: {
1.1.1.24 root 1271: return(update_console_input() || key_buf_char->count() != 0);
1.1.1.8 root 1272: }
1273:
1.1.1.20 root 1274: /* ----------------------------------------------------------------------------
1275: MS-DOS virtual machine
1276: ---------------------------------------------------------------------------- */
1277:
1278: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg);
1279: int msdos_psp_get_file_table(int fd, int psp_seg);
1280: void msdos_putch(UINT8 data);
1281:
1.1 root 1282: // process info
1283:
1284: process_t *msdos_process_info_create(UINT16 psp_seg)
1285: {
1286: for(int i = 0; i < MAX_PROCESS; i++) {
1287: if(process[i].psp == 0 || process[i].psp == psp_seg) {
1288: memset(&process[i], 0, sizeof(process_t));
1289: process[i].psp = psp_seg;
1290: return(&process[i]);
1291: }
1292: }
1293: fatalerror("too many processes\n");
1294: return(NULL);
1295: }
1296:
1297: process_t *msdos_process_info_get(UINT16 psp_seg)
1298: {
1299: for(int i = 0; i < MAX_PROCESS; i++) {
1300: if(process[i].psp == psp_seg) {
1301: return(&process[i]);
1302: }
1303: }
1304: fatalerror("invalid psp address\n");
1305: return(NULL);
1306: }
1307:
1.1.1.23 root 1308: void msdos_sda_update(int psp_seg)
1309: {
1310: sda_t *sda = (sda_t *)(mem + SDA_TOP);
1311:
1312: for(int i = 0; i < MAX_PROCESS; i++) {
1313: if(process[i].psp == psp_seg) {
1314: sda->switchar = process[i].switchar;
1315: sda->current_dta.w.l = process[i].dta.w.l;
1316: sda->current_dta.w.h = process[i].dta.w.h;
1317: sda->current_psp = process[i].psp;
1318: break;
1319: }
1320: }
1321: sda->malloc_strategy = malloc_strategy;
1322: sda->return_code = retval;
1323: sda->current_drive = _getdrive();
1324: }
1325:
1.1.1.13 root 1326: // dta info
1327:
1328: void msdos_dta_info_init()
1329: {
1.1.1.14 root 1330: for(int i = 0; i < MAX_DTAINFO; i++) {
1.1.1.13 root 1331: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
1332: }
1333: }
1334:
1335: dtainfo_t *msdos_dta_info_get(UINT16 psp_seg, UINT32 dta_laddr)
1336: {
1337: dtainfo_t *free_dta = NULL;
1.1.1.14 root 1338: for(int i = 0; i < MAX_DTAINFO; i++) {
1339: if(dtalist[i].find_handle == INVALID_HANDLE_VALUE) {
1340: if(free_dta == NULL) {
1.1.1.13 root 1341: free_dta = &dtalist[i];
1342: }
1.1.1.14 root 1343: } else if(dta_laddr < LFN_DTA_LADDR && dtalist[i].dta == dta_laddr) {
1.1.1.13 root 1344: return(&dtalist[i]);
1345: }
1346: }
1.1.1.14 root 1347: if(free_dta) {
1.1.1.13 root 1348: free_dta->psp = psp_seg;
1349: free_dta->dta = dta_laddr;
1350: return(free_dta);
1351: }
1352: fatalerror("too many dta\n");
1353: return(NULL);
1354: }
1355:
1356: void msdos_dta_info_free(UINT16 psp_seg)
1357: {
1.1.1.14 root 1358: for(int i = 0; i < MAX_DTAINFO; i++) {
1359: if(dtalist[i].psp == psp_seg && dtalist[i].find_handle != INVALID_HANDLE_VALUE) {
1.1.1.13 root 1360: FindClose(dtalist[i].find_handle);
1361: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
1362: }
1363: }
1364: }
1365:
1.1 root 1366: void msdos_cds_update(int drv)
1367: {
1368: cds_t *cds = (cds_t *)(mem + CDS_TOP);
1369:
1370: memset(mem + CDS_TOP, 0, CDS_SIZE);
1371: sprintf(cds->path_name, "%c:\\", 'A' + drv);
1372: cds->drive_attrib = 0x4000; // physical drive
1373: cds->physical_drive_number = drv;
1374: }
1375:
1.1.1.17 root 1376: // nls information tables
1377:
1378: // uppercase table (func 6502h)
1379: void msdos_upper_table_update()
1380: {
1381: *(UINT16 *)(mem + UPPERTABLE_TOP) = 0x80;
1.1.1.22 root 1382: for(unsigned i = 0; i < 0x80; ++i) {
1.1.1.17 root 1383: UINT8 c[4];
1384: *(UINT32 *)c = 0; // reset internal conversion state
1385: CharUpperBuffA((LPSTR)c, 4); // (workaround for MBCS codepage)
1386: c[0] = 0x80 + i;
1387: DWORD rc = CharUpperBuffA((LPSTR)c, 1);
1388: mem[UPPERTABLE_TOP + 2 + i] = (rc == 1 && c[0]) ? c[0] : 0x80 + i;
1389: }
1390: }
1391:
1.1.1.23 root 1392: // lowercase table (func 6503h)
1393: void msdos_lower_table_update()
1394: {
1395: *(UINT16 *)(mem + LOWERTABLE_TOP) = 0x80;
1396: for(unsigned i = 0; i < 0x80; ++i) {
1397: UINT8 c[4];
1398: *(UINT32 *)c = 0; // reset internal conversion state
1399: CharLowerBuffA((LPSTR)c, 4); // (workaround for MBCS codepage)
1400: c[0] = 0x80 + i;
1401: DWORD rc = CharLowerBuffA((LPSTR)c, 1);
1402: mem[LOWERTABLE_TOP + 2 + i] = (rc == 1 && c[0]) ? c[0] : 0x80 + i;
1403: }
1404: }
1405:
1.1.1.17 root 1406: // filename uppercase table (func 6504h)
1407: void msdos_filename_upper_table_init()
1408: {
1409: // depended on (file)system, not on active codepage
1410: // temporary solution: just filling data
1411: *(UINT16 *)(mem + FILENAME_UPPERTABLE_TOP) = 0x80;
1.1.1.22 root 1412: for(unsigned i = 0; i < 0x80; ++i) {
1.1.1.17 root 1413: mem[FILENAME_UPPERTABLE_TOP + 2 + i] = 0x80 + i;
1414: }
1415: }
1416:
1417: // filaname terminator table (func 6505h)
1418: void msdos_filename_terminator_table_init()
1419: {
1420: const char illegal_chars[] = ".\"/\\[]:|<>+=;,"; // for standard MS-DOS fs.
1421: UINT8 *data = mem + FILENAME_TERMINATOR_TOP;
1422:
1423: data[2] = 1; // marker? (permissible character value)
1424: data[3] = 0x00; // 00h...FFh
1425: data[4] = 0xff;
1426: data[5] = 0; // marker? (excluded character)
1427: data[6] = 0x00; // 00h...20h
1428: data[7] = 0x20;
1429: data[8] = 2; // marker? (illegal characters for filename)
1430: data[9] = (UINT8)strlen(illegal_chars);
1431: memcpy(data + 10, illegal_chars, data[9]);
1432:
1433: // total length
1434: *(UINT16 *)data = (10 - 2) + data[9];
1435: }
1436:
1437: // collating table (func 6506h)
1438: void msdos_collating_table_update()
1439: {
1440: // temporary solution: just filling data
1441: *(UINT16 *)(mem + COLLATING_TABLE_TOP) = 0x100;
1.1.1.22 root 1442: for(unsigned i = 0; i < 256; ++i) {
1.1.1.17 root 1443: mem[COLLATING_TABLE_TOP + 2 + i] = i;
1444: }
1445: }
1446:
1.1 root 1447: // dbcs
1448:
1449: void msdos_dbcs_table_update()
1450: {
1451: UINT8 dbcs_data[DBCS_SIZE];
1452: memset(dbcs_data, 0, sizeof(dbcs_data));
1453:
1454: CPINFO info;
1455: GetCPInfo(active_code_page, &info);
1456:
1457: if(info.MaxCharSize != 1) {
1458: for(int i = 0;; i += 2) {
1459: UINT8 lo = info.LeadByte[i + 0];
1460: UINT8 hi = info.LeadByte[i + 1];
1461: dbcs_data[2 + i + 0] = lo;
1462: dbcs_data[2 + i + 1] = hi;
1463: if(lo == 0 && hi == 0) {
1464: dbcs_data[0] = i + 2;
1465: break;
1466: }
1467: }
1468: } else {
1469: dbcs_data[0] = 2; // ???
1470: }
1471: memcpy(mem + DBCS_TOP, dbcs_data, sizeof(dbcs_data));
1472: }
1473:
1.1.1.17 root 1474: void msdos_dbcs_table_finish()
1475: {
1476: if(active_code_page != system_code_page) {
1477: _setmbcp(system_code_page);
1478: }
1479: }
1480:
1481: void msdos_nls_tables_init()
1.1 root 1482: {
1483: system_code_page = active_code_page = _getmbcp();
1.1.1.17 root 1484: msdos_upper_table_update();
1.1.1.23 root 1485: msdos_lower_table_update();
1.1.1.17 root 1486: msdos_filename_terminator_table_init();
1487: msdos_filename_upper_table_init();
1488: msdos_collating_table_update();
1.1 root 1489: msdos_dbcs_table_update();
1490: }
1491:
1.1.1.17 root 1492: void msdos_nls_tables_update()
1.1 root 1493: {
1.1.1.17 root 1494: msdos_dbcs_table_update();
1495: msdos_upper_table_update();
1.1.1.23 root 1496: msdos_lower_table_update();
1497: // msdos_collating_table_update();
1.1 root 1498: }
1499:
1500: int msdos_lead_byte_check(UINT8 code)
1501: {
1502: UINT8 *dbcs_table = mem + DBCS_TABLE;
1503:
1504: for(int i = 0;; i += 2) {
1505: UINT8 lo = dbcs_table[i + 0];
1506: UINT8 hi = dbcs_table[i + 1];
1507: if(lo == 0 && hi == 0) {
1508: break;
1509: }
1510: if(lo <= code && code <= hi) {
1511: return(1);
1512: }
1513: }
1514: return(0);
1515: }
1516:
1.1.1.20 root 1517: int msdos_ctrl_code_check(UINT8 code)
1518: {
1.1.1.22 root 1519: return (code >= 0x01 && code <= 0x1a && code != 0x07 && code != 0x08 && code != 0x09 && code != 0x0a && code != 0x0d);
1.1.1.20 root 1520: }
1521:
1.1 root 1522: // file control
1523:
1.1.1.14 root 1524: char *msdos_remove_double_quote(char *path)
1525: {
1526: static char tmp[MAX_PATH];
1527:
1528: memset(tmp, 0, sizeof(tmp));
1529: if(strlen(path) >= 2 && path[0] == '"' && path[strlen(path) - 1] == '"') {
1530: memcpy(tmp, path + 1, strlen(path) - 2);
1531: } else {
1532: strcpy(tmp, path);
1533: }
1534: return(tmp);
1535: }
1536:
1537: char *msdos_combine_path(char *dir, const char *file)
1538: {
1539: static char tmp[MAX_PATH];
1540: char *tmp_dir = msdos_remove_double_quote(dir);
1541:
1542: if(strlen(tmp_dir) == 0) {
1543: strcpy(tmp, file);
1544: } else if(tmp_dir[strlen(tmp_dir) - 1] == '\\') {
1545: sprintf(tmp, "%s%s", tmp_dir, file);
1546: } else {
1547: sprintf(tmp, "%s\\%s", tmp_dir, file);
1548: }
1549: return(tmp);
1550: }
1551:
1.1 root 1552: char *msdos_trimmed_path(char *path, int lfn)
1553: {
1554: static char tmp[MAX_PATH];
1555:
1556: if(lfn) {
1557: strcpy(tmp, path);
1558: } else {
1559: // remove space in the path
1560: char *src = path, *dst = tmp;
1561:
1562: while(*src != '\0') {
1563: if(msdos_lead_byte_check(*src)) {
1564: *dst++ = *src++;
1565: *dst++ = *src++;
1566: } else if(*src != ' ') {
1567: *dst++ = *src++;
1568: } else {
1569: src++; // skip space
1570: }
1571: }
1572: *dst = '\0';
1573: }
1.1.1.14 root 1574: if(_stricmp(tmp, "C:\\COMMAND.COM") == 0) {
1575: // redirect C:\COMMAND.COM to comspec_path
1576: strcpy(tmp, comspec_path);
1577: } else if(is_vista_or_later && _access(tmp, 0) != 0) {
1578: // redirect new files (without wildcards) in C:\ to %TEMP%, since C:\ is not usually writable
1579: static int root_drive_protected = -1;
1580: char temp[MAX_PATH], name[MAX_PATH], *name_temp = NULL;
1581: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
1582:
1583: if(GetFullPathName(tmp, MAX_PATH, temp, &name_temp) != 0 &&
1584: name_temp != NULL && strstr(name_temp, "?") == NULL && strstr(name_temp, "*") == NULL) {
1585: strcpy(name, name_temp);
1586: name_temp[0] = '\0';
1587:
1588: if((temp[0] == 'A' + dos_info->boot_drive - 1 || temp[0] == 'a' + dos_info->boot_drive - 1) &&
1589: (temp[1] == ':') && (temp[2] == '\\' || temp[2] == '/') && (temp[3] == '\0')) {
1590: if(root_drive_protected == -1) {
1591: FILE *fp = NULL;
1592:
1593: sprintf(temp, "%c:\\MS-DOS_Player.$$$", 'A' + dos_info->boot_drive - 1);
1594: root_drive_protected = 1;
1595: try {
1596: if((fp = fopen(temp, "w")) != NULL) {
1597: if(fprintf(fp, "TEST") == 4) {
1598: root_drive_protected = 0;
1599: }
1600: }
1601: } catch(...) {
1602: }
1603: if(fp != NULL) {
1604: fclose(fp);
1605: }
1606: if(_access(temp, 0) == 0) {
1607: remove(temp);
1608: }
1609: }
1610: if(root_drive_protected == 1) {
1611: if(GetEnvironmentVariable("TEMP", temp, MAX_PATH) != 0 ||
1612: GetEnvironmentVariable("TMP", temp, MAX_PATH) != 0) {
1613: strcpy(tmp, msdos_combine_path(temp, name));
1614: }
1615: }
1616: }
1617: }
1618: }
1.1 root 1619: return(tmp);
1620: }
1621:
1622: bool match(char *text, char *pattern)
1623: {
1.1.1.24 root 1624: // http://www.prefield.com/algorithm/string/wildcard.html
1.1.1.14 root 1625: switch(*pattern) {
1.1 root 1626: case '\0':
1627: return !*text;
1628: case '*':
1.1.1.14 root 1629: return match(text, pattern + 1) || (*text && match(text + 1, pattern));
1.1 root 1630: case '?':
1631: return *text && match(text + 1, pattern + 1);
1632: default:
1633: return (*text == *pattern) && match(text + 1, pattern + 1);
1634: }
1635: }
1636:
1637: bool msdos_match_volume_label(char *path, char *volume)
1638: {
1639: char *p;
1640:
1.1.1.14 root 1641: if(!*volume) {
1642: return false;
1643: } else if((p = my_strchr(path, ':')) != NULL) {
1.1 root 1644: return msdos_match_volume_label(p + 1, volume);
1645: } else if((p = my_strchr(path, '\\')) != NULL) {
1646: return msdos_match_volume_label(p + 1, volume);
1647: } else if((p = my_strchr(path, '.')) != NULL) {
1.1.1.14 root 1648: char tmp[MAX_PATH];
1649: sprintf(tmp, "%.*s%s", (int)(p - path), path, p + 1);
1650: return match(volume, tmp);
1.1 root 1651: } else {
1652: return match(volume, path);
1653: }
1654: }
1655:
1656: char *msdos_fcb_path(fcb_t *fcb)
1657: {
1658: static char tmp[MAX_PATH];
1659: char name[9], ext[4];
1660:
1661: memset(name, 0, sizeof(name));
1662: memcpy(name, fcb->file_name, 8);
1663: strcpy(name, msdos_trimmed_path(name, 0));
1664:
1665: memset(ext, 0, sizeof(ext));
1666: memcpy(ext, fcb->file_name + 8, 3);
1667: strcpy(ext, msdos_trimmed_path(ext, 0));
1668:
1669: if(name[0] == '\0' || strcmp(name, "????????") == 0) {
1670: strcpy(name, "*");
1671: }
1672: if(ext[0] == '\0') {
1673: strcpy(tmp, name);
1674: } else {
1675: if(strcmp(ext, "???") == 0) {
1676: strcpy(ext, "*");
1677: }
1678: sprintf(tmp, "%s.%s", name, ext);
1679: }
1680: return(tmp);
1681: }
1682:
1683: void msdos_set_fcb_path(fcb_t *fcb, char *path)
1684: {
1685: char *ext = my_strchr(path, '.');
1686:
1687: memset(fcb->file_name, 0x20, 8 + 3);
1688: if(ext != NULL && path[0] != '.') {
1689: *ext = '\0';
1690: memcpy(fcb->file_name + 8, ext + 1, strlen(ext + 1));
1691: }
1692: memcpy(fcb->file_name, path, strlen(path));
1693: }
1694:
1695: char *msdos_short_path(char *path)
1696: {
1697: static char tmp[MAX_PATH];
1698:
1.1.1.24 root 1699: if(GetShortPathName(path, tmp, MAX_PATH) == 0) {
1700: strcpy(tmp, path);
1701: }
1.1 root 1702: my_strupr(tmp);
1703: return(tmp);
1704: }
1705:
1.1.1.13 root 1706: char *msdos_short_name(WIN32_FIND_DATA *fd)
1707: {
1708: static char tmp[MAX_PATH];
1709:
1.1.1.14 root 1710: if(fd->cAlternateFileName[0]) {
1.1.1.13 root 1711: strcpy(tmp, fd->cAlternateFileName);
1712: } else {
1713: strcpy(tmp, fd->cFileName);
1714: }
1715: my_strupr(tmp);
1716: return(tmp);
1717: }
1718:
1.1 root 1719: char *msdos_short_full_path(char *path)
1720: {
1721: static char tmp[MAX_PATH];
1722: char full[MAX_PATH], *name;
1723:
1.1.1.14 root 1724: // Full works with non-existent files, but Short does not
1.1 root 1725: GetFullPathName(path, MAX_PATH, full, &name);
1.1.1.14 root 1726: *tmp = '\0';
1727: if(GetShortPathName(full, tmp, MAX_PATH) == 0 && name > path) {
1728: name[-1] = '\0';
1729: DWORD len = GetShortPathName(full, tmp, MAX_PATH);
1730: if(len == 0) {
1731: strcpy(tmp, full);
1732: } else {
1733: tmp[len++] = '\\';
1734: strcpy(tmp + len, name);
1735: }
1736: }
1.1 root 1737: my_strupr(tmp);
1738: return(tmp);
1739: }
1740:
1741: char *msdos_short_full_dir(char *path)
1742: {
1743: static char tmp[MAX_PATH];
1744: char full[MAX_PATH], *name;
1745:
1746: GetFullPathName(path, MAX_PATH, full, &name);
1747: name[-1] = '\0';
1.1.1.24 root 1748: if(GetShortPathName(full, tmp, MAX_PATH) == 0) {
1749: strcpy(tmp, full);
1750: }
1.1 root 1751: my_strupr(tmp);
1752: return(tmp);
1753: }
1754:
1755: char *msdos_local_file_path(char *path, int lfn)
1756: {
1757: char *trimmed = msdos_trimmed_path(path, lfn);
1.1.1.14 root 1758: #if 0
1759: // I have forgotten the reason of this routine... :-(
1.1 root 1760: if(_access(trimmed, 0) != 0) {
1761: process_t *process = msdos_process_info_get(current_psp);
1762: static char tmp[MAX_PATH];
1763:
1764: sprintf(tmp, "%s\\%s", process->module_dir, trimmed);
1765: if(_access(tmp, 0) == 0) {
1766: return(tmp);
1767: }
1768: }
1.1.1.14 root 1769: #endif
1.1 root 1770: return(trimmed);
1771: }
1772:
1.1.1.11 root 1773: bool msdos_is_con_path(char *path)
1774: {
1775: char full[MAX_PATH], *name;
1776:
1.1.1.24 root 1777: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1778: return(_stricmp(full, "\\\\.\\CON") == 0);
1779: }
1780: return(false);
1.1.1.11 root 1781: }
1782:
1.1.1.14 root 1783: bool msdos_is_nul_path(char *path)
1.1.1.8 root 1784: {
1.1.1.14 root 1785: char full[MAX_PATH], *name;
1.1.1.8 root 1786:
1.1.1.24 root 1787: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1788: return(_stricmp(full, "\\\\.\\NUL") == 0);
1789: }
1790: return(false);
1791: }
1792:
1793: bool msdos_is_driver_name(char *path)
1794: {
1795: char full[MAX_PATH], *name;
1796:
1797: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1798: if(_stricmp(name, "EMMXXXX0") == 0) {
1799: return(true);
1800: }
1801: }
1802: return(false);
1803: }
1804:
1805: bool msdos_is_existing_file(char *path)
1806: {
1807: // http://d.hatena.ne.jp/yu-hr/20100317/1268826458
1808: WIN32_FIND_DATA FindData;
1809: HANDLE hFind;
1810:
1811: if((hFind = FindFirstFile(path, &FindData)) != INVALID_HANDLE_VALUE) {
1812: FindClose(hFind);
1813: return(!(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY));
1814: }
1815: return(false);
1.1.1.8 root 1816: }
1817:
1.1.1.9 root 1818: char *msdos_search_command_com(char *command_path, char *env_path)
1819: {
1820: static char tmp[MAX_PATH];
1821: char path[MAX_PATH], *file_name;
1822:
1823: if(GetFullPathName(command_path, MAX_PATH, tmp, &file_name) != 0) {
1824: sprintf(file_name, "COMMAND.COM");
1825: if(_access(tmp, 0) == 0) {
1826: return(tmp);
1827: }
1828: }
1829: if(GetModuleFileName(NULL, path, MAX_PATH) != 0 && GetFullPathName(path, MAX_PATH, tmp, &file_name) != 0) {
1830: sprintf(file_name, "COMMAND.COM");
1831: if(_access(tmp, 0) == 0) {
1832: return(tmp);
1833: }
1834: }
1835: if(GetFullPathName("COMMAND.COM", MAX_PATH, tmp, &file_name) != 0) {
1836: if(_access(tmp, 0) == 0) {
1837: return(tmp);
1838: }
1839: }
1840: char *token = my_strtok(env_path, ";");
1841: while(token != NULL) {
1.1.1.14 root 1842: if(strlen(token) != 0 && token[0] != '%') {
1.1.1.9 root 1843: strcpy(tmp, msdos_combine_path(token, "COMMAND.COM"));
1844: if(_access(tmp, 0) == 0) {
1845: return(tmp);
1846: }
1847: }
1848: token = my_strtok(NULL, ";");
1849: }
1850: return(NULL);
1851: }
1852:
1.1.1.14 root 1853: int msdos_drive_number(const char *path)
1.1 root 1854: {
1855: char tmp[MAX_PATH], *name;
1856:
1857: GetFullPathName(path, MAX_PATH, tmp, &name);
1858: if(tmp[0] >= 'a' && tmp[0] <= 'z') {
1859: return(tmp[0] - 'a');
1860: } else {
1861: return(tmp[0] - 'A');
1862: }
1863: }
1864:
1865: char *msdos_volume_label(char *path)
1866: {
1867: static char tmp[MAX_PATH];
1868: char volume[] = "A:\\";
1869:
1870: if(path[1] == ':') {
1871: volume[0] = path[0];
1872: } else {
1873: volume[0] = 'A' + _getdrive() - 1;
1874: }
1875: if(!GetVolumeInformation(volume, tmp, MAX_PATH, NULL, NULL, NULL, NULL, 0)) {
1876: memset(tmp, 0, sizeof(tmp));
1877: }
1878: return(tmp);
1879: }
1880:
1881: char *msdos_short_volume_label(char *label)
1882: {
1883: static char tmp[(8 + 1 + 3) + 1];
1884: char *src = label;
1885: int remain = strlen(label);
1886: char *dst_n = tmp;
1887: char *dst_e = tmp + 9;
1888:
1889: strcpy(tmp, " . ");
1890: for(int i = 0; i < 8 && remain > 0; i++) {
1891: if(msdos_lead_byte_check(*src)) {
1892: if(++i == 8) {
1893: break;
1894: }
1895: *dst_n++ = *src++;
1896: remain--;
1897: }
1898: *dst_n++ = *src++;
1899: remain--;
1900: }
1901: if(remain > 0) {
1902: for(int i = 0; i < 3 && remain > 0; i++) {
1903: if(msdos_lead_byte_check(*src)) {
1904: if(++i == 3) {
1905: break;
1906: }
1907: *dst_e++ = *src++;
1908: remain--;
1909: }
1910: *dst_e++ = *src++;
1911: remain--;
1912: }
1913: *dst_e = '\0';
1914: } else {
1915: *dst_n = '\0';
1916: }
1917: my_strupr(tmp);
1918: return(tmp);
1919: }
1920:
1.1.1.13 root 1921: errno_t msdos_maperr(unsigned long oserrno)
1922: {
1923: _doserrno = oserrno;
1.1.1.14 root 1924: switch(oserrno) {
1.1.1.13 root 1925: case ERROR_FILE_NOT_FOUND: // 2
1926: case ERROR_PATH_NOT_FOUND: // 3
1927: case ERROR_INVALID_DRIVE: // 15
1928: case ERROR_NO_MORE_FILES: // 18
1929: case ERROR_BAD_NETPATH: // 53
1930: case ERROR_BAD_NET_NAME: // 67
1931: case ERROR_BAD_PATHNAME: // 161
1932: case ERROR_FILENAME_EXCED_RANGE: // 206
1933: return ENOENT;
1934: case ERROR_TOO_MANY_OPEN_FILES: // 4
1935: return EMFILE;
1936: case ERROR_ACCESS_DENIED: // 5
1937: case ERROR_CURRENT_DIRECTORY: // 16
1938: case ERROR_NETWORK_ACCESS_DENIED: // 65
1939: case ERROR_CANNOT_MAKE: // 82
1940: case ERROR_FAIL_I24: // 83
1941: case ERROR_DRIVE_LOCKED: // 108
1942: case ERROR_SEEK_ON_DEVICE: // 132
1943: case ERROR_NOT_LOCKED: // 158
1944: case ERROR_LOCK_FAILED: // 167
1945: return EACCES;
1946: case ERROR_INVALID_HANDLE: // 6
1947: case ERROR_INVALID_TARGET_HANDLE: // 114
1948: case ERROR_DIRECT_ACCESS_HANDLE: // 130
1949: return EBADF;
1950: case ERROR_ARENA_TRASHED: // 7
1951: case ERROR_NOT_ENOUGH_MEMORY: // 8
1952: case ERROR_INVALID_BLOCK: // 9
1953: case ERROR_NOT_ENOUGH_QUOTA: // 1816
1954: return ENOMEM;
1955: case ERROR_BAD_ENVIRONMENT: // 10
1956: return E2BIG;
1957: case ERROR_BAD_FORMAT: // 11
1958: return ENOEXEC;
1959: case ERROR_NOT_SAME_DEVICE: // 17
1960: return EXDEV;
1961: case ERROR_FILE_EXISTS: // 80
1962: case ERROR_ALREADY_EXISTS: // 183
1963: return EEXIST;
1964: case ERROR_NO_PROC_SLOTS: // 89
1965: case ERROR_MAX_THRDS_REACHED: // 164
1966: case ERROR_NESTING_NOT_ALLOWED: // 215
1967: return EAGAIN;
1968: case ERROR_BROKEN_PIPE: // 109
1969: return EPIPE;
1970: case ERROR_DISK_FULL: // 112
1971: return ENOSPC;
1972: case ERROR_WAIT_NO_CHILDREN: // 128
1973: case ERROR_CHILD_NOT_COMPLETE: // 129
1974: return ECHILD;
1975: case ERROR_DIR_NOT_EMPTY: // 145
1976: return ENOTEMPTY;
1977: }
1.1.1.14 root 1978: if(oserrno >= ERROR_WRITE_PROTECT /* 19 */ &&
1.1.1.13 root 1979: oserrno <= ERROR_SHARING_BUFFER_EXCEEDED /* 36 */) {
1980: return EACCES;
1981: }
1.1.1.14 root 1982: if(oserrno >= ERROR_INVALID_STARTING_CODESEG /* 188 */ &&
1.1.1.13 root 1983: oserrno <= ERROR_INFLOOP_IN_RELOC_CHAIN /* 202 */) {
1984: return ENOEXEC;
1985: }
1986: return EINVAL;
1987: }
1988:
1989: int msdos_open(const char *filename, int oflag)
1990: {
1.1.1.14 root 1991: if((oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) != _O_RDONLY) {
1.1.1.13 root 1992: return _open(filename, oflag);
1993: }
1.1.1.14 root 1994:
1995: SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, !(oflag & _O_NOINHERIT) };
1.1.1.13 root 1996: DWORD disposition;
1.1.1.14 root 1997: switch(oflag & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
1998: default:
1.1.1.13 root 1999: case _O_EXCL:
2000: disposition = OPEN_EXISTING;
2001: break;
2002: case _O_CREAT:
2003: disposition = OPEN_ALWAYS;
2004: break;
2005: case _O_CREAT | _O_EXCL:
2006: case _O_CREAT | _O_TRUNC | _O_EXCL:
2007: disposition = CREATE_NEW;
2008: break;
2009: case _O_TRUNC:
2010: case _O_TRUNC | _O_EXCL:
2011: disposition = TRUNCATE_EXISTING;
2012: break;
2013: case _O_CREAT | _O_TRUNC:
2014: disposition = CREATE_ALWAYS;
2015: break;
2016: }
1.1.1.14 root 2017:
1.1.1.13 root 2018: HANDLE h = CreateFile(filename, GENERIC_READ | FILE_WRITE_ATTRIBUTES,
2019: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
2020: FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.14 root 2021: if(h == INVALID_HANDLE_VALUE) {
1.1.1.13 root 2022: // FILE_WRITE_ATTRIBUTES may not be granted for standard users.
2023: // Retry without FILE_WRITE_ATTRIBUTES.
2024: h = CreateFile(filename, GENERIC_READ,
2025: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
2026: FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.14 root 2027: if(h == INVALID_HANDLE_VALUE) {
1.1.1.13 root 2028: errno = msdos_maperr(GetLastError());
2029: return -1;
2030: }
2031: }
1.1.1.14 root 2032:
1.1.1.13 root 2033: int fd = _open_osfhandle((intptr_t) h, oflag);
1.1.1.14 root 2034: if(fd == -1) {
1.1.1.13 root 2035: CloseHandle(h);
2036: }
2037: return fd;
2038: }
2039:
1.1.1.14 root 2040: void msdos_file_handler_open(int fd, const char *path, int atty, int mode, UINT16 info, UINT16 psp_seg)
1.1 root 2041: {
2042: static int id = 0;
2043: char full[MAX_PATH], *name;
2044:
2045: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
2046: strcpy(file_handler[fd].path, full);
2047: } else {
2048: strcpy(file_handler[fd].path, path);
2049: }
1.1.1.14 root 2050: // isatty makes no distinction between CON & NUL
2051: // GetFileSize fails on CON, succeeds on NUL
2052: if(atty && (info != 0x80d3 || GetFileSize((HANDLE)_get_osfhandle(fd), NULL) == 0)) {
2053: info = 0x8084;
2054: atty = 0;
2055: } else if(!atty && info == 0x80d3) {
2056: info = msdos_drive_number(".");
2057: }
1.1 root 2058: file_handler[fd].valid = 1;
2059: file_handler[fd].id = id++; // dummy id for int 21h ax=71a6h
2060: file_handler[fd].atty = atty;
2061: file_handler[fd].mode = mode;
2062: file_handler[fd].info = info;
2063: file_handler[fd].psp = psp_seg;
1.1.1.21 root 2064:
2065: // init system file table
2066: if(fd < 20) {
2067: UINT8 *sft = mem + SFT_TOP + 6 + 0x3b * fd;
2068:
2069: memset(sft, 0, 0x3b);
2070:
2071: *(UINT16 *)(sft + 0x00) = 1;
2072: *(UINT16 *)(sft + 0x02) = file_handler[fd].mode;
2073: *(UINT8 *)(sft + 0x04) = GetFileAttributes(file_handler[fd].path) & 0xff;
2074: *(UINT16 *)(sft + 0x05) = file_handler[fd].info & 0xff;
2075:
2076: if(!(file_handler[fd].info & 0x80)) {
2077: *(UINT16 *)(sft + 0x07) = sizeof(dpb_t) * (file_handler[fd].info & 0x1f);
2078: *(UINT16 *)(sft + 0x09) = DPB_TOP >> 4;
2079:
2080: FILETIME time, local;
2081: HANDLE hHandle;
2082: WORD dos_date = 0, dos_time = 0;
2083: DWORD file_size = 0;
2084: if((hHandle = (HANDLE)_get_osfhandle(fd)) != INVALID_HANDLE_VALUE) {
2085: if(GetFileTime(hHandle, NULL, NULL, &time)) {
2086: FileTimeToLocalFileTime(&time, &local);
2087: FileTimeToDosDateTime(&local, &dos_date, &dos_time);
2088: }
2089: file_size = GetFileSize(hHandle, NULL);
2090: }
2091: *(UINT16 *)(sft + 0x0d) = dos_time;
2092: *(UINT16 *)(sft + 0x0f) = dos_date;
2093: *(UINT32 *)(sft + 0x11) = file_size;
2094: }
2095:
2096: char fname[MAX_PATH] = {0}, ext[MAX_PATH] = {0};
2097: _splitpath(file_handler[fd].path, NULL, NULL, fname, ext);
2098: my_strupr(fname);
2099: my_strupr(ext);
2100: memset(sft + 0x20, 0x20, 11);
2101: memcpy(sft + 0x20, fname, min(strlen(fname), 8));
2102: memcpy(sft + 0x28, ext + 1, min(strlen(ext + 1), 3));
2103:
2104: *(UINT16 *)(sft + 0x31) = psp_seg;
2105: }
1.1 root 2106: }
2107:
2108: void msdos_file_handler_dup(int dst, int src, UINT16 psp_seg)
2109: {
2110: strcpy(file_handler[dst].path, file_handler[src].path);
2111: file_handler[dst].valid = 1;
2112: file_handler[dst].id = file_handler[src].id;
2113: file_handler[dst].atty = file_handler[src].atty;
2114: file_handler[dst].mode = file_handler[src].mode;
2115: file_handler[dst].info = file_handler[src].info;
2116: file_handler[dst].psp = psp_seg;
2117: }
2118:
1.1.1.20 root 2119: void msdos_file_handler_close(int fd)
1.1 root 2120: {
2121: file_handler[fd].valid = 0;
1.1.1.21 root 2122:
2123: if(fd < 20) {
2124: memset(mem + SFT_TOP + 6 + 0x3b * fd, 0, 0x3b);
2125: }
1.1 root 2126: }
2127:
1.1.1.14 root 2128: inline int msdos_file_attribute_create(UINT16 new_attr)
1.1 root 2129: {
1.1.1.14 root 2130: return(new_attr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
2131: FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE |
2132: FILE_ATTRIBUTE_DIRECTORY));
1.1 root 2133: }
2134:
2135: // find file
2136:
2137: int msdos_find_file_check_attribute(int attribute, int allowed_mask, int required_mask)
2138: {
2139: if((allowed_mask & 0x08) && !(attribute & FILE_ATTRIBUTE_DIRECTORY)) {
2140: return(0); // search directory only !!!
2141: } else if(!(allowed_mask & 0x02) && (attribute & FILE_ATTRIBUTE_HIDDEN)) {
2142: return(0);
2143: } else if(!(allowed_mask & 0x04) && (attribute & FILE_ATTRIBUTE_SYSTEM)) {
2144: return(0);
2145: } else if(!(allowed_mask & 0x10) && (attribute & FILE_ATTRIBUTE_DIRECTORY)) {
2146: return(0);
2147: } else if((attribute & required_mask) != required_mask) {
2148: return(0);
2149: } else {
2150: return(1);
2151: }
2152: }
2153:
1.1.1.13 root 2154: int msdos_find_file_has_8dot3name(WIN32_FIND_DATA *fd)
2155: {
1.1.1.14 root 2156: if(fd->cAlternateFileName[0]) {
1.1.1.13 root 2157: return 1;
2158: }
2159: size_t len = strlen(fd->cFileName);
1.1.1.14 root 2160: if(len > 12) {
1.1.1.13 root 2161: return 0;
2162: }
2163: const char *ext = strrchr(fd->cFileName, '.');
1.1.1.14 root 2164: if((ext ? ext - fd->cFileName : len) > 8) {
1.1.1.13 root 2165: return 0;
2166: }
2167: return 1;
2168: }
2169:
1.1 root 2170: void msdos_find_file_conv_local_time(WIN32_FIND_DATA *fd)
2171: {
2172: FILETIME local;
2173:
2174: FileTimeToLocalFileTime(&fd->ftCreationTime, &local);
2175: fd->ftCreationTime.dwLowDateTime = local.dwLowDateTime;
2176: fd->ftCreationTime.dwHighDateTime = local.dwHighDateTime;
2177:
2178: FileTimeToLocalFileTime(&fd->ftLastAccessTime, &local);
2179: fd->ftLastAccessTime.dwLowDateTime = local.dwLowDateTime;
2180: fd->ftLastAccessTime.dwHighDateTime = local.dwHighDateTime;
2181:
2182: FileTimeToLocalFileTime(&fd->ftLastWriteTime, &local);
2183: fd->ftLastWriteTime.dwLowDateTime = local.dwLowDateTime;
2184: fd->ftLastWriteTime.dwHighDateTime = local.dwHighDateTime;
2185: }
2186:
2187: // i/o
2188:
2189: void msdos_stdio_reopen()
2190: {
2191: if(!file_handler[0].valid) {
2192: _dup2(DUP_STDIN, 0);
2193: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
2194: }
2195: if(!file_handler[1].valid) {
2196: _dup2(DUP_STDOUT, 1);
2197: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
2198: }
2199: if(!file_handler[2].valid) {
2200: _dup2(DUP_STDERR, 2);
2201: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
2202: }
1.1.1.21 root 2203: if(!file_handler[3].valid) {
2204: _dup2(DUP_STDAUX, 3);
2205: msdos_file_handler_open(3, "STDAUX", 0, 2, 0x80c0, 0);
2206: }
2207: if(!file_handler[4].valid) {
2208: _dup2(DUP_STDPRN, 4);
2209: msdos_file_handler_open(4, "STDPRN", 0, 1, 0xa8c0, 0);
2210: }
2211: for(int i = 0; i < 5; i++) {
2212: if(msdos_psp_get_file_table(i, current_psp) == 0xff) {
2213: msdos_psp_set_file_table(i, i, current_psp);
2214: }
2215: }
1.1 root 2216: }
2217:
2218: int msdos_kbhit()
2219: {
2220: msdos_stdio_reopen();
2221:
1.1.1.20 root 2222: process_t *process = msdos_process_info_get(current_psp);
2223: int fd = msdos_psp_get_file_table(0, current_psp);
2224:
2225: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 2226: // stdin is redirected to file
1.1.1.20 root 2227: return(eof(fd) == 0);
1.1 root 2228: }
2229:
2230: // check keyboard status
1.1.1.5 root 2231: if(key_buf_char->count() != 0 || key_code != 0) {
1.1 root 2232: return(1);
2233: } else {
2234: return(_kbhit());
2235: }
2236: }
2237:
2238: int msdos_getch_ex(int echo)
2239: {
2240: static char prev = 0;
2241:
2242: msdos_stdio_reopen();
2243:
1.1.1.20 root 2244: process_t *process = msdos_process_info_get(current_psp);
2245: int fd = msdos_psp_get_file_table(0, current_psp);
2246:
2247: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 2248: // stdin is redirected to file
2249: retry:
2250: char data;
1.1.1.20 root 2251: if(_read(fd, &data, 1) == 1) {
1.1 root 2252: char tmp = data;
2253: if(data == 0x0a) {
2254: if(prev == 0x0d) {
2255: goto retry; // CRLF -> skip LF
2256: } else {
2257: data = 0x0d; // LF only -> CR
2258: }
2259: }
2260: prev = tmp;
2261: return(data);
2262: }
2263: return(EOF);
2264: }
2265:
2266: // input from console
1.1.1.5 root 2267: int key_char, key_scan;
2268: if(key_code != 0) {
2269: key_char = (key_code >> 0) & 0xff;
2270: key_scan = (key_code >> 8) & 0xff;
2271: key_code >>= 16;
2272: } else {
1.1.1.26! root 2273: while(key_buf_char->count() == 0 && !m_halted && !ctrl_c_pressed) {
1.1.1.23 root 2274: if(!(fd < process->max_files && file_handler[fd].valid && file_handler[fd].atty && file_mode[file_handler[fd].mode].in)) {
2275: // NOTE: stdin is redirected to stderr when we do "type (file) | more" on freedos's command.com
2276: if(_kbhit()) {
2277: key_buf_char->write(_getch());
2278: key_buf_scan->write(0);
2279: } else {
2280: Sleep(10);
2281: }
2282: } else {
2283: if(!update_key_buffer()) {
2284: Sleep(10);
2285: }
1.1.1.14 root 2286: }
2287: }
2288: if(m_halted) {
1.1.1.26! root 2289: // ctrl-break pressed - insert CR to terminate input loops
1.1.1.14 root 2290: key_char = 0x0d;
2291: key_scan = 0;
1.1.1.26! root 2292: } else if(ctrl_c_pressed) {
! 2293: // ctrl-c pressed
! 2294: key_char = 0x03;
! 2295: key_scan = 0;
1.1.1.14 root 2296: } else {
2297: key_char = key_buf_char->read();
2298: key_scan = key_buf_scan->read();
1.1.1.5 root 2299: }
1.1 root 2300: }
2301: if(echo && key_char) {
2302: msdos_putch(key_char);
2303: }
2304: return key_char ? key_char : (key_scan != 0xe0) ? key_scan : 0;
2305: }
2306:
2307: inline int msdos_getch()
2308: {
2309: return(msdos_getch_ex(0));
2310: }
2311:
2312: inline int msdos_getche()
2313: {
2314: return(msdos_getch_ex(1));
2315: }
2316:
2317: int msdos_write(int fd, const void *buffer, unsigned int count)
2318: {
2319: static int is_cr = 0;
2320:
2321: if(fd == 1 && !file_handler[1].atty) {
2322: // CR+LF -> LF
2323: UINT8 *buf = (UINT8 *)buffer;
2324: for(unsigned int i = 0; i < count; i++) {
2325: UINT8 data = buf[i];
2326: if(is_cr) {
2327: if(data != 0x0a) {
2328: UINT8 tmp = 0x0d;
2329: _write(1, &tmp, 1);
2330: }
2331: _write(1, &data, 1);
2332: is_cr = 0;
2333: } else if(data == 0x0d) {
2334: is_cr = 1;
2335: } else {
2336: _write(1, &data, 1);
2337: }
2338: }
2339: return(count);
2340: }
1.1.1.14 root 2341: vram_flush();
1.1 root 2342: return(_write(fd, buffer, count));
2343: }
2344:
2345: void msdos_putch(UINT8 data)
2346: {
2347: static int p = 0;
2348: static int is_kanji = 0;
2349: static int is_esc = 0;
2350: static int stored_x;
2351: static int stored_y;
2352: static WORD stored_a;
1.1.1.20 root 2353: static char tmp[64], out[64];
1.1 root 2354:
2355: msdos_stdio_reopen();
2356:
1.1.1.20 root 2357: process_t *process = msdos_process_info_get(current_psp);
2358: int fd = msdos_psp_get_file_table(1, current_psp);
2359:
2360: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 2361: // stdout is redirected to file
1.1.1.20 root 2362: msdos_write(fd, &data, 1);
1.1 root 2363: return;
2364: }
1.1.1.23 root 2365: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 2366:
2367: // output to console
2368: tmp[p++] = data;
2369:
1.1.1.14 root 2370: vram_flush();
2371:
1.1 root 2372: if(is_kanji) {
2373: // kanji character
2374: is_kanji = 0;
2375: } else if(is_esc) {
2376: // escape sequense
2377: if((tmp[1] == ')' || tmp[1] == '(') && p == 3) {
2378: p = is_esc = 0;
2379: } else if(tmp[1] == '=' && p == 4) {
2380: COORD co;
2381: co.X = tmp[3] - 0x20;
1.1.1.14 root 2382: co.Y = tmp[2] - 0x20 + scr_top;
1.1 root 2383: SetConsoleCursorPosition(hStdout, co);
2384: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14 root 2385: mem[0x451 + mem[0x462] * 2] = co.Y - scr_top;
1.1 root 2386: cursor_moved = false;
2387: p = is_esc = 0;
2388: } else if((data >= 'a' && data <= 'z') || (data >= 'A' && data <= 'Z') || data == '*') {
2389: CONSOLE_SCREEN_BUFFER_INFO csbi;
2390: COORD co;
2391: GetConsoleScreenBufferInfo(hStdout, &csbi);
2392: co.X = csbi.dwCursorPosition.X;
2393: co.Y = csbi.dwCursorPosition.Y;
2394: WORD wAttributes = csbi.wAttributes;
2395:
2396: if(tmp[1] == 'D') {
2397: co.Y++;
2398: } else if(tmp[1] == 'E') {
2399: co.X = 0;
2400: co.Y++;
2401: } else if(tmp[1] == 'M') {
2402: co.Y--;
2403: } else if(tmp[1] == '*') {
2404: SMALL_RECT rect;
1.1.1.14 root 2405: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2406: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2407: co.X = 0;
2408: co.Y = csbi.srWindow.Top;
1.1 root 2409: } else if(tmp[1] == '[') {
2410: int param[256], params = 0;
2411: memset(param, 0, sizeof(param));
2412: for(int i = 2; i < p; i++) {
2413: if(tmp[i] >= '0' && tmp[i] <= '9') {
2414: param[params] *= 10;
2415: param[params] += tmp[i] - '0';
2416: } else {
2417: params++;
2418: }
2419: }
2420: if(data == 'A') {
1.1.1.14 root 2421: co.Y -= (params == 0) ? 1 : param[0];
1.1 root 2422: } else if(data == 'B') {
1.1.1.14 root 2423: co.Y += (params == 0) ? 1 : param[0];
1.1 root 2424: } else if(data == 'C') {
1.1.1.14 root 2425: co.X += (params == 0) ? 1 : param[0];
1.1 root 2426: } else if(data == 'D') {
1.1.1.14 root 2427: co.X -= (params == 0) ? 1 : param[0];
1.1 root 2428: } else if(data == 'H' || data == 'f') {
1.1.1.14 root 2429: co.X = (param[1] == 0 ? 1 : param[1]) - 1;
2430: co.Y = (param[0] == 0 ? 1 : param[0]) - 1 + csbi.srWindow.Top;
1.1 root 2431: } else if(data == 'J') {
2432: SMALL_RECT rect;
1.1.1.14 root 2433: clear_scr_buffer(csbi.wAttributes);
1.1 root 2434: if(param[0] == 0) {
2435: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 2436: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2437: if(co.Y < csbi.srWindow.Bottom) {
2438: SET_RECT(rect, 0, co.Y + 1, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2439: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2440: }
2441: } else if(param[0] == 1) {
1.1.1.14 root 2442: if(co.Y > csbi.srWindow.Top) {
2443: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, co.Y - 1);
2444: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2445: }
2446: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14 root 2447: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2448: } else if(param[0] == 2) {
1.1.1.14 root 2449: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2450: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2451: co.X = co.Y = 0;
2452: }
2453: } else if(data == 'K') {
2454: SMALL_RECT rect;
1.1.1.14 root 2455: clear_scr_buffer(csbi.wAttributes);
1.1 root 2456: if(param[0] == 0) {
2457: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 2458: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2459: } else if(param[0] == 1) {
2460: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14 root 2461: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2462: } else if(param[0] == 2) {
2463: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 2464: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2465: }
2466: } else if(data == 'L') {
2467: SMALL_RECT rect;
1.1.1.14 root 2468: if(params == 0) {
2469: param[0] = 1;
1.1 root 2470: }
1.1.1.14 root 2471: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2472: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2473: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2474: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2475: clear_scr_buffer(csbi.wAttributes);
1.1 root 2476: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y + param[0] - 1);
1.1.1.14 root 2477: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2478: co.X = 0;
2479: } else if(data == 'M') {
2480: SMALL_RECT rect;
1.1.1.14 root 2481: if(params == 0) {
2482: param[0] = 1;
2483: }
2484: if(co.Y + param[0] > csbi.srWindow.Bottom) {
2485: clear_scr_buffer(csbi.wAttributes);
2486: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2487: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2488: } else {
1.1.1.14 root 2489: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2490: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2491: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2492: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2493: clear_scr_buffer(csbi.wAttributes);
1.1 root 2494: }
2495: co.X = 0;
2496: } else if(data == 'h') {
2497: if(tmp[2] == '>' && tmp[3] == '5') {
2498: CONSOLE_CURSOR_INFO cur;
2499: GetConsoleCursorInfo(hStdout, &cur);
2500: if(cur.bVisible) {
2501: cur.bVisible = FALSE;
1.1.1.14 root 2502: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 2503: }
2504: }
2505: } else if(data == 'l') {
2506: if(tmp[2] == '>' && tmp[3] == '5') {
2507: CONSOLE_CURSOR_INFO cur;
2508: GetConsoleCursorInfo(hStdout, &cur);
2509: if(!cur.bVisible) {
2510: cur.bVisible = TRUE;
1.1.1.14 root 2511: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 2512: }
2513: }
2514: } else if(data == 'm') {
2515: wAttributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
2516: int reverse = 0, hidden = 0;
2517: for(int i = 0; i < params; i++) {
2518: if(param[i] == 1) {
2519: wAttributes |= FOREGROUND_INTENSITY;
2520: } else if(param[i] == 4) {
2521: wAttributes |= COMMON_LVB_UNDERSCORE;
2522: } else if(param[i] == 7) {
2523: reverse = 1;
2524: } else if(param[i] == 8 || param[i] == 16) {
2525: hidden = 1;
2526: } else if((param[i] >= 17 && param[i] <= 23) || (param[i] >= 30 && param[i] <= 37)) {
2527: wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
2528: if(param[i] >= 17 && param[i] <= 23) {
2529: param[i] -= 16;
2530: } else {
2531: param[i] -= 30;
2532: }
2533: if(param[i] & 1) {
2534: wAttributes |= FOREGROUND_RED;
2535: }
2536: if(param[i] & 2) {
2537: wAttributes |= FOREGROUND_GREEN;
2538: }
2539: if(param[i] & 4) {
2540: wAttributes |= FOREGROUND_BLUE;
2541: }
2542: } else if(param[i] >= 40 && param[i] <= 47) {
2543: wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
2544: if((param[i] - 40) & 1) {
2545: wAttributes |= BACKGROUND_RED;
2546: }
2547: if((param[i] - 40) & 2) {
2548: wAttributes |= BACKGROUND_GREEN;
2549: }
2550: if((param[i] - 40) & 4) {
2551: wAttributes |= BACKGROUND_BLUE;
2552: }
2553: }
2554: }
2555: if(reverse) {
2556: wAttributes &= ~0xff;
2557: wAttributes |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
2558: }
2559: if(hidden) {
2560: wAttributes &= ~0x0f;
2561: wAttributes |= (wAttributes >> 4) & 0x0f;
2562: }
2563: } else if(data == 'n') {
2564: if(param[0] == 6) {
2565: char tmp[16];
2566: sprintf(tmp, "\x1b[%d;%dR", co.Y + 1, co.X + 1);
2567: int len = strlen(tmp);
2568: for(int i = 0; i < len; i++) {
2569: key_buf_char->write(tmp[i]);
2570: key_buf_scan->write(0x00);
2571: }
2572: }
2573: } else if(data == 's') {
2574: stored_x = co.X;
2575: stored_y = co.Y;
2576: stored_a = wAttributes;
2577: } else if(data == 'u') {
2578: co.X = stored_x;
2579: co.Y = stored_y;
2580: wAttributes = stored_a;
2581: }
2582: }
2583: if(co.X < 0) {
2584: co.X = 0;
2585: } else if(co.X >= csbi.dwSize.X) {
2586: co.X = csbi.dwSize.X - 1;
2587: }
1.1.1.14 root 2588: if(co.Y < csbi.srWindow.Top) {
2589: co.Y = csbi.srWindow.Top;
2590: } else if(co.Y > csbi.srWindow.Bottom) {
2591: co.Y = csbi.srWindow.Bottom;
1.1 root 2592: }
2593: if(co.X != csbi.dwCursorPosition.X || co.Y != csbi.dwCursorPosition.Y) {
2594: SetConsoleCursorPosition(hStdout, co);
2595: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14 root 2596: mem[0x451 + mem[0x462] * 2] = co.Y - csbi.srWindow.Top;
1.1 root 2597: cursor_moved = false;
2598: }
2599: if(wAttributes != csbi.wAttributes) {
2600: SetConsoleTextAttribute(hStdout, wAttributes);
2601: }
2602: p = is_esc = 0;
2603: }
2604: return;
2605: } else {
2606: if(msdos_lead_byte_check(data)) {
2607: is_kanji = 1;
2608: return;
2609: } else if(data == 0x1b) {
2610: is_esc = 1;
2611: return;
2612: }
2613: }
1.1.1.20 root 2614:
2615: DWORD q = 0, num;
2616: is_kanji = 0;
2617: for(int i = 0; i < p; i++) {
2618: UINT8 c = tmp[i];
2619: if(is_kanji) {
2620: is_kanji = 0;
2621: } else if(msdos_lead_byte_check(data)) {
2622: is_kanji = 1;
2623: } else if(msdos_ctrl_code_check(data)) {
2624: out[q++] = '^';
2625: c += 'A' - 1;
2626: }
2627: out[q++] = c;
2628: }
2629: WriteConsole(hStdout, out, q, &num, NULL);
1.1 root 2630: p = 0;
1.1.1.14 root 2631:
1.1.1.15 root 2632: if(!restore_console_on_exit) {
2633: CONSOLE_SCREEN_BUFFER_INFO csbi;
2634: GetConsoleScreenBufferInfo(hStdout, &csbi);
2635: scr_top = csbi.srWindow.Top;
2636: }
1.1 root 2637: cursor_moved = true;
2638: }
2639:
2640: int msdos_aux_in()
2641: {
1.1.1.21 root 2642: msdos_stdio_reopen();
2643:
1.1.1.20 root 2644: process_t *process = msdos_process_info_get(current_psp);
2645: int fd = msdos_psp_get_file_table(3, current_psp);
2646:
2647: if(fd < process->max_files && file_handler[fd].valid && !eof(fd)) {
1.1 root 2648: char data = 0;
1.1.1.20 root 2649: _read(fd, &data, 1);
1.1 root 2650: return(data);
2651: } else {
2652: return(EOF);
2653: }
2654: }
2655:
2656: void msdos_aux_out(char data)
2657: {
1.1.1.21 root 2658: msdos_stdio_reopen();
2659:
1.1.1.20 root 2660: process_t *process = msdos_process_info_get(current_psp);
2661: int fd = msdos_psp_get_file_table(3, current_psp);
2662:
2663: if(fd < process->max_files && file_handler[fd].valid) {
2664: msdos_write(fd, &data, 1);
1.1 root 2665: }
2666: }
2667:
2668: void msdos_prn_out(char data)
2669: {
1.1.1.21 root 2670: msdos_stdio_reopen();
2671:
1.1.1.20 root 2672: process_t *process = msdos_process_info_get(current_psp);
2673: int fd = msdos_psp_get_file_table(4, current_psp);
2674:
2675: if(fd < process->max_files && file_handler[fd].valid) {
2676: msdos_write(fd, &data, 1);
1.1 root 2677: }
2678: }
2679:
2680: // memory control
2681:
1.1.1.19 root 2682: mcb_t *msdos_mcb_create(int mcb_seg, UINT8 mz, UINT16 psp, int paragraphs)
1.1 root 2683: {
2684: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2685:
2686: mcb->mz = mz;
2687: mcb->psp = psp;
1.1.1.19 root 2688: mcb->paragraphs32 = paragraphs;
1.1 root 2689: return(mcb);
2690: }
2691:
2692: void msdos_mcb_check(mcb_t *mcb)
2693: {
2694: if(!(mcb->mz == 'M' || mcb->mz == 'Z')) {
2695: fatalerror("broken mcb\n");
2696: }
2697: }
2698:
2699: int msdos_mem_split(int seg, int paragraphs)
2700: {
2701: int mcb_seg = seg - 1;
2702: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2703: msdos_mcb_check(mcb);
2704:
1.1.1.19 root 2705: if(mcb->paragraphs() > paragraphs) {
1.1 root 2706: int new_seg = mcb_seg + 1 + paragraphs;
1.1.1.19 root 2707: int new_paragraphs = mcb->paragraphs() - paragraphs - 1;
1.1 root 2708:
2709: msdos_mcb_create(new_seg, mcb->mz, 0, new_paragraphs);
2710: mcb->mz = 'M';
1.1.1.19 root 2711: mcb->paragraphs32 = paragraphs;
1.1 root 2712: return(0);
2713: }
2714: return(-1);
2715: }
2716:
2717: void msdos_mem_merge(int seg)
2718: {
2719: int mcb_seg = seg - 1;
2720: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2721: msdos_mcb_check(mcb);
2722:
2723: while(1) {
2724: if(mcb->mz == 'Z') {
2725: break;
2726: }
1.1.1.19 root 2727: int next_seg = mcb_seg + 1 + mcb->paragraphs();
1.1 root 2728: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
2729: msdos_mcb_check(next_mcb);
2730:
2731: if(next_mcb->psp != 0) {
2732: break;
2733: }
2734: mcb->mz = next_mcb->mz;
1.1.1.19 root 2735: mcb->paragraphs32 = mcb->paragraphs() + 1 + next_mcb->paragraphs();
1.1 root 2736: }
2737: }
2738:
1.1.1.8 root 2739: int msdos_mem_alloc(int mcb_seg, int paragraphs, int new_process)
1.1 root 2740: {
2741: while(1) {
2742: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2743:
1.1.1.14 root 2744: if(mcb->psp == 0) {
2745: msdos_mem_merge(mcb_seg + 1);
2746: } else {
2747: msdos_mcb_check(mcb);
2748: }
1.1.1.8 root 2749: if(!(new_process && mcb->mz != 'Z')) {
1.1.1.19 root 2750: if(mcb->psp == 0 && mcb->paragraphs() >= paragraphs) {
1.1 root 2751: msdos_mem_split(mcb_seg + 1, paragraphs);
2752: mcb->psp = current_psp;
2753: return(mcb_seg + 1);
2754: }
2755: }
2756: if(mcb->mz == 'Z') {
2757: break;
2758: }
1.1.1.19 root 2759: mcb_seg += 1 + mcb->paragraphs();
1.1 root 2760: }
2761: return(-1);
2762: }
2763:
2764: int msdos_mem_realloc(int seg, int paragraphs, int *max_paragraphs)
2765: {
2766: int mcb_seg = seg - 1;
2767: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2768: msdos_mcb_check(mcb);
1.1.1.19 root 2769: int current_paragraphs = mcb->paragraphs();
1.1 root 2770:
2771: msdos_mem_merge(seg);
1.1.1.19 root 2772: if(paragraphs > mcb->paragraphs()) {
1.1.1.14 root 2773: if(max_paragraphs) {
1.1.1.19 root 2774: *max_paragraphs = mcb->paragraphs();
1.1.1.14 root 2775: }
1.1 root 2776: msdos_mem_split(seg, current_paragraphs);
2777: return(-1);
2778: }
2779: msdos_mem_split(seg, paragraphs);
2780: return(0);
2781: }
2782:
2783: void msdos_mem_free(int seg)
2784: {
2785: int mcb_seg = seg - 1;
2786: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2787: msdos_mcb_check(mcb);
2788:
2789: mcb->psp = 0;
2790: msdos_mem_merge(seg);
2791: }
2792:
1.1.1.8 root 2793: int msdos_mem_get_free(int mcb_seg, int new_process)
1.1 root 2794: {
2795: int max_paragraphs = 0;
2796:
2797: while(1) {
2798: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2799: msdos_mcb_check(mcb);
2800:
1.1.1.8 root 2801: if(!(new_process && mcb->mz != 'Z')) {
1.1.1.19 root 2802: if(mcb->psp == 0 && mcb->paragraphs() > max_paragraphs) {
2803: max_paragraphs = mcb->paragraphs();
1.1 root 2804: }
2805: }
2806: if(mcb->mz == 'Z') {
2807: break;
2808: }
1.1.1.19 root 2809: mcb_seg += 1 + mcb->paragraphs();
1.1 root 2810: }
1.1.1.14 root 2811: return(max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs);
1.1 root 2812: }
2813:
1.1.1.8 root 2814: int msdos_mem_get_last_mcb(int mcb_seg, UINT16 psp)
2815: {
2816: int last_seg = -1;
2817:
2818: while(1) {
2819: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2820: msdos_mcb_check(mcb);
2821:
1.1.1.14 root 2822: if(mcb->psp == psp) {
1.1.1.8 root 2823: last_seg = mcb_seg;
2824: }
1.1.1.14 root 2825: if(mcb->mz == 'Z') {
2826: break;
2827: }
1.1.1.19 root 2828: mcb_seg += 1 + mcb->paragraphs();
1.1.1.8 root 2829: }
2830: return(last_seg);
2831: }
2832:
1.1.1.19 root 2833: int msdos_mem_get_umb_linked()
2834: {
2835: int mcb_seg = first_mcb;
2836:
2837: while(1) {
2838: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2839: msdos_mcb_check(mcb);
2840:
2841: if(mcb->mz == 'Z') {
2842: if(mcb_seg >= (UMB_TOP >> 4)) {
2843: return(-1);
2844: }
2845: break;
2846: }
2847: mcb_seg += 1 + mcb->paragraphs();
2848: }
2849: return(0);
2850: }
2851:
2852: int msdos_mem_link_umb()
2853: {
2854: int mcb_seg = first_mcb;
2855:
2856: while(1) {
2857: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2858: msdos_mcb_check(mcb);
2859: mcb_seg += 1 + mcb->paragraphs();
2860:
2861: if(mcb->mz == 'Z') {
2862: if(mcb_seg == (MEMORY_END >> 4) - 1) {
2863: mcb->mz = 'M';
1.1.1.20 root 2864: ((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked |= 0x01;
1.1.1.19 root 2865: return(-1);
2866: }
2867: break;
2868: }
2869: }
2870: return(0);
2871: }
2872:
2873: int msdos_mem_unlink_umb()
2874: {
2875: int mcb_seg = first_mcb;
2876:
2877: while(1) {
2878: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2879: msdos_mcb_check(mcb);
2880: mcb_seg += 1 + mcb->paragraphs();
2881:
2882: if(mcb->mz == 'Z') {
2883: break;
2884: } else {
2885: if(mcb_seg == (MEMORY_END >> 4) - 1) {
2886: mcb->mz = 'Z';
1.1.1.20 root 2887: ((dos_info_t *)(mem + DOS_INFO_TOP))->umb_linked &= ~0x01;
1.1.1.19 root 2888: return(-1);
2889: }
2890: }
2891: }
2892: return(0);
2893: }
2894:
1.1 root 2895: // environment
2896:
2897: void msdos_env_set_argv(int env_seg, char *argv)
2898: {
2899: char *dst = (char *)(mem + (env_seg << 4));
2900:
2901: while(1) {
2902: if(dst[0] == 0) {
2903: break;
2904: }
2905: dst += strlen(dst) + 1;
2906: }
2907: *dst++ = 0; // end of environment
2908: *dst++ = 1; // top of argv[0]
2909: *dst++ = 0;
2910: memcpy(dst, argv, strlen(argv));
2911: dst += strlen(argv);
2912: *dst++ = 0;
2913: *dst++ = 0;
2914: }
2915:
2916: char *msdos_env_get_argv(int env_seg)
2917: {
2918: static char env[ENV_SIZE];
2919: char *src = env;
2920:
2921: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
2922: while(1) {
2923: if(src[0] == 0) {
2924: if(src[1] == 1) {
2925: return(src + 3);
2926: }
2927: break;
2928: }
2929: src += strlen(src) + 1;
2930: }
2931: return(NULL);
2932: }
2933:
2934: char *msdos_env_get(int env_seg, const char *name)
2935: {
2936: static char env[ENV_SIZE];
2937: char *src = env;
2938:
2939: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
2940: while(1) {
2941: if(src[0] == 0) {
2942: break;
2943: }
2944: int len = strlen(src);
2945: char *n = my_strtok(src, "=");
2946: char *v = src + strlen(n) + 1;
2947:
2948: if(_stricmp(name, n) == 0) {
2949: return(v);
2950: }
2951: src += len + 1;
2952: }
2953: return(NULL);
2954: }
2955:
2956: void msdos_env_set(int env_seg, char *name, char *value)
2957: {
2958: char env[ENV_SIZE];
2959: char *src = env;
2960: char *dst = (char *)(mem + (env_seg << 4));
2961: char *argv = msdos_env_get_argv(env_seg);
2962: int done = 0;
2963:
2964: memcpy(src, dst, ENV_SIZE);
2965: memset(dst, 0, ENV_SIZE);
2966: while(1) {
2967: if(src[0] == 0) {
2968: break;
2969: }
2970: int len = strlen(src);
2971: char *n = my_strtok(src, "=");
2972: char *v = src + strlen(n) + 1;
2973: char tmp[1024];
2974:
2975: if(_stricmp(name, n) == 0) {
2976: sprintf(tmp, "%s=%s", n, value);
2977: done = 1;
2978: } else {
2979: sprintf(tmp, "%s=%s", n, v);
2980: }
2981: memcpy(dst, tmp, strlen(tmp));
2982: dst += strlen(tmp) + 1;
2983: src += len + 1;
2984: }
2985: if(!done) {
2986: char tmp[1024];
2987:
2988: sprintf(tmp, "%s=%s", name, value);
2989: memcpy(dst, tmp, strlen(tmp));
2990: dst += strlen(tmp) + 1;
2991: }
2992: if(argv) {
2993: *dst++ = 0; // end of environment
2994: *dst++ = 1; // top of argv[0]
2995: *dst++ = 0;
2996: memcpy(dst, argv, strlen(argv));
2997: dst += strlen(argv);
2998: *dst++ = 0;
2999: *dst++ = 0;
3000: }
3001: }
3002:
3003: // process
3004:
1.1.1.8 root 3005: psp_t *msdos_psp_create(int psp_seg, UINT16 mcb_seg, UINT16 parent_psp, UINT16 env_seg)
1.1 root 3006: {
3007: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
3008:
3009: memset(psp, 0, PSP_SIZE);
3010: psp->exit[0] = 0xcd;
3011: psp->exit[1] = 0x20;
1.1.1.8 root 3012: psp->first_mcb = mcb_seg;
1.1 root 3013: psp->far_call = 0xea;
3014: psp->cpm_entry.w.l = 0xfff1; // int 21h, retf
3015: psp->cpm_entry.w.h = 0xf000;
3016: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
3017: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
3018: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
3019: psp->parent_psp = parent_psp;
1.1.1.20 root 3020: if(parent_psp == (UINT16)-1) {
3021: for(int i = 0; i < 20; i++) {
3022: if(file_handler[i].valid) {
3023: psp->file_table[i] = i;
3024: } else {
3025: psp->file_table[i] = 0xff;
3026: }
1.1 root 3027: }
1.1.1.20 root 3028: } else {
3029: memcpy(psp->file_table, ((psp_t *)(mem + (parent_psp << 4)))->file_table, 20);
1.1 root 3030: }
3031: psp->env_seg = env_seg;
3032: psp->stack.w.l = REG16(SP);
1.1.1.3 root 3033: psp->stack.w.h = SREG(SS);
1.1.1.14 root 3034: psp->file_table_size = 20;
3035: psp->file_table_ptr.w.l = 0x18;
3036: psp->file_table_ptr.w.h = psp_seg;
1.1 root 3037: psp->service[0] = 0xcd;
3038: psp->service[1] = 0x21;
3039: psp->service[2] = 0xcb;
3040: return(psp);
3041: }
3042:
1.1.1.20 root 3043: void msdos_psp_set_file_table(int fd, UINT8 value, int psp_seg)
3044: {
3045: if(psp_seg && fd < 20) {
3046: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
3047: psp->file_table[fd] = value;
3048: }
3049: }
3050:
3051: int msdos_psp_get_file_table(int fd, int psp_seg)
3052: {
3053: if(psp_seg && fd < 20) {
3054: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
3055: fd = psp->file_table[fd];
3056: }
3057: return fd;
3058: }
3059:
1.1 root 3060: int msdos_process_exec(char *cmd, param_block_t *param, UINT8 al)
3061: {
3062: // load command file
3063: int fd = -1;
3064: int dos_command = 0;
1.1.1.24 root 3065: char command[MAX_PATH], path[MAX_PATH], opt[MAX_PATH], *name = NULL, name_tmp[MAX_PATH];
1.1 root 3066:
3067: int opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
3068: int opt_len = mem[opt_ofs];
3069: memset(opt, 0, sizeof(opt));
3070: memcpy(opt, mem + opt_ofs + 1, opt_len);
3071:
1.1.1.14 root 3072: if(strlen(cmd) >= 5 && _stricmp(&cmd[strlen(cmd) - 4], ".BAT") == 0) {
3073: // this is a batch file, run command.com
3074: char tmp[MAX_PATH];
3075: if(opt_len != 0) {
3076: sprintf(tmp, "/C %s %s", cmd, opt);
3077: } else {
3078: sprintf(tmp, "/C %s", cmd);
3079: }
3080: strcpy(opt, tmp);
3081: opt_len = strlen(opt);
3082: mem[opt_ofs] = opt_len;
3083: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
3084: strcpy(command, comspec_path);
3085: strcpy(name_tmp, "COMMAND.COM");
3086: } else {
3087: if(_stricmp(cmd, "C:\\COMMAND.COM") == 0) {
3088: // redirect C:\COMMAND.COM to comspec_path
3089: strcpy(command, comspec_path);
3090: } else {
3091: strcpy(command, cmd);
3092: }
1.1.1.24 root 3093: if(GetFullPathName(command, MAX_PATH, path, &name) == 0) {
3094: return(-1);
3095: }
1.1.1.14 root 3096: memset(name_tmp, 0, sizeof(name_tmp));
3097: strcpy(name_tmp, name);
3098:
3099: // check command.com
3100: if(_stricmp(name, "COMMAND.COM") == 0 || _stricmp(name, "COMMAND") == 0) {
3101: if(opt_len == 0) {
3102: // process_t *current_process = msdos_process_info_get(current_psp);
3103: process_t *current_process = NULL;
3104: for(int i = 0; i < MAX_PROCESS; i++) {
3105: if(process[i].psp == current_psp) {
3106: current_process = &process[i];
3107: break;
3108: }
3109: }
3110: if(current_process != NULL) {
3111: param->cmd_line.dw = current_process->dta.dw;
3112: opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
3113: opt_len = mem[opt_ofs];
3114: memset(opt, 0, sizeof(opt));
3115: memcpy(opt, mem + opt_ofs + 1, opt_len);
3116: }
3117: }
3118: for(int i = 0; i < opt_len; i++) {
3119: if(opt[i] == ' ') {
3120: continue;
3121: }
3122: if(opt[i] == '/' && (opt[i + 1] == 'c' || opt[i + 1] == 'C') && opt[i + 2] == ' ') {
3123: for(int j = i + 3; j < opt_len; j++) {
3124: if(opt[j] == ' ') {
3125: continue;
3126: }
3127: char *token = my_strtok(opt + j, " ");
3128:
3129: if(strlen(token) >= 5 && _stricmp(&token[strlen(token) - 4], ".BAT") == 0) {
3130: // this is a batch file, okay to run command.com
3131: } else {
3132: // run program directly without command.com
3133: strcpy(command, token);
3134: char tmp[MAX_PATH];
3135: strcpy(tmp, token + strlen(token) + 1);
3136: strcpy(opt, tmp);
3137: opt_len = strlen(opt);
3138: mem[opt_ofs] = opt_len;
3139: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
3140: dos_command = 1;
3141: }
3142: break;
1.1 root 3143: }
3144: }
1.1.1.14 root 3145: break;
1.1 root 3146: }
3147: }
3148: }
3149:
3150: // load command file
3151: strcpy(path, command);
3152: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
3153: sprintf(path, "%s.COM", command);
3154: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
3155: sprintf(path, "%s.EXE", command);
3156: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
1.1.1.14 root 3157: sprintf(path, "%s.BAT", command);
3158: if(_access(path, 0) == 0) {
3159: // this is a batch file, run command.com
3160: char tmp[MAX_PATH];
3161: if(opt_len != 0) {
3162: sprintf(tmp, "/C %s %s", path, opt);
3163: } else {
3164: sprintf(tmp, "/C %s", path);
3165: }
3166: strcpy(opt, tmp);
3167: opt_len = strlen(opt);
3168: mem[opt_ofs] = opt_len;
3169: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
3170: strcpy(path, comspec_path);
3171: strcpy(name_tmp, "COMMAND.COM");
3172: fd = _open(path, _O_RDONLY | _O_BINARY);
3173: } else {
3174: // search path in parent environments
3175: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
3176: char *env = msdos_env_get(parent_psp->env_seg, "PATH");
3177: if(env != NULL) {
3178: char env_path[4096];
3179: strcpy(env_path, env);
3180: char *token = my_strtok(env_path, ";");
3181:
3182: while(token != NULL) {
3183: if(strlen(token) != 0) {
3184: sprintf(path, "%s", msdos_combine_path(token, command));
3185: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
3186: break;
3187: }
3188: sprintf(path, "%s.COM", msdos_combine_path(token, command));
3189: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
3190: break;
3191: }
3192: sprintf(path, "%s.EXE", msdos_combine_path(token, command));
3193: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
3194: break;
3195: }
3196: sprintf(path, "%s.BAT", msdos_combine_path(token, command));
3197: if(_access(path, 0) == 0) {
3198: // this is a batch file, run command.com
3199: char tmp[MAX_PATH];
3200: if(opt_len != 0) {
3201: sprintf(tmp, "/C %s %s", path, opt);
3202: } else {
3203: sprintf(tmp, "/C %s", path);
3204: }
3205: strcpy(opt, tmp);
3206: opt_len = strlen(opt);
3207: mem[opt_ofs] = opt_len;
3208: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
3209: strcpy(path, comspec_path);
3210: strcpy(name_tmp, "COMMAND.COM");
3211: fd = _open(path, _O_RDONLY | _O_BINARY);
3212: break;
3213: }
1.1.1.8 root 3214: }
1.1.1.14 root 3215: token = my_strtok(NULL, ";");
1.1 root 3216: }
3217: }
3218: }
3219: }
3220: }
3221: }
3222: if(fd == -1) {
3223: if(dos_command) {
3224: // may be dos command
3225: char tmp[MAX_PATH];
3226: sprintf(tmp, "%s %s", command, opt);
3227: system(tmp);
3228: return(0);
3229: } else {
3230: return(-1);
3231: }
3232: }
3233: _read(fd, file_buffer, sizeof(file_buffer));
3234: _close(fd);
3235:
3236: // copy environment
3237: int env_seg, psp_seg;
3238:
1.1.1.8 root 3239: if((env_seg = msdos_mem_alloc(first_mcb, ENV_SIZE >> 4, 1)) == -1) {
1.1 root 3240: return(-1);
3241: }
3242: if(param->env_seg == 0) {
3243: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
3244: memcpy(mem + (env_seg << 4), mem + (parent_psp->env_seg << 4), ENV_SIZE);
3245: } else {
3246: memcpy(mem + (env_seg << 4), mem + (param->env_seg << 4), ENV_SIZE);
3247: }
3248: msdos_env_set_argv(env_seg, msdos_short_full_path(path));
3249:
3250: // check exe header
3251: exe_header_t *header = (exe_header_t *)file_buffer;
1.1.1.8 root 3252: int paragraphs, free_paragraphs = msdos_mem_get_free(first_mcb, 1);
1.1 root 3253: UINT16 cs, ss, ip, sp;
3254:
3255: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
3256: // memory allocation
3257: int header_size = header->header_size * 16;
3258: int load_size = header->pages * 512 - header_size;
3259: if(header_size + load_size < 512) {
3260: load_size = 512 - header_size;
3261: }
3262: paragraphs = (PSP_SIZE + load_size) >> 4;
3263: if(paragraphs + header->min_alloc > free_paragraphs) {
3264: msdos_mem_free(env_seg);
3265: return(-1);
3266: }
3267: paragraphs += header->max_alloc ? header->max_alloc : header->min_alloc;
3268: if(paragraphs > free_paragraphs) {
3269: paragraphs = free_paragraphs;
3270: }
1.1.1.8 root 3271: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1 root 3272: msdos_mem_free(env_seg);
3273: return(-1);
3274: }
3275: // relocation
3276: int start_seg = psp_seg + (PSP_SIZE >> 4);
3277: for(int i = 0; i < header->relocations; i++) {
3278: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
3279: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
3280: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
3281: }
3282: memcpy(mem + (start_seg << 4), file_buffer + header_size, load_size);
3283: // segments
3284: cs = header->init_cs + start_seg;
3285: ss = header->init_ss + start_seg;
3286: ip = header->init_ip;
3287: sp = header->init_sp - 2; // for symdeb
3288: } else {
3289: // memory allocation
3290: paragraphs = free_paragraphs;
1.1.1.8 root 3291: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1 root 3292: msdos_mem_free(env_seg);
3293: return(-1);
3294: }
3295: int start_seg = psp_seg + (PSP_SIZE >> 4);
3296: memcpy(mem + (start_seg << 4), file_buffer, 0x10000 - PSP_SIZE);
3297: // segments
3298: cs = ss = psp_seg;
3299: ip = 0x100;
3300: sp = 0xfffe;
3301: }
3302:
3303: // create psp
1.1.1.3 root 3304: #if defined(HAS_I386)
3305: *(UINT16 *)(mem + 4 * 0x22 + 0) = m_eip;
3306: #else
3307: *(UINT16 *)(mem + 4 * 0x22 + 0) = m_pc - SREG_BASE(CS);
3308: #endif
3309: *(UINT16 *)(mem + 4 * 0x22 + 2) = SREG(CS);
1.1 root 3310: psp_t *psp = msdos_psp_create(psp_seg, psp_seg + paragraphs, current_psp, env_seg);
3311: memcpy(psp->fcb1, mem + (param->fcb1.w.h << 4) + param->fcb1.w.l, sizeof(psp->fcb1));
3312: memcpy(psp->fcb2, mem + (param->fcb2.w.h << 4) + param->fcb2.w.l, sizeof(psp->fcb2));
3313: memcpy(psp->buffer, mem + (param->cmd_line.w.h << 4) + param->cmd_line.w.l, sizeof(psp->buffer));
3314:
3315: mcb_t *mcb_env = (mcb_t *)(mem + ((env_seg - 1) << 4));
3316: mcb_t *mcb_psp = (mcb_t *)(mem + ((psp_seg - 1) << 4));
3317: mcb_psp->psp = mcb_env->psp = psp_seg;
3318:
1.1.1.4 root 3319: for(int i = 0; i < 8; i++) {
3320: if(name_tmp[i] == '.') {
3321: mcb_psp->prog_name[i] = '\0';
3322: break;
3323: } else if(i < 7 && msdos_lead_byte_check(name_tmp[i])) {
3324: mcb_psp->prog_name[i] = name_tmp[i];
3325: i++;
3326: mcb_psp->prog_name[i] = name_tmp[i];
3327: } else if(name_tmp[i] >= 'a' && name_tmp[i] <= 'z') {
3328: mcb_psp->prog_name[i] = name_tmp[i] - 'a' + 'A';
3329: } else {
3330: mcb_psp->prog_name[i] = name_tmp[i];
3331: }
3332: }
3333:
1.1 root 3334: // process info
3335: process_t *process = msdos_process_info_create(psp_seg);
3336: strcpy(process->module_dir, msdos_short_full_dir(path));
3337: process->dta.w.l = 0x80;
3338: process->dta.w.h = psp_seg;
3339: process->switchar = '/';
3340: process->max_files = 20;
3341: process->parent_int_10h_feh_called = int_10h_feh_called;
3342: process->parent_int_10h_ffh_called = int_10h_ffh_called;
1.1.1.14 root 3343: process->parent_ds = SREG(DS);
1.1 root 3344:
3345: current_psp = psp_seg;
1.1.1.23 root 3346: msdos_sda_update(current_psp);
1.1 root 3347:
3348: if(al == 0x00) {
3349: int_10h_feh_called = int_10h_ffh_called = false;
3350:
3351: // registers and segments
3352: REG16(AX) = REG16(BX) = 0x00;
3353: REG16(CX) = 0xff;
3354: REG16(DX) = psp_seg;
3355: REG16(SI) = ip;
3356: REG16(DI) = sp;
3357: REG16(SP) = sp;
1.1.1.3 root 3358: SREG(DS) = SREG(ES) = psp_seg;
3359: SREG(SS) = ss;
3360: i386_load_segment_descriptor(DS);
3361: i386_load_segment_descriptor(ES);
3362: i386_load_segment_descriptor(SS);
1.1 root 3363:
3364: *(UINT16 *)(mem + (ss << 4) + sp) = 0;
3365: i386_jmp_far(cs, ip);
3366: } else if(al == 0x01) {
3367: // copy ss:sp and cs:ip to param block
3368: param->sp = sp;
3369: param->ss = ss;
3370: param->ip = ip;
3371: param->cs = cs;
3372: }
3373: return(0);
3374: }
3375:
3376: void msdos_process_terminate(int psp_seg, int ret, int mem_free)
3377: {
3378: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
3379:
3380: *(UINT32 *)(mem + 4 * 0x22) = psp->int_22h.dw;
3381: *(UINT32 *)(mem + 4 * 0x23) = psp->int_23h.dw;
3382: *(UINT32 *)(mem + 4 * 0x24) = psp->int_24h.dw;
3383:
1.1.1.3 root 3384: SREG(SS) = psp->stack.w.h;
3385: i386_load_segment_descriptor(SS);
1.1 root 3386: REG16(SP) = psp->stack.w.l;
3387: i386_jmp_far(psp->int_22h.w.h, psp->int_22h.w.l);
3388:
3389: process_t *process = msdos_process_info_get(psp_seg);
3390: int_10h_feh_called = process->parent_int_10h_feh_called;
3391: int_10h_ffh_called = process->parent_int_10h_ffh_called;
1.1.1.14 root 3392: SREG(DS) = process->parent_ds;
3393: i386_load_segment_descriptor(DS);
1.1 root 3394:
3395: if(mem_free) {
1.1.1.8 root 3396: int mcb_seg;
3397: while((mcb_seg = msdos_mem_get_last_mcb(first_mcb, psp_seg)) != -1) {
3398: msdos_mem_free(mcb_seg + 1);
3399: }
3400: while((mcb_seg = msdos_mem_get_last_mcb(UMB_TOP >> 4, psp_seg)) != -1) {
3401: msdos_mem_free(mcb_seg + 1);
3402: }
1.1 root 3403:
3404: for(int i = 0; i < MAX_FILES; i++) {
3405: if(file_handler[i].valid && file_handler[i].psp == psp_seg) {
3406: _close(i);
1.1.1.20 root 3407: msdos_file_handler_close(i);
3408: msdos_psp_set_file_table(i, 0x0ff, psp_seg); // FIXME: consider duplicated file handles
1.1 root 3409: }
3410: }
1.1.1.13 root 3411: msdos_dta_info_free(psp_seg);
1.1 root 3412: }
1.1.1.14 root 3413: msdos_stdio_reopen();
1.1 root 3414:
3415: memset(process, 0, sizeof(process_t));
3416:
3417: current_psp = psp->parent_psp;
3418: retval = ret;
1.1.1.23 root 3419: msdos_sda_update(current_psp);
1.1 root 3420: }
3421:
3422: // drive
3423:
3424: int msdos_drive_param_block_update(int drive_num, UINT16 *seg, UINT16 *ofs, int force_update)
3425: {
3426: *seg = DPB_TOP >> 4;
3427: *ofs = sizeof(dpb_t) * drive_num;
3428: dpb_t *dpb = (dpb_t *)(mem + (*seg << 4) + *ofs);
3429:
3430: if(!force_update && dpb->free_clusters != 0) {
3431: return(dpb->bytes_per_sector ? 1 : 0);
3432: }
3433: memset(dpb, 0, sizeof(dpb_t));
3434:
3435: int res = 0;
3436: char dev[64];
3437: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num);
3438:
1.1.1.17 root 3439: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1.1 root 3440: if(hFile != INVALID_HANDLE_VALUE) {
3441: DISK_GEOMETRY geo;
3442: DWORD dwSize;
3443: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
3444: dpb->bytes_per_sector = (UINT16)geo.BytesPerSector;
3445: dpb->highest_sector_num = (UINT8)(geo.SectorsPerTrack - 1);
3446: dpb->highest_cluster_num = (UINT16)(geo.TracksPerCylinder * geo.Cylinders.QuadPart + 1);
1.1.1.14 root 3447: dpb->maximum_cluster_num = (UINT32)(geo.TracksPerCylinder * geo.Cylinders.QuadPart + 1);
1.1 root 3448: switch(geo.MediaType) {
3449: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K)
3450: dpb->media_type = 0xff;
3451: break;
3452: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K)
3453: dpb->media_type = 0xfe;
3454: break;
3455: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K)
3456: dpb->media_type = 0xfd;
3457: break;
3458: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K)
3459: dpb->media_type = 0xfc;
3460: break;
3461: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M)
3462: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5")
3463: dpb->media_type = 0xf9;
3464: break;
3465: case FixedMedia: // hard disk
3466: case RemovableMedia:
1.1.1.19 root 3467: case Unknown:
1.1 root 3468: dpb->media_type = 0xf8;
3469: break;
3470: default:
3471: dpb->media_type = 0xf0;
3472: break;
3473: }
3474: res = 1;
3475: }
3476: dpb->drive_num = drive_num;
3477: dpb->unit_num = drive_num;
3478: dpb->next_dpb_ofs = *ofs + sizeof(dpb_t);
3479: dpb->next_dpb_seg = *seg;
1.1.1.14 root 3480: dpb->info_sector = 0xffff;
3481: dpb->backup_boot_sector = 0xffff;
1.1 root 3482: dpb->free_clusters = 0xffff;
1.1.1.14 root 3483: dpb->free_search_cluster = 0xffffffff;
1.1 root 3484: CloseHandle(hFile);
3485: }
3486: return(res);
3487: }
3488:
3489: // pc bios
3490:
1.1.1.19 root 3491: UINT32 get_ticks_since_midnight(UINT32 cur_msec)
3492: {
3493: static unsigned __int64 start_msec_since_midnight = 0;
3494: static unsigned __int64 start_msec_since_hostboot = 0;
3495:
3496: if(start_msec_since_midnight == 0) {
3497: SYSTEMTIME time;
3498: GetLocalTime(&time);
3499: start_msec_since_midnight = ((time.wHour * 60 + time.wMinute) * 60 + time.wSecond) * 1000 + time.wMilliseconds;
3500: start_msec_since_hostboot = cur_msec;
3501: }
3502: unsigned __int64 msec = (start_msec_since_midnight + cur_msec - start_msec_since_hostboot) % (24 * 60 * 60 * 1000);
3503: unsigned __int64 tick = msec * 0x1800b0 / (24 * 60 * 60 * 1000);
3504: return (UINT32)tick;
3505: }
3506:
3507: void pcbios_update_daily_timer_counter(UINT32 cur_msec)
3508: {
3509: UINT32 prev_tick = *(UINT32 *)(mem + 0x46c);
3510: UINT32 next_tick = get_ticks_since_midnight(cur_msec);
3511:
3512: if(prev_tick > next_tick) {
3513: mem[0x470] = 1;
3514: }
3515: *(UINT32 *)(mem + 0x46c) = next_tick;
3516: }
3517:
1.1.1.14 root 3518: inline void pcbios_irq0()
3519: {
3520: //++*(UINT32 *)(mem + 0x46c);
1.1.1.19 root 3521: pcbios_update_daily_timer_counter(timeGetTime());
1.1.1.14 root 3522: }
3523:
1.1.1.16 root 3524: int pcbios_get_text_vram_address(int page)
1.1 root 3525: {
3526: if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 3527: return TEXT_VRAM_TOP;
1.1 root 3528: } else {
1.1.1.14 root 3529: return TEXT_VRAM_TOP + VIDEO_REGEN * (page % vram_pages);
1.1 root 3530: }
3531: }
3532:
1.1.1.16 root 3533: int pcbios_get_shadow_buffer_address(int page)
1.1 root 3534: {
1.1.1.14 root 3535: if(!int_10h_feh_called) {
1.1.1.16 root 3536: return pcbios_get_text_vram_address(page);
1.1.1.14 root 3537: } else if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 3538: return SHADOW_BUF_TOP;
3539: } else {
1.1.1.14 root 3540: return SHADOW_BUF_TOP + VIDEO_REGEN * (page % vram_pages);
1.1.1.8 root 3541: }
3542: }
3543:
1.1.1.16 root 3544: int pcbios_get_shadow_buffer_address(int page, int x, int y)
1.1.1.8 root 3545: {
1.1.1.16 root 3546: return pcbios_get_shadow_buffer_address(page) + (x + y * scr_width) * 2;
1.1 root 3547: }
3548:
1.1.1.16 root 3549: void pcbios_set_console_size(int width, int height, bool clr_screen)
1.1 root 3550: {
1.1.1.14 root 3551: // clear the existing screen, not just the new one
3552: int clr_height = max(height, scr_height);
3553:
1.1.1.16 root 3554: if(scr_width != width || scr_height != height) {
3555: change_console_size(width, height);
1.1.1.14 root 3556: }
3557: mem[0x462] = 0;
3558: *(UINT16 *)(mem + 0x44e) = 0;
3559:
1.1.1.16 root 3560: text_vram_top_address = pcbios_get_text_vram_address(0);
3561: text_vram_end_address = text_vram_top_address + width * height * 2;
3562: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(0);
3563: shadow_buffer_end_address = shadow_buffer_top_address + width * height * 2;
1.1 root 3564:
1.1.1.23 root 3565: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.16 root 3566: if(clr_screen) {
1.1.1.14 root 3567: for(int ofs = shadow_buffer_top_address; ofs < shadow_buffer_end_address;) {
3568: mem[ofs++] = 0x20;
3569: mem[ofs++] = 0x07;
3570: }
3571:
3572: EnterCriticalSection(&vram_crit_sect);
3573: for(int y = 0; y < clr_height; y++) {
3574: for(int x = 0; x < scr_width; x++) {
3575: SCR_BUF(y,x).Char.AsciiChar = ' ';
3576: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
1.1 root 3577: }
3578: }
3579: SMALL_RECT rect;
1.1.1.14 root 3580: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + clr_height - 1);
3581: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
3582: vram_length_char = vram_last_length_char = 0;
3583: vram_length_attr = vram_last_length_attr = 0;
3584: LeaveCriticalSection(&vram_crit_sect);
1.1 root 3585: }
1.1.1.14 root 3586: COORD co;
3587: co.X = 0;
3588: co.Y = scr_top;
3589: SetConsoleCursorPosition(hStdout, co);
3590: cursor_moved = true;
3591: SetConsoleTextAttribute(hStdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
1.1 root 3592: }
3593:
1.1.1.16 root 3594: inline void pcbios_int_10h_00h()
3595: {
3596: switch(REG8(AL) & 0x7f) {
3597: case 0x70: // v-text mode
3598: case 0x71: // extended cga v-text mode
3599: pcbios_set_console_size(scr_width, scr_height, !(REG8(AL) & 0x80));
3600: break;
3601: default:
3602: pcbios_set_console_size(80, 25, !(REG8(AL) & 0x80));
3603: break;
3604: }
3605: if(REG8(AL) & 0x80) {
3606: mem[0x487] |= 0x80;
3607: } else {
3608: mem[0x487] &= ~0x80;
3609: }
3610: mem[0x449] = REG8(AL) & 0x7f;
3611: }
3612:
1.1 root 3613: inline void pcbios_int_10h_01h()
3614: {
1.1.1.13 root 3615: mem[0x460] = REG8(CL);
3616: mem[0x461] = REG8(CH);
1.1.1.14 root 3617:
1.1.1.23 root 3618: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 3619: CONSOLE_CURSOR_INFO ci;
3620: GetConsoleCursorInfo(hStdout, &ci);
3621: // ci.bVisible = !(REG8(CH) & 0x60) && REG8(CH) <= REG8(CL);
3622: // if(ci.bVisible) {
3623: int lines = max(8, REG8(CL) + 1);
3624: ci.dwSize = (REG8(CL) - REG8(CH) + 1) * 100 / lines;
3625: // }
3626: SetConsoleCursorInfo(hStdout, &ci);
1.1 root 3627: }
3628:
3629: inline void pcbios_int_10h_02h()
3630: {
1.1.1.14 root 3631: // continuously setting the cursor effectively stops it blinking
3632: if(mem[0x462] == REG8(BH) && (REG8(DL) != mem[0x450 + REG8(BH) * 2] || REG8(DH) != mem[0x451 + REG8(BH) * 2])) {
1.1 root 3633: COORD co;
3634: co.X = REG8(DL);
1.1.1.14 root 3635: co.Y = REG8(DH) + scr_top;
3636:
3637: // some programs hide the cursor by moving it off screen
3638: static bool hidden = false;
1.1.1.23 root 3639: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 3640: CONSOLE_CURSOR_INFO ci;
3641: GetConsoleCursorInfo(hStdout, &ci);
3642:
3643: if(REG8(DH) >= scr_height || !SetConsoleCursorPosition(hStdout, co)) {
3644: if(ci.bVisible) {
3645: ci.bVisible = FALSE;
3646: // SetConsoleCursorInfo(hStdout, &ci);
3647: hidden = true;
3648: }
3649: } else if(hidden) {
3650: if(!ci.bVisible) {
3651: ci.bVisible = TRUE;
3652: // SetConsoleCursorInfo(hStdout, &ci);
3653: }
3654: hidden = false;
3655: }
1.1 root 3656: }
1.1.1.14 root 3657: mem[0x450 + (REG8(BH) % vram_pages) * 2] = REG8(DL);
3658: mem[0x451 + (REG8(BH) % vram_pages) * 2] = REG8(DH);
1.1 root 3659: }
3660:
3661: inline void pcbios_int_10h_03h()
3662: {
1.1.1.14 root 3663: REG8(DL) = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3664: REG8(DH) = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 3665: REG8(CL) = mem[0x460];
3666: REG8(CH) = mem[0x461];
3667: }
3668:
3669: inline void pcbios_int_10h_05h()
3670: {
1.1.1.14 root 3671: if(REG8(AL) >= vram_pages) {
3672: return;
3673: }
3674: if(mem[0x462] != REG8(AL)) {
3675: vram_flush();
3676:
1.1.1.23 root 3677: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 3678: SMALL_RECT rect;
1.1.1.14 root 3679: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
3680: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3681:
1.1.1.16 root 3682: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(mem[0x462]); y < scr_height; y++) {
1.1.1.14 root 3683: for(int x = 0; x < scr_width; x++) {
3684: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
3685: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 3686: }
3687: }
1.1.1.16 root 3688: for(int y = 0, ofs = pcbios_get_shadow_buffer_address(REG8(AL)); y < scr_height; y++) {
1.1.1.14 root 3689: for(int x = 0; x < scr_width; x++) {
3690: SCR_BUF(y,x).Char.AsciiChar = mem[ofs++];
3691: SCR_BUF(y,x).Attributes = mem[ofs++];
1.1 root 3692: }
3693: }
1.1.1.14 root 3694: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3695:
3696: COORD co;
1.1.1.14 root 3697: co.X = mem[0x450 + REG8(AL) * 2];
3698: co.Y = mem[0x451 + REG8(AL) * 2] + scr_top;
3699: if(co.Y < scr_top + scr_height) {
3700: SetConsoleCursorPosition(hStdout, co);
3701: }
1.1 root 3702: }
1.1.1.14 root 3703: mem[0x462] = REG8(AL);
3704: *(UINT16 *)(mem + 0x44e) = REG8(AL) * VIDEO_REGEN;
3705: int regen = min(scr_width * scr_height * 2, 0x8000);
1.1.1.16 root 3706: text_vram_top_address = pcbios_get_text_vram_address(mem[0x462]);
1.1.1.14 root 3707: text_vram_end_address = text_vram_top_address + regen;
1.1.1.16 root 3708: shadow_buffer_top_address = pcbios_get_shadow_buffer_address(mem[0x462]);
1.1.1.14 root 3709: shadow_buffer_end_address = shadow_buffer_top_address + regen;
1.1 root 3710: }
3711:
3712: inline void pcbios_int_10h_06h()
3713: {
1.1.1.14 root 3714: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
3715: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
3716: return;
3717: }
3718: vram_flush();
3719:
1.1.1.23 root 3720: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 3721: SMALL_RECT rect;
1.1.1.14 root 3722: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
3723: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
3724:
3725: int right = min(REG8(DL), scr_width - 1);
3726: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 3727:
3728: if(REG8(AL) == 0) {
1.1.1.14 root 3729: for(int y = REG8(CH); y <= bottom; y++) {
1.1.1.16 root 3730: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 3731: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
3732: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3733: }
3734: }
3735: } else {
1.1.1.14 root 3736: for(int y = REG8(CH), y2 = min(REG8(CH) + REG8(AL), bottom + 1); y <= bottom; y++, y2++) {
1.1.1.16 root 3737: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 3738: if(y2 <= bottom) {
3739: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 3740: } else {
1.1.1.14 root 3741: SCR_BUF(y,x).Char.AsciiChar = ' ';
3742: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3743: }
1.1.1.14 root 3744: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
3745: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 3746: }
3747: }
3748: }
1.1.1.14 root 3749: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3750: }
3751:
3752: inline void pcbios_int_10h_07h()
3753: {
1.1.1.14 root 3754: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
3755: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
3756: return;
3757: }
3758: vram_flush();
3759:
1.1.1.23 root 3760: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 3761: SMALL_RECT rect;
1.1.1.14 root 3762: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
3763: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
3764:
3765: int right = min(REG8(DL), scr_width - 1);
3766: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 3767:
3768: if(REG8(AL) == 0) {
1.1.1.14 root 3769: for(int y = REG8(CH); y <= bottom; y++) {
1.1.1.16 root 3770: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 3771: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
3772: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3773: }
3774: }
3775: } else {
1.1.1.14 root 3776: for(int y = bottom, y2 = max(REG8(CH) - 1, bottom - REG8(AL)); y >= REG8(CH); y--, y2--) {
1.1.1.16 root 3777: for(int x = REG8(CL), ofs = pcbios_get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
1.1.1.14 root 3778: if(y2 >= REG8(CH)) {
3779: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 3780: } else {
1.1.1.14 root 3781: SCR_BUF(y,x).Char.AsciiChar = ' ';
3782: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3783: }
1.1.1.14 root 3784: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
3785: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 3786: }
3787: }
3788: }
1.1.1.14 root 3789: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3790: }
3791:
3792: inline void pcbios_int_10h_08h()
3793: {
3794: COORD co;
3795: DWORD num;
3796:
1.1.1.14 root 3797: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3798: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 3799:
3800: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 3801: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 3802: co.Y += scr_top;
3803: vram_flush();
1.1 root 3804: ReadConsoleOutputCharacter(hStdout, scr_char, 1, co, &num);
3805: ReadConsoleOutputAttribute(hStdout, scr_attr, 1, co, &num);
3806: REG8(AL) = scr_char[0];
3807: REG8(AH) = scr_attr[0];
3808: } else {
1.1.1.16 root 3809: REG16(AX) = *(UINT16 *)(mem + pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y));
1.1 root 3810: }
3811: }
3812:
3813: inline void pcbios_int_10h_09h()
3814: {
3815: COORD co;
3816:
1.1.1.14 root 3817: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3818: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
3819:
1.1.1.16 root 3820: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
3821: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 3822:
3823: if(mem[0x462] == REG8(BH)) {
1.1.1.14 root 3824: EnterCriticalSection(&vram_crit_sect);
1.1.1.16 root 3825: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 3826: while(dest < end) {
3827: write_text_vram_char(dest - vram, REG8(AL));
3828: mem[dest++] = REG8(AL);
3829: write_text_vram_attr(dest - vram, REG8(BL));
3830: mem[dest++] = REG8(BL);
1.1 root 3831: }
1.1.1.14 root 3832: LeaveCriticalSection(&vram_crit_sect);
1.1 root 3833: } else {
1.1.1.14 root 3834: while(dest < end) {
1.1 root 3835: mem[dest++] = REG8(AL);
3836: mem[dest++] = REG8(BL);
3837: }
3838: }
3839: }
3840:
3841: inline void pcbios_int_10h_0ah()
3842: {
3843: COORD co;
3844:
1.1.1.14 root 3845: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3846: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
3847:
1.1.1.16 root 3848: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
3849: int end = min(dest + REG16(CX) * 2, pcbios_get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 3850:
3851: if(mem[0x462] == REG8(BH)) {
1.1.1.14 root 3852: EnterCriticalSection(&vram_crit_sect);
1.1.1.16 root 3853: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 3854: while(dest < end) {
3855: write_text_vram_char(dest - vram, REG8(AL));
3856: mem[dest++] = REG8(AL);
3857: dest++;
1.1 root 3858: }
1.1.1.14 root 3859: LeaveCriticalSection(&vram_crit_sect);
1.1 root 3860: } else {
1.1.1.14 root 3861: while(dest < end) {
1.1 root 3862: mem[dest++] = REG8(AL);
3863: dest++;
3864: }
3865: }
3866: }
3867:
3868: inline void pcbios_int_10h_0eh()
3869: {
1.1.1.14 root 3870: DWORD num;
3871: COORD co;
3872:
3873: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3874: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
3875:
3876: if(REG8(AL) == 7) {
3877: //MessageBeep(-1);
3878: } else if(REG8(AL) == 8 || REG8(AL) == 10 || REG8(AL) == 13) {
3879: if(REG8(AL) == 10) {
3880: vram_flush();
3881: }
1.1.1.23 root 3882: WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ®8(AL), 1, &num, NULL);
1.1.1.14 root 3883: cursor_moved = true;
3884: } else {
1.1.1.16 root 3885: int dest = pcbios_get_shadow_buffer_address(REG8(BH), co.X, co.Y);
1.1.1.14 root 3886: if(mem[0x462] == REG8(BH)) {
3887: EnterCriticalSection(&vram_crit_sect);
1.1.1.16 root 3888: int vram = pcbios_get_shadow_buffer_address(REG8(BH));
1.1.1.14 root 3889: write_text_vram_char(dest - vram, REG8(AL));
3890: LeaveCriticalSection(&vram_crit_sect);
3891:
1.1.1.23 root 3892: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 3893: if(++co.X == scr_width) {
3894: co.X = 0;
3895: if(++co.Y == scr_height) {
3896: vram_flush();
3897: WriteConsole(hStdout, "\n", 1, &num, NULL);
3898: cursor_moved = true;
3899: }
3900: }
3901: if(!cursor_moved) {
3902: co.Y += scr_top;
3903: SetConsoleCursorPosition(hStdout, co);
3904: cursor_moved = true;
3905: }
3906: }
3907: mem[dest] = REG8(AL);
3908: }
1.1 root 3909: }
3910:
3911: inline void pcbios_int_10h_0fh()
3912: {
3913: REG8(AL) = mem[0x449];
3914: REG8(AH) = mem[0x44a];
3915: REG8(BH) = mem[0x462];
3916: }
3917:
1.1.1.14 root 3918: inline void pcbios_int_10h_11h()
3919: {
3920: switch(REG8(AL)) {
1.1.1.16 root 3921: case 0x01:
1.1.1.14 root 3922: case 0x11:
1.1.1.16 root 3923: pcbios_set_console_size(80, 28, true);
1.1.1.14 root 3924: break;
1.1.1.16 root 3925: case 0x02:
1.1.1.14 root 3926: case 0x12:
1.1.1.16 root 3927: pcbios_set_console_size(80, 50, true);
1.1.1.14 root 3928: break;
1.1.1.16 root 3929: case 0x04:
1.1.1.14 root 3930: case 0x14:
1.1.1.16 root 3931: pcbios_set_console_size(80, 25, true);
3932: break;
3933: case 0x18:
3934: pcbios_set_console_size(80, 50, true);
1.1.1.14 root 3935: break;
3936: case 0x30:
3937: SREG(ES) = 0;
3938: i386_load_segment_descriptor(ES);
3939: REG16(BP) = 0;
3940: REG16(CX) = mem[0x485];
3941: REG8(DL) = mem[0x484];
3942: break;
3943: }
3944: }
3945:
3946: inline void pcbios_int_10h_12h()
3947: {
1.1.1.16 root 3948: switch(REG8(BL)) {
3949: case 0x10:
1.1.1.14 root 3950: REG16(BX) = 0x0003;
3951: REG16(CX) = 0x0009;
1.1.1.16 root 3952: break;
1.1.1.14 root 3953: }
3954: }
3955:
1.1 root 3956: inline void pcbios_int_10h_13h()
3957: {
1.1.1.3 root 3958: int ofs = SREG_BASE(ES) + REG16(BP);
1.1 root 3959: COORD co;
3960: DWORD num;
3961:
3962: co.X = REG8(DL);
1.1.1.14 root 3963: co.Y = REG8(DH) + scr_top;
3964:
3965: vram_flush();
1.1 root 3966:
3967: switch(REG8(AL)) {
3968: case 0x00:
3969: case 0x01:
3970: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 3971: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 3972: CONSOLE_SCREEN_BUFFER_INFO csbi;
3973: GetConsoleScreenBufferInfo(hStdout, &csbi);
3974: SetConsoleCursorPosition(hStdout, co);
3975:
3976: if(csbi.wAttributes != REG8(BL)) {
3977: SetConsoleTextAttribute(hStdout, REG8(BL));
3978: }
1.1.1.14 root 3979: WriteConsole(hStdout, &mem[ofs], REG16(CX), &num, NULL);
3980:
1.1 root 3981: if(csbi.wAttributes != REG8(BL)) {
3982: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
3983: }
3984: if(REG8(AL) == 0x00) {
1.1.1.15 root 3985: if(!restore_console_on_exit) {
3986: GetConsoleScreenBufferInfo(hStdout, &csbi);
3987: scr_top = csbi.srWindow.Top;
3988: }
1.1.1.14 root 3989: co.X = mem[0x450 + REG8(BH) * 2];
3990: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 3991: SetConsoleCursorPosition(hStdout, co);
3992: } else {
3993: cursor_moved = true;
3994: }
3995: } else {
1.1.1.3 root 3996: m_CF = 1;
1.1 root 3997: }
3998: break;
3999: case 0x02:
4000: case 0x03:
4001: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 4002: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 4003: CONSOLE_SCREEN_BUFFER_INFO csbi;
4004: GetConsoleScreenBufferInfo(hStdout, &csbi);
4005: SetConsoleCursorPosition(hStdout, co);
4006:
4007: WORD wAttributes = csbi.wAttributes;
4008: for(int i = 0; i < REG16(CX); i++, ofs += 2) {
4009: if(wAttributes != mem[ofs + 1]) {
4010: SetConsoleTextAttribute(hStdout, mem[ofs + 1]);
4011: wAttributes = mem[ofs + 1];
4012: }
1.1.1.14 root 4013: WriteConsole(hStdout, &mem[ofs], 1, &num, NULL);
1.1 root 4014: }
4015: if(csbi.wAttributes != wAttributes) {
4016: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
4017: }
4018: if(REG8(AL) == 0x02) {
1.1.1.14 root 4019: co.X = mem[0x450 + REG8(BH) * 2];
4020: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 4021: SetConsoleCursorPosition(hStdout, co);
4022: } else {
4023: cursor_moved = true;
4024: }
4025: } else {
1.1.1.3 root 4026: m_CF = 1;
1.1 root 4027: }
4028: break;
4029: case 0x10:
4030: case 0x11:
4031: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 4032: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 4033: ReadConsoleOutputCharacter(hStdout, scr_char, REG16(CX), co, &num);
4034: ReadConsoleOutputAttribute(hStdout, scr_attr, REG16(CX), co, &num);
4035: for(int i = 0; i < num; i++) {
4036: mem[ofs++] = scr_char[i];
4037: mem[ofs++] = scr_attr[i];
4038: if(REG8(AL) == 0x11) {
4039: mem[ofs++] = 0;
4040: mem[ofs++] = 0;
4041: }
4042: }
4043: } else {
1.1.1.16 root 4044: 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 4045: mem[ofs++] = mem[src++];
4046: mem[ofs++] = mem[src++];
4047: if(REG8(AL) == 0x11) {
4048: mem[ofs++] = 0;
4049: mem[ofs++] = 0;
4050: }
1.1.1.14 root 4051: if(++co.X == scr_width) {
4052: if(++co.Y == scr_height) {
1.1 root 4053: break;
4054: }
4055: co.X = 0;
4056: }
4057: }
4058: }
4059: break;
4060: case 0x20:
4061: case 0x21:
4062: if(mem[0x462] == REG8(BH)) {
1.1.1.23 root 4063: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.14 root 4064: int len = min(REG16(CX), scr_width * scr_height);
4065: for(int i = 0; i < len; i++) {
1.1 root 4066: scr_char[i] = mem[ofs++];
4067: scr_attr[i] = mem[ofs++];
4068: if(REG8(AL) == 0x21) {
4069: ofs += 2;
4070: }
4071: }
1.1.1.14 root 4072: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
4073: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 4074: } else {
1.1.1.16 root 4075: 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 4076: mem[dest++] = mem[ofs++];
4077: mem[dest++] = mem[ofs++];
4078: if(REG8(AL) == 0x21) {
4079: ofs += 2;
4080: }
1.1.1.14 root 4081: if(++co.X == scr_width) {
4082: if(++co.Y == scr_height) {
1.1 root 4083: break;
4084: }
4085: co.X = 0;
4086: }
4087: }
4088: }
4089: break;
4090: default:
1.1.1.22 root 4091: 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 4092: m_CF = 1;
1.1 root 4093: break;
4094: }
4095: }
4096:
1.1.1.14 root 4097: inline void pcbios_int_10h_1ah()
4098: {
4099: switch(REG8(AL)) {
4100: case 0x00:
4101: REG8(AL) = 0x1a;
4102: REG8(BL) = 0x08;
4103: REG8(BH) = 0x00;
4104: break;
4105: default:
1.1.1.22 root 4106: 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 4107: m_CF = 1;
4108: break;
4109: }
4110: }
4111:
1.1 root 4112: inline void pcbios_int_10h_1dh()
4113: {
4114: switch(REG8(AL)) {
4115: case 0x01:
4116: break;
4117: case 0x02:
4118: REG16(BX) = 0;
4119: break;
4120: default:
1.1.1.22 root 4121: 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));
4122: m_CF = 1;
4123: break;
4124: }
4125: }
4126:
4127: inline void pcbios_int_10h_4fh()
4128: {
4129: switch(REG8(AL)) {
4130: case 0x00:
4131: REG8(AH) = 0x02; // not supported
4132: break;
4133: case 0x01:
4134: case 0x02:
4135: case 0x03:
4136: case 0x04:
4137: case 0x05:
4138: case 0x06:
4139: case 0x07:
4140: case 0x08:
4141: case 0x09:
4142: case 0x0a:
4143: case 0x0b:
4144: case 0x0c:
4145: REG8(AH) = 0x01; // failed
4146: break;
4147: default:
4148: 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 4149: m_CF = 1;
1.1 root 4150: break;
4151: }
4152: }
4153:
4154: inline void pcbios_int_10h_82h()
4155: {
4156: static UINT8 mode = 0;
4157:
4158: switch(REG8(AL)) {
1.1.1.22 root 4159: case 0x00:
1.1 root 4160: if(REG8(BL) != 0xff) {
4161: mode = REG8(BL);
4162: }
4163: REG8(AL) = mode;
4164: break;
4165: default:
1.1.1.22 root 4166: 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 4167: m_CF = 1;
1.1 root 4168: break;
4169: }
4170: }
4171:
1.1.1.22 root 4172: inline void pcbios_int_10h_83h()
4173: {
4174: static UINT8 mode = 0;
4175:
4176: switch(REG8(AL)) {
4177: case 0x00:
4178: REG16(AX) = 0; // offset???
4179: SREG(ES) = (SHADOW_BUF_TOP >> 4);
4180: i386_load_segment_descriptor(ES);
4181: REG16(BX) = (SHADOW_BUF_TOP & 0x0f);
4182: break;
4183: default:
4184: 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));
4185: m_CF = 1;
4186: break;
4187: }
4188: }
4189:
4190: inline void pcbios_int_10h_90h()
4191: {
4192: REG8(AL) = mem[0x449];
4193: }
4194:
4195: inline void pcbios_int_10h_91h()
4196: {
4197: REG8(AL) = 0x04; // VGA
4198: }
4199:
4200: inline void pcbios_int_10h_efh()
4201: {
4202: REG16(DX) = 0xffff;
4203: }
4204:
1.1 root 4205: inline void pcbios_int_10h_feh()
4206: {
4207: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 4208: SREG(ES) = (SHADOW_BUF_TOP >> 4);
1.1.1.3 root 4209: i386_load_segment_descriptor(ES);
1.1.1.8 root 4210: REG16(DI) = (SHADOW_BUF_TOP & 0x0f);
1.1 root 4211: }
4212: int_10h_feh_called = true;
4213: }
4214:
4215: inline void pcbios_int_10h_ffh()
4216: {
4217: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.23 root 4218: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 4219: COORD co;
4220: DWORD num;
4221:
1.1.1.14 root 4222: vram_flush();
4223:
4224: co.X = (REG16(DI) >> 1) % scr_width;
4225: co.Y = (REG16(DI) >> 1) / scr_width;
1.1.1.16 root 4226: int ofs = pcbios_get_shadow_buffer_address(0, co.X, co.Y);
4227: int end = min(ofs + REG16(CX) * 2, pcbios_get_shadow_buffer_address(0, 0, scr_height));
1.1.1.14 root 4228: int len;
4229: for(len = 0; ofs < end; len++) {
4230: scr_char[len] = mem[ofs++];
4231: scr_attr[len] = mem[ofs++];
4232: }
4233: co.Y += scr_top;
4234: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
4235: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 4236: }
4237: int_10h_ffh_called = true;
4238: }
4239:
1.1.1.25 root 4240: inline void pcbios_int_14h_00h()
4241: {
4242: if(REG16(DX) < 2) {
4243: static const unsigned int rate[] = {110, 150, 300, 600, 1200, 2400, 4800, 9600};
4244: UINT8 selector = sio_read(REG16(DX), 3);
4245: selector &= ~0x3f;
4246: selector |= REG8(AL) & 0x1f;
4247: UINT16 divisor = 115200 / rate[REG8(AL) >> 5];
4248: sio_write(REG16(DX), 3, selector | 0x80);
4249: sio_write(REG16(DX), 0, divisor & 0xff);
4250: sio_write(REG16(DX), 1, divisor >> 8);
4251: sio_write(REG16(DX), 3, selector);
4252: REG8(AH) = sio_read(REG16(DX), 5);
4253: REG8(AL) = sio_read(REG16(DX), 6);
4254: } else {
4255: REG8(AH) = 0x80;
4256: }
4257: }
4258:
4259: inline void pcbios_int_14h_01h()
4260: {
4261: if(REG16(DX) < 2) {
4262: UINT8 selector = sio_read(REG16(DX), 3);
4263: sio_write(REG16(DX), 3, selector & ~0x80);
4264: sio_write(REG16(DX), 0, REG8(AL));
4265: sio_write(REG16(DX), 3, selector);
4266: REG8(AH) = sio_read(REG16(DX), 5);
4267: } else {
4268: REG8(AH) = 0x80;
4269: }
4270: }
4271:
4272: inline void pcbios_int_14h_02h()
4273: {
4274: if(REG16(DX) < 2) {
4275: UINT8 selector = sio_read(REG16(DX), 3);
4276: sio_write(REG16(DX), 3, selector & ~0x80);
4277: REG8(AL) = sio_read(REG16(DX), 0);
4278: sio_write(REG16(DX), 3, selector);
4279: REG8(AH) = sio_read(REG16(DX), 5);
4280: } else {
4281: REG8(AH) = 0x80;
4282: }
4283: }
4284:
4285: inline void pcbios_int_14h_03h()
4286: {
4287: if(REG16(DX) < 2) {
4288: REG8(AH) = sio_read(REG16(DX), 5);
4289: REG8(AL) = sio_read(REG16(DX), 6);
4290: } else {
4291: REG8(AH) = 0x80;
4292: }
4293: }
4294:
4295: inline void pcbios_int_14h_04h()
4296: {
4297: if(REG16(DX) < 2) {
4298: UINT8 selector = sio_read(REG16(DX), 3);
4299: if(REG8(CH) <= 0x03) {
4300: selector = (selector & ~0x03) | REG8(CH);
4301: }
4302: if(REG8(BL) == 0x00) {
4303: selector &= ~0x04;
4304: } else if(REG8(BL) == 0x01) {
4305: selector |= 0x04;
4306: }
4307: if(REG8(BH) == 0x00) {
4308: selector = (selector & ~0x38) | 0x00;
4309: } else if(REG8(BH) == 0x01) {
4310: selector = (selector & ~0x38) | 0x08;
4311: } else if(REG8(BH) == 0x02) {
4312: selector = (selector & ~0x38) | 0x18;
4313: } else if(REG8(BH) == 0x03) {
4314: selector = (selector & ~0x38) | 0x28;
4315: } else if(REG8(BH) == 0x04) {
4316: selector = (selector & ~0x38) | 0x38;
4317: }
4318: if(REG8(AL) == 0x00) {
4319: selector |= 0x40;
4320: } else if(REG8(AL) == 0x01) {
4321: selector &= ~0x40;
4322: }
4323: if(REG8(CL) <= 0x0b) {
4324: static const unsigned int rate[] = {110, 150, 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200};
4325: UINT16 divisor = 115200 / rate[REG8(CL)];
4326: sio_write(REG16(DX), 3, selector | 0x80);
4327: sio_write(REG16(DX), 0, divisor & 0xff);
4328: sio_write(REG16(DX), 1, divisor >> 8);
4329: }
4330: sio_write(REG16(DX), 3, selector);
4331: REG8(AH) = sio_read(REG16(DX), 5);
4332: REG8(AL) = sio_read(REG16(DX), 6);
4333: } else {
4334: REG8(AH) = 0x80;
4335: }
4336: }
4337:
4338: inline void pcbios_int_14h_05h()
4339: {
4340: if(REG16(DX) < 2) {
4341: if(REG8(AL) == 0x00) {
4342: REG8(BL) = sio_read(REG16(DX), 4);
4343: REG8(AH) = sio_read(REG16(DX), 5);
4344: REG8(AL) = sio_read(REG16(DX), 6);
4345: } else if(REG8(AL) == 0x01) {
4346: sio_write(REG16(DX), 4, REG8(BL));
4347: REG8(AH) = sio_read(REG16(DX), 5);
4348: REG8(AL) = sio_read(REG16(DX), 6);
4349: } else {
4350: 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));
4351: }
4352: } else {
4353: REG8(AH) = 0x80;
4354: }
4355: }
4356:
1.1.1.14 root 4357: inline void pcbios_int_15h_10h()
4358: {
1.1.1.22 root 4359: switch(REG8(AL)) {
4360: case 0x00:
1.1.1.14 root 4361: Sleep(10);
4362: hardware_update();
1.1.1.22 root 4363: break;
4364: default:
4365: 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 4366: REG8(AH) = 0x86;
4367: m_CF = 1;
4368: }
4369: }
4370:
1.1 root 4371: inline void pcbios_int_15h_23h()
4372: {
4373: switch(REG8(AL)) {
1.1.1.22 root 4374: case 0x00:
1.1.1.8 root 4375: REG8(CL) = cmos_read(0x2d);
4376: REG8(CH) = cmos_read(0x2e);
1.1 root 4377: break;
1.1.1.22 root 4378: case 0x01:
1.1.1.8 root 4379: cmos_write(0x2d, REG8(CL));
4380: cmos_write(0x2e, REG8(CH));
1.1 root 4381: break;
4382: default:
1.1.1.22 root 4383: 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 4384: REG8(AH) = 0x86;
1.1.1.3 root 4385: m_CF = 1;
1.1 root 4386: break;
4387: }
4388: }
4389:
4390: inline void pcbios_int_15h_24h()
4391: {
4392: switch(REG8(AL)) {
1.1.1.22 root 4393: case 0x00:
1.1.1.3 root 4394: i386_set_a20_line(0);
1.1 root 4395: REG8(AH) = 0;
4396: break;
1.1.1.22 root 4397: case 0x01:
1.1.1.3 root 4398: i386_set_a20_line(1);
1.1 root 4399: REG8(AH) = 0;
4400: break;
1.1.1.22 root 4401: case 0x02:
1.1 root 4402: REG8(AH) = 0;
1.1.1.3 root 4403: REG8(AL) = (m_a20_mask >> 20) & 1;
1.1 root 4404: REG16(CX) = 0;
4405: break;
1.1.1.22 root 4406: case 0x03:
1.1 root 4407: REG16(AX) = 0;
4408: REG16(BX) = 0;
4409: break;
1.1.1.22 root 4410: default:
4411: 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));
4412: REG8(AH) = 0x86;
4413: m_CF = 1;
4414: break;
1.1 root 4415: }
4416: }
4417:
4418: inline void pcbios_int_15h_49h()
4419: {
1.1.1.14 root 4420: REG8(AH) = 0;
4421: REG8(BL) = 0; // DOS/V
1.1 root 4422: }
4423:
1.1.1.22 root 4424: inline void pcbios_int_15h_50h()
4425: {
4426: switch(REG8(AL)) {
4427: case 0x00:
4428: case 0x01:
4429: if(REG8(BH) != 0x00 && REG8(BH) != 0x01) {
4430: REG8(AH) = 0x01; // invalid font type in bh
4431: m_CF = 1;
4432: } else if(REG8(BL) != 0) {
4433: REG8(AH) = 0x02; // bl not zero
4434: m_CF = 1;
4435: } else if(REG16(BP) != 0 && REG16(BP) != 437 && REG16(BP) != 932 && REG16(BP) != 934 && REG16(BP) != 936 && REG16(BP) != 938) {
4436: REG8(AH) = 0x04; // invalid code page
4437: m_CF = 1;
4438: } else {
4439: REG8(AH) = 0x86; // finally, this function is not supported
4440: m_CF = 1;
4441: }
4442: break;
4443: default:
4444: 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));
4445: REG8(AH) = 0x86;
4446: m_CF = 1;
4447: break;
4448: }
4449: }
4450:
1.1 root 4451: inline void pcbios_int_15h_86h()
4452: {
4453: UINT32 usec = (REG16(CX) << 16) | REG16(DX);
1.1.1.14 root 4454: UINT32 msec = usec / 1000;
4455:
4456: while(msec) {
4457: UINT32 tmp = min(msec, 100);
4458: if(msec - tmp < 10) {
4459: tmp = msec;
4460: }
4461: Sleep(tmp);
4462:
4463: if(m_halted) {
4464: return;
4465: }
4466: msec -= tmp;
4467: }
1.1 root 4468: }
4469:
4470: inline void pcbios_int_15h_87h()
4471: {
4472: // copy extended memory (from DOSBox)
4473: int len = REG16(CX) * 2;
1.1.1.3 root 4474: int ofs = SREG_BASE(ES) + REG16(SI);
1.1 root 4475: int src = (*(UINT32 *)(mem + ofs + 0x12) & 0xffffff); // + (mem[ofs + 0x16] << 24);
4476: int dst = (*(UINT32 *)(mem + ofs + 0x1a) & 0xffffff); // + (mem[ofs + 0x1e] << 24);
4477: memcpy(mem + dst, mem + src, len);
4478: REG16(AX) = 0x00;
4479: }
4480:
4481: inline void pcbios_int_15h_88h()
4482: {
1.1.1.17 root 4483: REG16(AX) = ((min(MAX_MEM, 0x4000000) - 0x100000) >> 10);
1.1 root 4484: }
4485:
4486: inline void pcbios_int_15h_89h()
4487: {
1.1.1.21 root 4488: #if defined(HAS_I286) || defined(HAS_I386)
1.1 root 4489: // switch to protected mode (from DOSBox)
4490: write_io_byte(0x20, 0x10);
4491: write_io_byte(0x21, REG8(BH));
4492: write_io_byte(0x21, 0x00);
4493: write_io_byte(0xa0, 0x10);
4494: write_io_byte(0xa1, REG8(BL));
4495: write_io_byte(0xa1, 0x00);
1.1.1.3 root 4496: i386_set_a20_line(1);
4497: int ofs = SREG_BASE(ES) + REG16(SI);
4498: m_gdtr.limit = *(UINT16 *)(mem + ofs + 0x08);
4499: m_gdtr.base = *(UINT32 *)(mem + ofs + 0x08 + 0x02) & 0xffffff;
4500: m_idtr.limit = *(UINT16 *)(mem + ofs + 0x10);
4501: m_idtr.base = *(UINT32 *)(mem + ofs + 0x10 + 0x02) & 0xffffff;
4502: #if defined(HAS_I386)
4503: m_cr[0] |= 1;
4504: #else
4505: m_msw |= 1;
4506: #endif
4507: SREG(DS) = 0x18;
4508: SREG(ES) = 0x20;
4509: SREG(SS) = 0x28;
4510: i386_load_segment_descriptor(DS);
4511: i386_load_segment_descriptor(ES);
4512: i386_load_segment_descriptor(SS);
1.1.1.21 root 4513: UINT16 offset = *(UINT16 *)(mem + SREG_BASE(SS) + REG16(SP));
1.1 root 4514: REG16(SP) += 6;
1.1.1.3 root 4515: #if defined(HAS_I386)
1.1.1.21 root 4516: UINT32 flags = get_flags();
4517: flags &= (0x20000 | 0x40000 | 0x80000 | 0x100000 | 0x200000);
4518: set_flags(flags);
1.1.1.3 root 4519: #else
1.1.1.21 root 4520: UINT32 flags = CompressFlags();
4521: flags &= (0x20000 | 0x40000 | 0x80000 | 0x100000 | 0x200000);
4522: ExpandFlags(flags);
1.1.1.3 root 4523: #endif
1.1 root 4524: REG16(AX) = 0x00;
1.1.1.21 root 4525: i386_jmp_far(0x30, /*REG16(CX)*/offset);
1.1 root 4526: #else
1.1.1.21 root 4527: // i86/i186/v30: protected mode is not supported
1.1 root 4528: REG8(AH) = 0x86;
1.1.1.3 root 4529: m_CF = 1;
1.1 root 4530: #endif
4531: }
4532:
1.1.1.21 root 4533: inline void pcbios_int_15h_8ah()
4534: {
4535: UINT32 size = MAX_MEM - 0x100000;
4536: REG16(AX) = size & 0xffff;
4537: REG16(DX) = size >> 16;
4538: }
4539:
1.1.1.3 root 4540: #if defined(HAS_I386)
1.1 root 4541: inline void pcbios_int_15h_c9h()
4542: {
4543: REG8(AH) = 0x00;
4544: REG8(CH) = cpu_type;
4545: REG8(CL) = cpu_step;
4546: }
1.1.1.3 root 4547: #endif
1.1 root 4548:
4549: inline void pcbios_int_15h_cah()
4550: {
4551: switch(REG8(AL)) {
1.1.1.22 root 4552: case 0x00:
1.1 root 4553: if(REG8(BL) > 0x3f) {
4554: REG8(AH) = 0x03;
1.1.1.3 root 4555: m_CF = 1;
1.1 root 4556: } else if(REG8(BL) < 0x0e) {
4557: REG8(AH) = 0x04;
1.1.1.3 root 4558: m_CF = 1;
1.1 root 4559: } else {
1.1.1.8 root 4560: REG8(CL) = cmos_read(REG8(BL));
1.1 root 4561: }
4562: break;
1.1.1.22 root 4563: case 0x01:
1.1 root 4564: if(REG8(BL) > 0x3f) {
4565: REG8(AH) = 0x03;
1.1.1.3 root 4566: m_CF = 1;
1.1 root 4567: } else if(REG8(BL) < 0x0e) {
4568: REG8(AH) = 0x04;
1.1.1.3 root 4569: m_CF = 1;
1.1 root 4570: } else {
1.1.1.8 root 4571: cmos_write(REG8(BL), REG8(CL));
1.1 root 4572: }
4573: break;
4574: default:
1.1.1.22 root 4575: 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 4576: REG8(AH) = 0x86;
1.1.1.3 root 4577: m_CF = 1;
1.1 root 4578: break;
4579: }
4580: }
4581:
1.1.1.22 root 4582: inline void pcbios_int_15h_e8h()
1.1.1.17 root 4583: {
1.1.1.22 root 4584: switch(REG8(AL)) {
4585: #if defined(HAS_I386)
4586: case 0x01:
4587: REG16(AX) = REG16(CX) = ((min(MAX_MEM, 0x1000000) - 0x100000) >> 10);
4588: REG16(BX) = REG16(DX) = ((max(MAX_MEM, 0x1000000) - 0x1000000) >> 16);
4589: break;
1.1.1.17 root 4590: #endif
1.1.1.22 root 4591: default:
4592: 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));
4593: REG8(AH) = 0x86;
4594: m_CF = 1;
4595: break;
4596: }
4597: }
1.1.1.17 root 4598:
1.1.1.16 root 4599: UINT32 pcbios_get_key_code(bool clear_buffer)
1.1 root 4600: {
4601: UINT32 code = 0;
4602:
4603: if(key_buf_char->count() == 0) {
1.1.1.14 root 4604: if(!update_key_buffer()) {
4605: if(clear_buffer) {
4606: Sleep(10);
4607: } else {
4608: maybe_idle();
4609: }
4610: }
1.1 root 4611: }
4612: if(!clear_buffer) {
4613: key_buf_char->store_buffer();
4614: key_buf_scan->store_buffer();
4615: }
4616: if(key_buf_char->count() != 0) {
4617: code = key_buf_char->read() | (key_buf_scan->read() << 8);
4618: }
4619: if(key_buf_char->count() != 0) {
4620: code |= (key_buf_char->read() << 16) | (key_buf_scan->read() << 24);
4621: }
4622: if(!clear_buffer) {
4623: key_buf_char->restore_buffer();
4624: key_buf_scan->restore_buffer();
4625: }
4626: return code;
4627: }
4628:
4629: inline void pcbios_int_16h_00h()
4630: {
1.1.1.14 root 4631: while(key_code == 0 && !m_halted) {
1.1.1.16 root 4632: key_code = pcbios_get_key_code(true);
1.1 root 4633: }
4634: if((key_code & 0xffff) == 0x0000 || (key_code & 0xffff) == 0xe000) {
4635: if(REG8(AH) == 0x10) {
4636: key_code = ((key_code >> 8) & 0xff) | ((key_code >> 16) & 0xff00);
4637: } else {
4638: key_code = ((key_code >> 16) & 0xff00);
4639: }
4640: }
4641: REG16(AX) = key_code & 0xffff;
4642: key_code >>= 16;
4643: }
4644:
4645: inline void pcbios_int_16h_01h()
4646: {
1.1.1.5 root 4647: UINT32 key_code_tmp = key_code;
1.1 root 4648:
1.1.1.5 root 4649: if(key_code_tmp == 0) {
1.1.1.16 root 4650: key_code_tmp = pcbios_get_key_code(false);
1.1.1.5 root 4651: }
1.1.1.14 root 4652: if((key_code_tmp & 0xffff) == 0x0000 || (key_code_tmp & 0xffff) == 0xe000) {
4653: if(REG8(AH) == 0x11) {
4654: key_code_tmp = ((key_code_tmp >> 8) & 0xff) | ((key_code_tmp >> 16) & 0xff00);
4655: } else {
4656: key_code_tmp = ((key_code_tmp >> 16) & 0xff00);
1.1 root 4657: }
4658: }
1.1.1.5 root 4659: if(key_code_tmp != 0) {
4660: REG16(AX) = key_code_tmp & 0xffff;
1.1 root 4661: }
1.1.1.3 root 4662: #if defined(HAS_I386)
1.1.1.5 root 4663: m_ZF = (key_code_tmp == 0);
1.1.1.3 root 4664: #else
1.1.1.5 root 4665: m_ZeroVal = (key_code_tmp != 0);
1.1.1.3 root 4666: #endif
1.1 root 4667: }
4668:
4669: inline void pcbios_int_16h_02h()
4670: {
4671: REG8(AL) = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
4672: REG8(AL) |= (GetAsyncKeyState(VK_CAPITAL) & 0x0001) ? 0x40 : 0;
4673: REG8(AL) |= (GetAsyncKeyState(VK_NUMLOCK) & 0x0001) ? 0x20 : 0;
4674: REG8(AL) |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
4675: REG8(AL) |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
4676: REG8(AL) |= (GetAsyncKeyState(VK_CONTROL) & 0x8000) ? 0x04 : 0;
4677: REG8(AL) |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
4678: REG8(AL) |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
4679: }
4680:
4681: inline void pcbios_int_16h_03h()
4682: {
4683: static UINT16 status = 0;
4684:
4685: switch(REG8(AL)) {
4686: case 0x05:
4687: status = REG16(BX);
4688: break;
4689: case 0x06:
4690: REG16(BX) = status;
4691: break;
4692: default:
1.1.1.3 root 4693: m_CF = 1;
1.1 root 4694: break;
4695: }
4696: }
4697:
4698: inline void pcbios_int_16h_05h()
4699: {
1.1.1.14 root 4700: key_buf_char->write(REG8(CL));
4701: key_buf_scan->write(REG8(CH));
1.1 root 4702: REG8(AL) = 0x00;
4703: }
4704:
4705: inline void pcbios_int_16h_12h()
4706: {
4707: pcbios_int_16h_02h();
4708:
4709: REG8(AH) = 0;//(GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x80 : 0;
4710: REG8(AH) |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
4711: REG8(AH) |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
4712: REG8(AH) |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
4713: REG8(AH) |= (GetAsyncKeyState(VK_RMENU ) & 0x8000) ? 0x08 : 0;
4714: REG8(AH) |= (GetAsyncKeyState(VK_RCONTROL) & 0x8000) ? 0x04 : 0;
4715: REG8(AH) |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
4716: REG8(AH) |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
4717: }
4718:
4719: inline void pcbios_int_16h_13h()
4720: {
4721: static UINT16 status = 0;
4722:
4723: switch(REG8(AL)) {
4724: case 0x00:
4725: status = REG16(DX);
4726: break;
4727: case 0x01:
4728: REG16(DX) = status;
4729: break;
4730: default:
1.1.1.22 root 4731: 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 4732: m_CF = 1;
1.1 root 4733: break;
4734: }
4735: }
4736:
4737: inline void pcbios_int_16h_14h()
4738: {
4739: static UINT8 status = 0;
4740:
4741: switch(REG8(AL)) {
4742: case 0x00:
4743: case 0x01:
4744: status = REG8(AL);
4745: break;
4746: case 0x02:
4747: REG8(AL) = status;
4748: break;
4749: default:
1.1.1.22 root 4750: 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 4751: m_CF = 1;
1.1 root 4752: break;
4753: }
4754: }
4755:
1.1.1.24 root 4756: inline void pcbios_int_16h_55h()
4757: {
4758: switch(REG8(AL)) {
4759: case 0x00:
4760: // keyboard tsr is not present
4761: break;
4762: case 0xfe:
4763: // handlers for INT 08, INT 09, INT 16, INT 1B, and INT 1C are installed
4764: break;
4765: case 0xff:
4766: break;
4767: default:
4768: 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));
4769: m_CF = 1;
4770: break;
4771: }
4772: }
4773:
1.1 root 4774: inline void pcbios_int_1ah_00h()
4775: {
1.1.1.19 root 4776: pcbios_update_daily_timer_counter(timeGetTime());
4777: REG16(CX) = *(UINT16 *)(mem + 0x46e);
4778: REG16(DX) = *(UINT16 *)(mem + 0x46c);
4779: REG8(AL) = mem[0x470];
4780: mem[0x470] = 0;
1.1 root 4781: }
4782:
4783: inline int to_bcd(int t)
4784: {
4785: int u = (t % 100) / 10;
4786: return (u << 4) | (t % 10);
4787: }
4788:
4789: inline void pcbios_int_1ah_02h()
4790: {
4791: SYSTEMTIME time;
4792:
4793: GetLocalTime(&time);
4794: REG8(CH) = to_bcd(time.wHour);
4795: REG8(CL) = to_bcd(time.wMinute);
4796: REG8(DH) = to_bcd(time.wSecond);
4797: REG8(DL) = 0x00;
4798: }
4799:
4800: inline void pcbios_int_1ah_04h()
4801: {
4802: SYSTEMTIME time;
4803:
4804: GetLocalTime(&time);
4805: REG8(CH) = to_bcd(time.wYear / 100);
4806: REG8(CL) = to_bcd(time.wYear);
4807: REG8(DH) = to_bcd(time.wMonth);
4808: REG8(DL) = to_bcd(time.wDay);
4809: }
4810:
4811: inline void pcbios_int_1ah_0ah()
4812: {
4813: SYSTEMTIME time;
4814: FILETIME file_time;
4815: WORD dos_date, dos_time;
4816:
4817: GetLocalTime(&time);
4818: SystemTimeToFileTime(&time, &file_time);
4819: FileTimeToDosDateTime(&file_time, &dos_date, &dos_time);
4820: REG16(CX) = dos_date;
4821: }
4822:
4823: // msdos system call
4824:
4825: inline void msdos_int_21h_00h()
4826: {
1.1.1.3 root 4827: msdos_process_terminate(SREG(CS), retval, 1);
1.1 root 4828: }
4829:
4830: inline void msdos_int_21h_01h()
4831: {
4832: REG8(AL) = msdos_getche();
1.1.1.26! root 4833: ctrl_c_detected = ctrl_c_pressed;
! 4834:
1.1.1.8 root 4835: // some seconds may be passed in console
1.1 root 4836: hardware_update();
4837: }
4838:
4839: inline void msdos_int_21h_02h()
4840: {
4841: msdos_putch(REG8(DL));
1.1.1.26! root 4842: ctrl_c_detected = ctrl_c_pressed;
1.1 root 4843: }
4844:
4845: inline void msdos_int_21h_03h()
4846: {
4847: REG8(AL) = msdos_aux_in();
4848: }
4849:
4850: inline void msdos_int_21h_04h()
4851: {
4852: msdos_aux_out(REG8(DL));
4853: }
4854:
4855: inline void msdos_int_21h_05h()
4856: {
4857: msdos_prn_out(REG8(DL));
4858: }
4859:
4860: inline void msdos_int_21h_06h()
4861: {
4862: if(REG8(DL) == 0xff) {
4863: if(msdos_kbhit()) {
4864: REG8(AL) = msdos_getch();
1.1.1.3 root 4865: #if defined(HAS_I386)
4866: m_ZF = 0;
4867: #else
4868: m_ZeroVal = 1;
4869: #endif
1.1 root 4870: } else {
4871: REG8(AL) = 0;
1.1.1.3 root 4872: #if defined(HAS_I386)
4873: m_ZF = 1;
4874: #else
4875: m_ZeroVal = 0;
4876: #endif
1.1.1.14 root 4877: maybe_idle();
1.1 root 4878: }
4879: } else {
4880: msdos_putch(REG8(DL));
4881: }
4882: }
4883:
4884: inline void msdos_int_21h_07h()
4885: {
4886: REG8(AL) = msdos_getch();
1.1.1.26! root 4887:
1.1.1.8 root 4888: // some seconds may be passed in console
1.1 root 4889: hardware_update();
4890: }
4891:
4892: inline void msdos_int_21h_08h()
4893: {
4894: REG8(AL) = msdos_getch();
1.1.1.26! root 4895: ctrl_c_detected = ctrl_c_pressed;
! 4896:
1.1.1.8 root 4897: // some seconds may be passed in console
1.1 root 4898: hardware_update();
4899: }
4900:
4901: inline void msdos_int_21h_09h()
4902: {
1.1.1.21 root 4903: msdos_stdio_reopen();
4904:
1.1.1.20 root 4905: process_t *process = msdos_process_info_get(current_psp);
4906: int fd = msdos_psp_get_file_table(1, current_psp);
4907:
1.1.1.14 root 4908: char *str = (char *)(mem + SREG_BASE(DS) + REG16(DX));
4909: int len = 0;
1.1 root 4910:
1.1.1.14 root 4911: while(str[len] != '$' && len < 0x10000) {
4912: len++;
4913: }
1.1.1.20 root 4914: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 4915: // stdout is redirected to file
1.1.1.20 root 4916: msdos_write(fd, str, len);
1.1 root 4917: } else {
4918: for(int i = 0; i < len; i++) {
1.1.1.14 root 4919: msdos_putch(str[i]);
1.1 root 4920: }
4921: }
1.1.1.26! root 4922: ctrl_c_detected = ctrl_c_pressed;
1.1 root 4923: }
4924:
4925: inline void msdos_int_21h_0ah()
4926: {
1.1.1.3 root 4927: int ofs = SREG_BASE(DS) + REG16(DX);
1.1 root 4928: int max = mem[ofs] - 1;
4929: UINT8 *buf = mem + ofs + 2;
4930: int chr, p = 0;
4931:
4932: while((chr = msdos_getch()) != 0x0d) {
1.1.1.26! root 4933: if(ctrl_c_pressed) {
! 4934: p = 0;
! 4935: msdos_putch(chr);
! 4936: break;
! 4937: } else if(chr == 0x00) {
1.1 root 4938: // skip 2nd byte
4939: msdos_getch();
4940: } else if(chr == 0x08) {
4941: // back space
4942: if(p > 0) {
4943: p--;
1.1.1.20 root 4944: if(msdos_ctrl_code_check(buf[p])) {
4945: msdos_putch(chr);
4946: msdos_putch(chr);
4947: msdos_putch(' ');
4948: msdos_putch(' ');
4949: msdos_putch(chr);
4950: msdos_putch(chr);
4951: } else {
4952: msdos_putch(chr);
4953: msdos_putch(' ');
4954: msdos_putch(chr);
4955: }
1.1 root 4956: }
4957: } else if(p < max) {
4958: buf[p++] = chr;
4959: msdos_putch(chr);
4960: }
4961: }
4962: buf[p] = 0x0d;
4963: mem[ofs + 1] = p;
1.1.1.26! root 4964: ctrl_c_detected = ctrl_c_pressed;
! 4965:
1.1.1.8 root 4966: // some seconds may be passed in console
1.1 root 4967: hardware_update();
4968: }
4969:
4970: inline void msdos_int_21h_0bh()
4971: {
4972: if(msdos_kbhit()) {
4973: REG8(AL) = 0xff;
4974: } else {
4975: REG8(AL) = 0x00;
1.1.1.14 root 4976: maybe_idle();
1.1 root 4977: }
1.1.1.26! root 4978: ctrl_c_detected = ctrl_c_pressed;
1.1 root 4979: }
4980:
4981: inline void msdos_int_21h_0ch()
4982: {
4983: // clear key buffer
1.1.1.21 root 4984: msdos_stdio_reopen();
4985:
1.1.1.20 root 4986: process_t *process = msdos_process_info_get(current_psp);
4987: int fd = msdos_psp_get_file_table(0, current_psp);
4988:
4989: if(fd < process->max_files && file_handler[fd].valid && !file_handler[fd].atty) {
1.1 root 4990: // stdin is redirected to file
4991: } else {
4992: while(msdos_kbhit()) {
4993: msdos_getch();
4994: }
4995: }
4996:
4997: switch(REG8(AL)) {
4998: case 0x01:
4999: msdos_int_21h_01h();
5000: break;
5001: case 0x06:
5002: msdos_int_21h_06h();
5003: break;
5004: case 0x07:
5005: msdos_int_21h_07h();
5006: break;
5007: case 0x08:
5008: msdos_int_21h_08h();
5009: break;
5010: case 0x0a:
5011: msdos_int_21h_0ah();
5012: break;
5013: default:
1.1.1.22 root 5014: // 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));
5015: // REG16(AX) = 0x01;
5016: // m_CF = 1;
1.1 root 5017: break;
5018: }
5019: }
5020:
5021: inline void msdos_int_21h_0dh()
5022: {
5023: }
5024:
5025: inline void msdos_int_21h_0eh()
5026: {
5027: if(REG8(DL) < 26) {
5028: _chdrive(REG8(DL) + 1);
5029: msdos_cds_update(REG8(DL));
1.1.1.23 root 5030: msdos_sda_update(current_psp);
1.1 root 5031: }
5032: REG8(AL) = 26; // zdrive
5033: }
5034:
1.1.1.14 root 5035: inline void msdos_int_21h_0fh()
5036: {
5037: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5038: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5039: char *path = msdos_fcb_path(fcb);
5040: 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 5041:
1.1.1.14 root 5042: if(hFile == INVALID_HANDLE_VALUE) {
5043: REG8(AL) = 0xff;
5044: } else {
5045: REG8(AL) = 0;
5046: fcb->current_block = 0;
5047: fcb->record_size = 128;
5048: fcb->file_size = GetFileSize(hFile, NULL);
5049: fcb->handle = hFile;
5050: fcb->cur_record = 0;
5051: }
5052: }
5053:
5054: inline void msdos_int_21h_10h()
5055: {
5056: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5057: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5058:
5059: REG8(AL) = CloseHandle(fcb->handle) ? 0 : 0xff;
5060: }
5061:
1.1 root 5062: inline void msdos_int_21h_11h()
5063: {
1.1.1.3 root 5064: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5065: fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 5066:
5067: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 5068: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5069: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
5070: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 5071: char *path = msdos_fcb_path(fcb);
5072: WIN32_FIND_DATA fd;
5073:
1.1.1.13 root 5074: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
5075: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
5076: FindClose(dtainfo->find_handle);
5077: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 5078: }
5079: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 5080: dtainfo->allowable_mask = (ext_fcb->flag == 0xff) ? ext_fcb->attribute : 0x20;
5081: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 5082:
1.1.1.14 root 5083: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
5084: dtainfo->allowable_mask &= ~8;
1.1 root 5085: }
1.1.1.14 root 5086: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
5087: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 5088: !msdos_find_file_has_8dot3name(&fd)) {
5089: if(!FindNextFile(dtainfo->find_handle, &fd)) {
5090: FindClose(dtainfo->find_handle);
5091: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 5092: break;
5093: }
5094: }
5095: }
1.1.1.13 root 5096: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 5097: if(ext_fcb->flag == 0xff) {
5098: ext_find->flag = 0xff;
5099: memset(ext_find->reserved, 0, 5);
5100: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
5101: }
5102: find->drive = _getdrive();
1.1.1.13 root 5103: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 5104: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
5105: find->nt_res = 0;
5106: msdos_find_file_conv_local_time(&fd);
5107: find->create_time_ms = 0;
5108: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
5109: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
5110: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
5111: find->cluster_hi = find->cluster_lo = 0;
5112: find->file_size = fd.nFileSizeLow;
5113: REG8(AL) = 0x00;
1.1.1.14 root 5114: } else if(dtainfo->allowable_mask & 8) {
1.1 root 5115: if(ext_fcb->flag == 0xff) {
5116: ext_find->flag = 0xff;
5117: memset(ext_find->reserved, 0, 5);
5118: ext_find->attribute = 8;
5119: }
5120: find->drive = _getdrive();
5121: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
5122: find->attribute = 8;
5123: find->nt_res = 0;
5124: msdos_find_file_conv_local_time(&fd);
5125: find->create_time_ms = 0;
5126: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
5127: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
5128: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
5129: find->cluster_hi = find->cluster_lo = 0;
5130: find->file_size = 0;
1.1.1.14 root 5131: dtainfo->allowable_mask &= ~8;
1.1 root 5132: REG8(AL) = 0x00;
5133: } else {
5134: REG8(AL) = 0xff;
5135: }
5136: }
5137:
5138: inline void msdos_int_21h_12h()
5139: {
1.1.1.3 root 5140: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1.1.14 root 5141: // fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 5142:
5143: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 5144: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5145: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
5146: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 5147: WIN32_FIND_DATA fd;
5148:
1.1.1.13 root 5149: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
5150: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
5151: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 5152: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 5153: !msdos_find_file_has_8dot3name(&fd)) {
5154: if(!FindNextFile(dtainfo->find_handle, &fd)) {
5155: FindClose(dtainfo->find_handle);
5156: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 5157: break;
5158: }
5159: }
5160: } else {
1.1.1.13 root 5161: FindClose(dtainfo->find_handle);
5162: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 5163: }
5164: }
1.1.1.13 root 5165: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 5166: if(ext_fcb->flag == 0xff) {
5167: ext_find->flag = 0xff;
5168: memset(ext_find->reserved, 0, 5);
5169: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
5170: }
5171: find->drive = _getdrive();
1.1.1.13 root 5172: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 5173: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
5174: find->nt_res = 0;
5175: msdos_find_file_conv_local_time(&fd);
5176: find->create_time_ms = 0;
5177: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
5178: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
5179: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
5180: find->cluster_hi = find->cluster_lo = 0;
5181: find->file_size = fd.nFileSizeLow;
5182: REG8(AL) = 0x00;
1.1.1.14 root 5183: } else if(dtainfo->allowable_mask & 8) {
1.1 root 5184: if(ext_fcb->flag == 0xff) {
5185: ext_find->flag = 0xff;
5186: memset(ext_find->reserved, 0, 5);
5187: ext_find->attribute = 8;
5188: }
5189: find->drive = _getdrive();
5190: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
5191: find->attribute = 8;
5192: find->nt_res = 0;
5193: msdos_find_file_conv_local_time(&fd);
5194: find->create_time_ms = 0;
5195: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
5196: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
5197: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
5198: find->cluster_hi = find->cluster_lo = 0;
5199: find->file_size = 0;
1.1.1.14 root 5200: dtainfo->allowable_mask &= ~8;
1.1 root 5201: REG8(AL) = 0x00;
5202: } else {
5203: REG8(AL) = 0xff;
5204: }
5205: }
5206:
5207: inline void msdos_int_21h_13h()
5208: {
1.1.1.3 root 5209: if(remove(msdos_fcb_path((fcb_t *)(mem + SREG_BASE(DS) + REG16(DX))))) {
1.1 root 5210: REG8(AL) = 0xff;
5211: } else {
5212: REG8(AL) = 0x00;
5213: }
5214: }
5215:
1.1.1.16 root 5216: inline void msdos_int_21h_14h()
5217: {
5218: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5219: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5220: process_t *process = msdos_process_info_get(current_psp);
5221: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5222: DWORD num = 0;
5223:
5224: memset(mem + dta_laddr, 0, fcb->record_size);
5225: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
5226: REG8(AL) = 1;
5227: } else {
5228: UINT32 position = fcb->current_block * fcb->record_size + fcb->cur_record + num;
5229: fcb->current_block = (position & 0xffffff) / fcb->record_size;
5230: fcb->cur_record = (position & 0xffffff) % fcb->record_size;
5231: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
5232: }
5233: }
5234:
5235: inline void msdos_int_21h_15h()
1.1.1.14 root 5236: {
5237: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5238: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.16 root 5239: process_t *process = msdos_process_info_get(current_psp);
5240: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5241: DWORD num = 0;
1.1.1.14 root 5242:
1.1.1.16 root 5243: if(!WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
5244: REG8(AL) = 1;
5245: } else {
5246: fcb->file_size = GetFileSize(fcb->handle, NULL);
5247: UINT32 position = fcb->current_block * fcb->record_size + fcb->cur_record + num;
5248: fcb->current_block = (position & 0xffffff) / fcb->record_size;
5249: fcb->cur_record = (position & 0xffffff) % fcb->record_size;
5250: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
5251: }
5252: }
5253:
5254: inline void msdos_int_21h_16h()
5255: {
5256: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5257: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
1.1.1.14 root 5258: char *path = msdos_fcb_path(fcb);
5259: 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 5260:
1.1.1.14 root 5261: if(hFile == INVALID_HANDLE_VALUE) {
5262: REG8(AL) = 0xff;
5263: } else {
5264: REG8(AL) = 0;
5265: fcb->current_block = 0;
5266: fcb->record_size = 128;
5267: fcb->file_size = 0;
5268: fcb->handle = hFile;
5269: fcb->cur_record = 0;
5270: }
5271: }
5272:
1.1.1.16 root 5273: inline void msdos_int_21h_17h()
5274: {
5275: ext_fcb_t *ext_fcb_src = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5276: fcb_t *fcb_src = (fcb_t *)(ext_fcb_src + (ext_fcb_src->flag == 0xff ? 1 : 0));
5277: char *path_src = msdos_fcb_path(fcb_src);
5278: ext_fcb_t *ext_fcb_dst = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + 16);
5279: fcb_t *fcb_dst = (fcb_t *)(ext_fcb_dst + (ext_fcb_dst->flag == 0xff ? 1 : 0));
5280: char *path_dst = msdos_fcb_path(fcb_dst);
5281:
5282: if(rename(path_src, path_dst)) {
5283: REG8(AL) = 0xff;
5284: } else {
5285: REG8(AL) = 0;
5286: }
5287: }
5288:
1.1 root 5289: inline void msdos_int_21h_18h()
5290: {
5291: REG8(AL) = 0x00;
5292: }
5293:
5294: inline void msdos_int_21h_19h()
5295: {
5296: REG8(AL) = _getdrive() - 1;
5297: }
5298:
5299: inline void msdos_int_21h_1ah()
5300: {
5301: process_t *process = msdos_process_info_get(current_psp);
5302:
5303: process->dta.w.l = REG16(DX);
1.1.1.3 root 5304: process->dta.w.h = SREG(DS);
1.1.1.23 root 5305: msdos_sda_update(current_psp);
1.1 root 5306: }
5307:
5308: inline void msdos_int_21h_1bh()
5309: {
5310: int drive_num = _getdrive() - 1;
5311: UINT16 seg, ofs;
5312:
5313: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
5314: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
5315: REG8(AL) = dpb->highest_sector_num + 1;
5316: REG16(CX) = dpb->bytes_per_sector;
5317: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 5318: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 5319: } else {
5320: REG8(AL) = 0xff;
1.1.1.3 root 5321: m_CF = 1;
1.1 root 5322: }
5323:
5324: }
5325:
5326: inline void msdos_int_21h_1ch()
5327: {
5328: int drive_num = REG8(DL) ? (REG8(DL) - 1) : (_getdrive() - 1);
5329: UINT16 seg, ofs;
5330:
5331: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
5332: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
5333: REG8(AL) = dpb->highest_sector_num + 1;
5334: REG16(CX) = dpb->bytes_per_sector;
5335: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 5336: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 5337: } else {
5338: REG8(AL) = 0xff;
1.1.1.3 root 5339: m_CF = 1;
1.1 root 5340: }
5341:
5342: }
5343:
5344: inline void msdos_int_21h_1dh()
5345: {
5346: REG8(AL) = 0;
5347: }
5348:
5349: inline void msdos_int_21h_1eh()
5350: {
5351: REG8(AL) = 0;
5352: }
5353:
5354: inline void msdos_int_21h_1fh()
5355: {
5356: int drive_num = _getdrive() - 1;
5357: UINT16 seg, ofs;
5358:
5359: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
5360: REG8(AL) = 0;
1.1.1.3 root 5361: SREG(DS) = seg;
5362: i386_load_segment_descriptor(DS);
1.1 root 5363: REG16(BX) = ofs;
5364: } else {
5365: REG8(AL) = 0xff;
1.1.1.3 root 5366: m_CF = 1;
1.1 root 5367: }
5368: }
5369:
5370: inline void msdos_int_21h_20h()
5371: {
5372: REG8(AL) = 0;
5373: }
5374:
1.1.1.14 root 5375: inline void msdos_int_21h_21h()
5376: {
5377: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5378: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5379:
5380: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
5381: REG8(AL) = 1;
5382: } else {
5383: process_t *process = msdos_process_info_get(current_psp);
5384: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5385: memset(mem + dta_laddr, 0, fcb->record_size);
1.1.1.16 root 5386: DWORD num = 0;
1.1.1.14 root 5387: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
5388: REG8(AL) = 1;
5389: } else {
5390: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
5391: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
1.1.1.16 root 5392: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
1.1.1.14 root 5393: }
5394: }
5395: }
5396:
5397: inline void msdos_int_21h_22h()
5398: {
5399: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5400: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5401:
5402: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
5403: REG8(AL) = 0xff;
5404: } else {
5405: process_t *process = msdos_process_info_get(current_psp);
5406: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
1.1.1.16 root 5407: DWORD num = 0;
1.1.1.14 root 5408: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL);
5409: fcb->file_size = GetFileSize(fcb->handle, NULL);
5410: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
5411: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
1.1.1.16 root 5412: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
1.1.1.14 root 5413: }
5414: }
5415:
1.1.1.16 root 5416: inline void msdos_int_21h_23h()
5417: {
5418: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5419: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5420: char *path = msdos_fcb_path(fcb);
5421: HANDLE hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
5422:
5423: if(hFile == INVALID_HANDLE_VALUE) {
5424: REG8(AL) = 0xff;
5425: } else {
5426: UINT32 size = GetFileSize(hFile, NULL);
5427: fcb->rand_record = size / fcb->record_size + ((size % fcb->record_size) != 0);
5428: REG8(AL) = 0;
5429: }
5430: }
5431:
5432: inline void msdos_int_21h_24h()
5433: {
5434: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5435: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5436:
5437: fcb->rand_record = fcb->current_block * fcb->record_size + fcb->cur_record;
5438: }
5439:
1.1 root 5440: inline void msdos_int_21h_25h()
5441: {
5442: *(UINT16 *)(mem + 4 * REG8(AL) + 0) = REG16(DX);
1.1.1.3 root 5443: *(UINT16 *)(mem + 4 * REG8(AL) + 2) = SREG(DS);
1.1 root 5444: }
5445:
5446: inline void msdos_int_21h_26h()
5447: {
5448: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
5449:
5450: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
5451: psp->first_mcb = REG16(DX) + 16;
5452: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
5453: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
5454: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
5455: psp->parent_psp = 0;
5456: }
5457:
1.1.1.16 root 5458: inline void msdos_int_21h_27h()
5459: {
5460: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5461: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5462:
5463: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
5464: REG8(AL) = 1;
5465: } else {
5466: process_t *process = msdos_process_info_get(current_psp);
5467: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5468: memset(mem + dta_laddr, 0, fcb->record_size * REG16(CX));
5469: DWORD num = 0;
5470: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size * REG16(CX), &num, NULL) || num == 0) {
5471: REG8(AL) = 1;
5472: } else {
5473: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
5474: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
5475: REG8(AL) = (num == fcb->record_size) ? 0 : 3;
5476: REG16(CX) = num / fcb->record_size + ((num % fcb->record_size) != 0);
5477: }
5478: }
5479: }
5480:
5481: inline void msdos_int_21h_28h()
5482: {
5483: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
5484: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
5485:
5486: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
5487: REG8(AL) = 0xff;
5488: } else {
5489: process_t *process = msdos_process_info_get(current_psp);
5490: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5491: DWORD num = 0;
5492: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size * REG16(CX), &num, NULL);
5493: fcb->file_size = GetFileSize(fcb->handle, NULL);
5494: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
5495: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
5496: REG8(AL) = (num == fcb->record_size) ? 0 : 1;
5497: REG16(CX) = num / fcb->record_size + ((num % fcb->record_size) != 0);
5498: }
5499: }
5500:
1.1 root 5501: inline void msdos_int_21h_29h()
5502: {
1.1.1.20 root 5503: int ofs = 0;//SREG_BASE(DS) + REG16(SI);
5504: char buffer[1024], name[MAX_PATH], ext[MAX_PATH];
1.1 root 5505: UINT8 drv = 0;
5506: char sep_chars[] = ":.;,=+";
5507: char end_chars[] = "\\<>|/\"[]";
5508: char spc_chars[] = " \t";
5509:
1.1.1.20 root 5510: memcpy(buffer, mem + SREG_BASE(DS) + REG16(SI), 1023);
5511: buffer[1023] = 0;
5512: memset(name, 0x20, sizeof(name));
5513: memset(ext, 0x20, sizeof(ext));
5514:
1.1 root 5515: if(REG8(AL) & 1) {
1.1.1.20 root 5516: ofs += strspn((char *)(buffer + ofs), spc_chars);
5517: if(my_strchr(sep_chars, buffer[ofs]) && buffer[ofs] != '\0') {
1.1 root 5518: ofs++;
5519: }
5520: }
1.1.1.20 root 5521: ofs += strspn((char *)(buffer + ofs), spc_chars);
1.1 root 5522:
1.1.1.24 root 5523: if(buffer[ofs + 1] == ':') {
5524: if(buffer[ofs] >= 'a' && buffer[ofs] <= 'z') {
5525: drv = buffer[ofs] - 'a' + 1;
1.1.1.20 root 5526: ofs += 2;
1.1.1.24 root 5527: if(buffer[ofs] == '\\' || buffer[ofs] == '/') {
5528: ofs++;
5529: }
5530: } else if(buffer[ofs] >= 'A' && buffer[ofs] <= 'Z') {
5531: drv = buffer[ofs] - 'A' + 1;
1.1 root 5532: ofs += 2;
1.1.1.24 root 5533: if(buffer[ofs] == '\\' || buffer[ofs] == '/') {
5534: ofs++;
5535: }
1.1 root 5536: }
5537: }
1.1.1.20 root 5538: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) {
5539: UINT8 c = buffer[ofs];
5540: if(is_kanji) {
5541: is_kanji = 0;
5542: } else if(msdos_lead_byte_check(c)) {
5543: is_kanji = 1;
5544: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
1.1 root 5545: break;
5546: } else if(c >= 'a' && c <= 'z') {
5547: c -= 0x20;
5548: }
5549: ofs++;
5550: name[i] = c;
5551: }
1.1.1.20 root 5552: if(buffer[ofs] == '.') {
1.1 root 5553: ofs++;
1.1.1.20 root 5554: for(int i = 0, is_kanji = 0; i < MAX_PATH; i++) {
5555: UINT8 c = buffer[ofs];
5556: if(is_kanji) {
5557: is_kanji = 0;
5558: } else if(msdos_lead_byte_check(c)) {
5559: is_kanji = 1;
5560: } else if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
1.1 root 5561: break;
5562: } else if(c >= 'a' && c <= 'z') {
5563: c -= 0x20;
5564: }
5565: ofs++;
5566: ext[i] = c;
5567: }
5568: }
1.1.1.20 root 5569: int si = REG16(SI) + ofs;
1.1.1.3 root 5570: int ds = SREG(DS);
1.1 root 5571: while(si > 0xffff) {
5572: si -= 0x10;
5573: ds++;
5574: }
5575: REG16(SI) = si;
1.1.1.3 root 5576: SREG(DS) = ds;
5577: i386_load_segment_descriptor(DS);
1.1 root 5578:
1.1.1.3 root 5579: UINT8 *fcb = mem + SREG_BASE(ES) + REG16(DI);
1.1.1.20 root 5580: if(!(REG8(AL) & 2) || drv != 0) {
5581: fcb[0] = drv;
5582: }
5583: if(!(REG8(AL) & 4) || name[0] != 0x20) {
5584: memcpy(fcb + 1, name, 8);
5585: }
5586: if(!(REG8(AL) & 8) || ext[0] != 0x20) {
5587: memcpy(fcb + 9, ext, 3);
5588: }
5589: for(int i = 1, found_star = 0; i < 1 + 8; i++) {
1.1 root 5590: if(fcb[i] == '*') {
5591: found_star = 1;
5592: }
5593: if(found_star) {
5594: fcb[i] = '?';
5595: }
5596: }
1.1.1.20 root 5597: for(int i = 9, found_star = 0; i < 9 + 3; i++) {
1.1 root 5598: if(fcb[i] == '*') {
5599: found_star = 1;
5600: }
5601: if(found_star) {
5602: fcb[i] = '?';
5603: }
5604: }
5605:
5606: if(drv == 0 || (drv > 0 && drv <= 26 && (GetLogicalDrives() & ( 1 << (drv - 1) )))) {
5607: if(memchr(fcb + 1, '?', 8 + 3)) {
5608: REG8(AL) = 0x01;
1.1.1.20 root 5609: } else {
5610: REG8(AL) = 0x00;
1.1 root 5611: }
5612: } else {
5613: REG8(AL) = 0xff;
5614: }
5615: }
5616:
5617: inline void msdos_int_21h_2ah()
5618: {
5619: SYSTEMTIME sTime;
5620:
5621: GetLocalTime(&sTime);
5622: REG16(CX) = sTime.wYear;
5623: REG8(DH) = (UINT8)sTime.wMonth;
5624: REG8(DL) = (UINT8)sTime.wDay;
5625: REG8(AL) = (UINT8)sTime.wDayOfWeek;
5626: }
5627:
5628: inline void msdos_int_21h_2bh()
5629: {
1.1.1.14 root 5630: REG8(AL) = 0xff;
1.1 root 5631: }
5632:
5633: inline void msdos_int_21h_2ch()
5634: {
5635: SYSTEMTIME sTime;
5636:
5637: GetLocalTime(&sTime);
5638: REG8(CH) = (UINT8)sTime.wHour;
5639: REG8(CL) = (UINT8)sTime.wMinute;
5640: REG8(DH) = (UINT8)sTime.wSecond;
1.1.1.14 root 5641: REG8(DL) = (UINT8)sTime.wMilliseconds / 10;
1.1 root 5642: }
5643:
5644: inline void msdos_int_21h_2dh()
5645: {
5646: REG8(AL) = 0x00;
5647: }
5648:
5649: inline void msdos_int_21h_2eh()
5650: {
5651: process_t *process = msdos_process_info_get(current_psp);
5652:
5653: process->verify = REG8(AL);
5654: }
5655:
5656: inline void msdos_int_21h_2fh()
5657: {
5658: process_t *process = msdos_process_info_get(current_psp);
5659:
5660: REG16(BX) = process->dta.w.l;
1.1.1.3 root 5661: SREG(ES) = process->dta.w.h;
5662: i386_load_segment_descriptor(ES);
1.1 root 5663: }
5664:
5665: inline void msdos_int_21h_30h()
5666: {
5667: // Version Flag / OEM
5668: if(REG8(AL) == 1) {
5669: REG8(BH) = 0x00; // not in ROM
5670: } else {
5671: REG8(BH) = 0xff; // OEM = Microsoft
5672: }
1.1.1.9 root 5673: REG8(AL) = major_version; // 7
5674: REG8(AH) = minor_version; // 10
1.1 root 5675: }
5676:
5677: inline void msdos_int_21h_31h()
5678: {
1.1.1.14 root 5679: msdos_mem_realloc(current_psp, REG16(DX), NULL);
1.1 root 5680: msdos_process_terminate(current_psp, REG8(AL) | 0x300, 0);
5681: }
5682:
5683: inline void msdos_int_21h_32h()
5684: {
5685: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
5686: UINT16 seg, ofs;
5687:
5688: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
5689: REG8(AL) = 0;
1.1.1.3 root 5690: SREG(DS) = seg;
5691: i386_load_segment_descriptor(DS);
1.1 root 5692: REG16(BX) = ofs;
5693: } else {
5694: REG8(AL) = 0xff;
1.1.1.3 root 5695: m_CF = 1;
1.1 root 5696: }
5697: }
5698:
5699: inline void msdos_int_21h_33h()
5700: {
5701: char path[MAX_PATH];
5702:
5703: switch(REG8(AL)) {
5704: case 0x00:
1.1.1.26! root 5705: REG8(DL) = ctrl_c_checking;
1.1 root 5706: break;
5707: case 0x01:
1.1.1.26! root 5708: ctrl_c_checking = REG8(DL);
1.1 root 5709: break;
5710: case 0x05:
5711: GetSystemDirectory(path, MAX_PATH);
5712: if(path[0] >= 'a' && path[0] <= 'z') {
5713: REG8(DL) = path[0] - 'a' + 1;
5714: } else {
5715: REG8(DL) = path[0] - 'A' + 1;
5716: }
5717: break;
5718: case 0x06:
1.1.1.2 root 5719: // MS-DOS version (7.10)
1.1 root 5720: REG8(BL) = 7;
1.1.1.2 root 5721: REG8(BH) = 10;
1.1 root 5722: REG8(DL) = 0;
5723: REG8(DH) = 0x10; // in HMA
5724: break;
1.1.1.6 root 5725: case 0x07:
5726: if(REG8(DL) == 0) {
5727: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag &= ~0x20;
5728: } else if(REG8(DL) == 1) {
5729: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag |= 0x20;
5730: }
5731: break;
1.1 root 5732: default:
1.1.1.22 root 5733: 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 5734: REG16(AX) = 0x01;
1.1.1.3 root 5735: m_CF = 1;
1.1 root 5736: break;
5737: }
5738: }
5739:
1.1.1.23 root 5740: inline void msdos_int_21h_34h()
5741: {
5742: SREG(ES) = SDA_TOP >> 4;
5743: i386_load_segment_descriptor(ES);
5744: REG16(BX) = offsetof(sda_t, indos_flag);;
5745: }
5746:
1.1 root 5747: inline void msdos_int_21h_35h()
5748: {
5749: REG16(BX) = *(UINT16 *)(mem + 4 * REG8(AL) + 0);
1.1.1.3 root 5750: SREG(ES) = *(UINT16 *)(mem + 4 * REG8(AL) + 2);
5751: i386_load_segment_descriptor(ES);
1.1 root 5752: }
5753:
5754: inline void msdos_int_21h_36h()
5755: {
5756: struct _diskfree_t df = {0};
5757:
5758: if(_getdiskfree(REG8(DL), &df) == 0) {
5759: REG16(AX) = (UINT16)df.sectors_per_cluster;
5760: REG16(CX) = (UINT16)df.bytes_per_sector;
1.1.1.13 root 5761: REG16(BX) = df.avail_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.avail_clusters;
5762: REG16(DX) = df.total_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.total_clusters;
1.1 root 5763: } else {
5764: REG16(AX) = 0xffff;
5765: }
5766: }
5767:
5768: inline void msdos_int_21h_37h()
5769: {
1.1.1.22 root 5770: static UINT8 dev_flag = 0xff;
1.1 root 5771:
5772: switch(REG8(AL)) {
5773: case 0x00:
1.1.1.22 root 5774: {
5775: process_t *process = msdos_process_info_get(current_psp);
5776: REG8(AL) = 0x00;
5777: REG8(DL) = process->switchar;
5778: }
1.1 root 5779: break;
5780: case 0x01:
1.1.1.22 root 5781: {
5782: process_t *process = msdos_process_info_get(current_psp);
5783: REG8(AL) = 0x00;
5784: process->switchar = REG8(DL);
1.1.1.23 root 5785: msdos_sda_update(current_psp);
1.1.1.22 root 5786: }
5787: break;
5788: case 0x02:
5789: REG8(DL) = dev_flag;
5790: break;
5791: case 0x03:
5792: dev_flag = REG8(DL);
5793: break;
5794: case 0xd0:
5795: case 0xd1:
5796: case 0xd2:
5797: case 0xd3:
5798: case 0xd4:
5799: case 0xd5:
5800: case 0xd6:
5801: case 0xd7:
5802: case 0xdc:
5803: case 0xdd:
5804: case 0xde:
5805: case 0xdf:
5806: // diet ???
5807: REG16(AX) = 1;
1.1 root 5808: break;
5809: default:
1.1.1.22 root 5810: 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 5811: REG16(AX) = 1;
5812: break;
5813: }
5814: }
5815:
1.1.1.19 root 5816: int get_country_info(country_info_t *ci)
1.1.1.17 root 5817: {
5818: char LCdata[80];
5819:
1.1.1.19 root 5820: ZeroMemory(ci, offsetof(country_info_t, reserved));
1.1.1.17 root 5821: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRDIGITS, LCdata, sizeof(LCdata));
5822: ci->currency_dec_digits = atoi(LCdata);
5823: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRENCY, LCdata, sizeof(LCdata));
5824: ci->currency_format = *LCdata - '0';
5825: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDATE, LCdata, sizeof(LCdata));
5826: ci->date_format = *LCdata - '0';
5827: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SCURRENCY, LCdata, sizeof(LCdata));
5828: memcpy(&ci->currency_symbol, LCdata, 4);
5829: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDATE, LCdata, sizeof(LCdata));
5830: *ci->date_sep = *LCdata;
5831: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, LCdata, sizeof(LCdata));
5832: *ci->dec_sep = *LCdata;
5833: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SLIST, LCdata, sizeof(LCdata));
5834: *ci->list_sep = *LCdata;
5835: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, LCdata, sizeof(LCdata));
5836: *ci->thou_sep = *LCdata;
5837: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIME, LCdata, sizeof(LCdata));
5838: *ci->time_sep = *LCdata;
5839: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIMEFORMAT, LCdata, sizeof(LCdata));
5840: if(strchr(LCdata, 'H') != NULL) {
5841: ci->time_format = 1;
5842: }
1.1.1.24 root 5843: ci->case_map.w.l = 0x000c; // FFFD:000C
5844: ci->case_map.w.h = 0xfffd;
1.1.1.17 root 5845: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICOUNTRY, LCdata, sizeof(LCdata));
5846: return atoi(LCdata);
5847: }
5848:
1.1.1.14 root 5849: inline void msdos_int_21h_38h()
5850: {
5851: switch(REG8(AL)) {
5852: case 0x00:
1.1.1.19 root 5853: REG16(BX) = get_country_info((country_info_t *)(mem + SREG_BASE(DS) + REG16(DX)));
1.1.1.14 root 5854: break;
5855: default:
1.1.1.22 root 5856: 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 5857: REG16(AX) = 2;
5858: m_CF = 1;
5859: break;
5860: }
5861: }
5862:
1.1 root 5863: inline void msdos_int_21h_39h(int lfn)
5864: {
1.1.1.3 root 5865: if(_mkdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 5866: REG16(AX) = errno;
1.1.1.3 root 5867: m_CF = 1;
1.1 root 5868: }
5869: }
5870:
5871: inline void msdos_int_21h_3ah(int lfn)
5872: {
1.1.1.3 root 5873: if(_rmdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 5874: REG16(AX) = errno;
1.1.1.3 root 5875: m_CF = 1;
1.1 root 5876: }
5877: }
5878:
5879: inline void msdos_int_21h_3bh(int lfn)
5880: {
1.1.1.3 root 5881: if(_chdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1.1.17 root 5882: REG16(AX) = 3; // must be 3 (path not found)
1.1.1.3 root 5883: m_CF = 1;
1.1 root 5884: }
5885: }
5886:
5887: inline void msdos_int_21h_3ch()
5888: {
1.1.1.3 root 5889: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 5890: int attr = GetFileAttributes(path);
5891: int fd = -1;
1.1.1.11 root 5892: UINT16 info;
1.1 root 5893:
1.1.1.11 root 5894: if(msdos_is_con_path(path)) {
5895: fd = _open("CON", _O_WRONLY | _O_BINARY);
5896: info = 0x80d3;
1.1.1.14 root 5897: } else if(msdos_is_nul_path(path)) {
5898: fd = _open("NUL", _O_WRONLY | _O_BINARY);
5899: info = 0x80d3;
1.1.1.24 root 5900: } else if(msdos_is_driver_name(path)) {
1.1.1.20 root 5901: fd = _open("NUL", _O_WRONLY | _O_BINARY);
5902: info = 0x80d3;
1.1 root 5903: } else {
5904: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
1.1.1.11 root 5905: info = msdos_drive_number(path);
1.1 root 5906: }
5907: if(fd != -1) {
5908: if(attr == -1) {
5909: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
5910: }
5911: SetFileAttributes(path, attr);
5912: REG16(AX) = fd;
1.1.1.11 root 5913: msdos_file_handler_open(fd, path, _isatty(fd), 2, info, current_psp);
1.1.1.20 root 5914: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 5915: } else {
5916: REG16(AX) = errno;
1.1.1.3 root 5917: m_CF = 1;
1.1 root 5918: }
5919: }
5920:
5921: inline void msdos_int_21h_3dh()
5922: {
1.1.1.3 root 5923: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 5924: int mode = REG8(AL) & 0x03;
1.1.1.11 root 5925: int fd = -1;
5926: UINT16 info;
1.1 root 5927:
5928: if(mode < 0x03) {
1.1.1.11 root 5929: if(msdos_is_con_path(path)) {
1.1.1.13 root 5930: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 5931: info = 0x80d3;
1.1.1.14 root 5932: } else if(msdos_is_nul_path(path)) {
5933: fd = msdos_open("NUL", file_mode[mode].mode);
5934: info = 0x80d3;
1.1.1.24 root 5935: } else if(msdos_is_driver_name(path)) {
1.1.1.20 root 5936: fd = msdos_open("NUL", file_mode[mode].mode);
5937: info = 0x80d3;
1.1.1.11 root 5938: } else {
1.1.1.13 root 5939: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 5940: info = msdos_drive_number(path);
5941: }
1.1 root 5942: if(fd != -1) {
5943: REG16(AX) = fd;
1.1.1.11 root 5944: msdos_file_handler_open(fd, path, _isatty(fd), mode, info, current_psp);
1.1.1.20 root 5945: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 5946: } else {
5947: REG16(AX) = errno;
1.1.1.3 root 5948: m_CF = 1;
1.1 root 5949: }
5950: } else {
5951: REG16(AX) = 0x0c;
1.1.1.3 root 5952: m_CF = 1;
1.1 root 5953: }
5954: }
5955:
5956: inline void msdos_int_21h_3eh()
5957: {
5958: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 5959: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 5960:
1.1.1.20 root 5961: if(fd < process->max_files && file_handler[fd].valid) {
5962: _close(fd);
5963: msdos_file_handler_close(fd);
5964: msdos_psp_set_file_table(REG16(BX), 0x0ff, current_psp);
1.1 root 5965: } else {
5966: REG16(AX) = 0x06;
1.1.1.3 root 5967: m_CF = 1;
1.1 root 5968: }
5969: }
5970:
5971: inline void msdos_int_21h_3fh()
5972: {
5973: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 5974: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 5975:
1.1.1.20 root 5976: if(fd < process->max_files && file_handler[fd].valid) {
5977: if(file_mode[file_handler[fd].mode].in) {
5978: if(file_handler[fd].atty) {
1.1 root 5979: // BX is stdin or is redirected to stdin
1.1.1.3 root 5980: UINT8 *buf = mem + SREG_BASE(DS) + REG16(DX);
1.1 root 5981: int max = REG16(CX);
5982: int p = 0;
5983:
5984: while(max > p) {
5985: int chr = msdos_getch();
5986:
1.1.1.26! root 5987: if(ctrl_c_pressed) {
! 5988: p = 0;
! 5989: buf[p++] = 0x0d;
! 5990: if(max > p) {
! 5991: buf[p++] = 0x0a;
! 5992: }
! 5993: msdos_putch(chr);
! 5994: msdos_putch('\n');
! 5995: break;
! 5996: } else if(chr == 0x00) {
1.1 root 5997: // skip 2nd byte
5998: msdos_getch();
5999: } else if(chr == 0x0d) {
6000: // carriage return
6001: buf[p++] = 0x0d;
6002: if(max > p) {
6003: buf[p++] = 0x0a;
6004: }
1.1.1.14 root 6005: msdos_putch('\n');
1.1 root 6006: break;
6007: } else if(chr == 0x08) {
6008: // back space
6009: if(p > 0) {
6010: p--;
1.1.1.20 root 6011: if(msdos_ctrl_code_check(buf[p])) {
6012: msdos_putch(chr);
6013: msdos_putch(chr);
6014: msdos_putch(' ');
6015: msdos_putch(' ');
6016: msdos_putch(chr);
6017: msdos_putch(chr);
6018: } else {
6019: msdos_putch(chr);
6020: msdos_putch(' ');
6021: msdos_putch(chr);
6022: }
1.1 root 6023: }
6024: } else {
6025: buf[p++] = chr;
6026: msdos_putch(chr);
6027: }
6028: }
6029: REG16(AX) = p;
1.1.1.26! root 6030:
1.1.1.8 root 6031: // some seconds may be passed in console
1.1 root 6032: hardware_update();
6033: } else {
1.1.1.20 root 6034: REG16(AX) = _read(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 6035: }
6036: } else {
6037: REG16(AX) = 0x05;
1.1.1.3 root 6038: m_CF = 1;
1.1 root 6039: }
6040: } else {
6041: REG16(AX) = 0x06;
1.1.1.3 root 6042: m_CF = 1;
1.1 root 6043: }
6044: }
6045:
6046: inline void msdos_int_21h_40h()
6047: {
6048: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 6049: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 6050:
1.1.1.20 root 6051: if(fd < process->max_files && file_handler[fd].valid) {
6052: if(file_mode[file_handler[fd].mode].out) {
1.1 root 6053: if(REG16(CX)) {
1.1.1.20 root 6054: if(file_handler[fd].atty) {
1.1 root 6055: // BX is stdout/stderr or is redirected to stdout
6056: for(int i = 0; i < REG16(CX); i++) {
1.1.1.3 root 6057: msdos_putch(mem[SREG_BASE(DS) + REG16(DX) + i]);
1.1 root 6058: }
6059: REG16(AX) = REG16(CX);
6060: } else {
1.1.1.20 root 6061: REG16(AX) = msdos_write(fd, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 6062: }
6063: } else {
1.1.1.20 root 6064: UINT32 pos = _tell(fd);
6065: _lseek(fd, 0, SEEK_END);
6066: UINT32 size = _tell(fd);
1.1.1.12 root 6067: if(pos < size) {
1.1.1.20 root 6068: _lseek(fd, pos, SEEK_SET);
6069: SetEndOfFile((HANDLE)_get_osfhandle(fd));
1.1.1.12 root 6070: } else {
6071: for(UINT32 i = size; i < pos; i++) {
6072: UINT8 tmp = 0;
1.1.1.23 root 6073: msdos_write(fd, &tmp, 1);
1.1.1.12 root 6074: }
1.1.1.20 root 6075: _lseek(fd, pos, SEEK_SET);
1.1 root 6076: }
1.1.1.23 root 6077: REG16(AX) = 0;
1.1 root 6078: }
6079: } else {
6080: REG16(AX) = 0x05;
1.1.1.3 root 6081: m_CF = 1;
1.1 root 6082: }
6083: } else {
6084: REG16(AX) = 0x06;
1.1.1.3 root 6085: m_CF = 1;
1.1 root 6086: }
6087: }
6088:
6089: inline void msdos_int_21h_41h(int lfn)
6090: {
1.1.1.3 root 6091: if(remove(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 6092: REG16(AX) = errno;
1.1.1.3 root 6093: m_CF = 1;
1.1 root 6094: }
6095: }
6096:
6097: inline void msdos_int_21h_42h()
6098: {
6099: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 6100: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 6101:
1.1.1.20 root 6102: if(fd < process->max_files && file_handler[fd].valid) {
1.1 root 6103: if(REG8(AL) < 0x03) {
6104: static int ptrname[] = { SEEK_SET, SEEK_CUR, SEEK_END };
1.1.1.20 root 6105: _lseek(fd, (REG16(CX) << 16) | REG16(DX), ptrname[REG8(AL)]);
6106: UINT32 pos = _tell(fd);
1.1 root 6107: REG16(AX) = pos & 0xffff;
6108: REG16(DX) = (pos >> 16);
6109: } else {
6110: REG16(AX) = 0x01;
1.1.1.3 root 6111: m_CF = 1;
1.1 root 6112: }
6113: } else {
6114: REG16(AX) = 0x06;
1.1.1.3 root 6115: m_CF = 1;
1.1 root 6116: }
6117: }
6118:
6119: inline void msdos_int_21h_43h(int lfn)
6120: {
1.1.1.3 root 6121: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn);
1.1 root 6122: int attr;
6123:
1.1.1.14 root 6124: if(!lfn && REG8(AL) > 2) {
6125: REG16(AX) = 0x01;
6126: m_CF = 1;
6127: return;
6128: }
6129: switch(REG8(lfn ? BL : AL)) {
1.1 root 6130: case 0x00:
6131: if((attr = GetFileAttributes(path)) != -1) {
1.1.1.14 root 6132: REG16(CX) = (UINT16)msdos_file_attribute_create((UINT16)attr);
6133: } else {
6134: REG16(AX) = (UINT16)GetLastError();
6135: m_CF = 1;
6136: }
6137: break;
6138: case 0x01:
6139: if(!SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)))) {
6140: REG16(AX) = (UINT16)GetLastError();
6141: m_CF = 1;
6142: }
6143: break;
6144: case 0x02:
6145: {
6146: DWORD size = GetCompressedFileSize(path, NULL);
6147: if(size != INVALID_FILE_SIZE) {
6148: if(size != 0 && size == GetFileSize(path, NULL)) {
6149: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
6150: // this isn't correct if the file is in the NTFS MFT
6151: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
6152: size = ((size - 1) | (sectors_per_cluster * bytes_per_sector - 1)) + 1;
6153: }
6154: }
6155: REG16(AX) = LOWORD(size);
6156: REG16(DX) = HIWORD(size);
6157: } else {
6158: REG16(AX) = (UINT16)GetLastError();
6159: m_CF = 1;
1.1 root 6160: }
1.1.1.14 root 6161: }
6162: break;
6163: case 0x03:
6164: case 0x05:
6165: case 0x07:
6166: {
6167: HANDLE hFile = CreateFile(path, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
6168: if(hFile != INVALID_HANDLE_VALUE) {
6169: FILETIME local, time;
6170: DosDateTimeToFileTime(REG16(DI), /*REG8(BL) == 5 ? 0 : */REG16(CX), &local);
6171: if(REG8(BL) == 7) {
6172: ULARGE_INTEGER hund;
6173: hund.LowPart = local.dwLowDateTime;
6174: hund.HighPart = local.dwHighDateTime;
6175: hund.QuadPart += REG16(SI) * 100000;
6176: local.dwLowDateTime = hund.LowPart;
6177: local.dwHighDateTime = hund.HighPart;
6178: }
6179: LocalFileTimeToFileTime(&local, &time);
6180: if(!SetFileTime(hFile, REG8(BL) == 0x07 ? &time : NULL,
6181: REG8(BL) == 0x05 ? &time : NULL,
6182: REG8(BL) == 0x03 ? &time : NULL)) {
6183: REG16(AX) = (UINT16)GetLastError();
6184: m_CF = 1;
6185: }
6186: CloseHandle(hFile);
6187: } else {
6188: REG16(AX) = (UINT16)GetLastError();
6189: m_CF = 1;
1.1 root 6190: }
1.1.1.14 root 6191: }
6192: break;
6193: case 0x04:
6194: case 0x06:
6195: case 0x08:
6196: {
6197: WIN32_FILE_ATTRIBUTE_DATA fad;
6198: if(GetFileAttributesEx(path, GetFileExInfoStandard, (LPVOID)&fad)) {
6199: FILETIME *time, local;
6200: time = REG8(BL) == 0x04 ? &fad.ftLastWriteTime :
6201: 0x06 ? &fad.ftLastAccessTime :
6202: &fad.ftCreationTime;
6203: FileTimeToLocalFileTime(time, &local);
6204: FileTimeToDosDateTime(&local, ®16(DI), ®16(CX));
6205: if(REG8(BL) == 0x08) {
6206: ULARGE_INTEGER hund;
6207: hund.LowPart = local.dwLowDateTime;
6208: hund.HighPart = local.dwHighDateTime;
6209: hund.QuadPart /= 100000;
6210: REG16(SI) = (UINT16)(hund.QuadPart % 200);
6211: }
6212: } else {
6213: REG16(AX) = (UINT16)GetLastError();
6214: m_CF = 1;
1.1 root 6215: }
1.1.1.14 root 6216: }
6217: break;
6218: default:
1.1.1.22 root 6219: 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 6220: REG16(AX) = 0x01;
6221: m_CF = 1;
6222: break;
6223: }
6224: }
6225:
6226: inline void msdos_int_21h_44h()
6227: {
1.1.1.22 root 6228: static UINT16 iteration_count = 0;
6229:
1.1.1.20 root 6230: process_t *process = msdos_process_info_get(current_psp);
6231: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
6232:
1.1.1.14 root 6233: UINT32 val = DRIVE_NO_ROOT_DIR;
6234:
6235: switch(REG8(AL)) {
6236: case 0x00:
6237: case 0x01:
6238: case 0x02:
6239: case 0x03:
6240: case 0x04:
6241: case 0x05:
6242: case 0x06:
6243: case 0x07:
1.1.1.20 root 6244: if(fd >= process->max_files || !file_handler[fd].valid) {
6245: REG16(AX) = 0x06;
6246: m_CF = 1;
6247: return;
1.1.1.14 root 6248: }
6249: break;
6250: case 0x08:
6251: case 0x09:
6252: if(REG8(BL) >= ('Z' - 'A' + 1)) {
6253: // invalid drive number
6254: REG16(AX) = 0x0f;
6255: m_CF = 1;
6256: return;
6257: } else {
6258: if(REG8(BL) == 0) {
6259: val = GetDriveType(NULL);
6260: } else {
6261: char tmp[8];
6262: sprintf(tmp, "%c:\\", 'A' + REG8(BL) - 1);
6263: val = GetDriveType(tmp);
6264: }
6265: if(val == DRIVE_NO_ROOT_DIR) {
6266: // no drive
6267: REG16(AX) = 0x0f;
6268: m_CF = 1;
6269: return;
1.1 root 6270: }
6271: }
6272: break;
6273: }
6274: switch(REG8(AL)) {
6275: case 0x00: // get ioctrl data
1.1.1.20 root 6276: REG16(DX) = file_handler[fd].info;
1.1 root 6277: break;
6278: case 0x01: // set ioctrl data
1.1.1.20 root 6279: file_handler[fd].info |= REG8(DL);
1.1 root 6280: break;
6281: case 0x02: // recv from character device
6282: case 0x03: // send to character device
6283: case 0x04: // recv from block device
6284: case 0x05: // send to block device
6285: REG16(AX) = 0x05;
1.1.1.3 root 6286: m_CF = 1;
1.1 root 6287: break;
6288: case 0x06: // get read status
1.1.1.20 root 6289: if(file_mode[file_handler[fd].mode].in) {
6290: if(file_handler[fd].atty) {
1.1.1.14 root 6291: REG8(AL) = msdos_kbhit() ? 0xff : 0x00;
1.1 root 6292: } else {
1.1.1.20 root 6293: REG8(AL) = eof(fd) ? 0x00 : 0xff;
1.1 root 6294: }
1.1.1.14 root 6295: } else {
6296: REG8(AL) = 0x00;
1.1 root 6297: }
6298: break;
6299: case 0x07: // get write status
1.1.1.20 root 6300: if(file_mode[file_handler[fd].mode].out) {
1.1.1.14 root 6301: REG8(AL) = 0xff;
6302: } else {
6303: REG8(AL) = 0x00;
1.1 root 6304: }
6305: break;
6306: case 0x08: // check removable drive
1.1.1.14 root 6307: if(val == DRIVE_REMOVABLE || val == DRIVE_CDROM) {
6308: // removable drive
6309: REG16(AX) = 0x00;
1.1 root 6310: } else {
1.1.1.14 root 6311: // fixed drive
6312: REG16(AX) = 0x01;
1.1 root 6313: }
6314: break;
6315: case 0x09: // check remote drive
1.1.1.14 root 6316: if(val == DRIVE_REMOTE) {
6317: // remote drive
6318: REG16(DX) = 0x1000;
1.1 root 6319: } else {
1.1.1.14 root 6320: // local drive
6321: REG16(DX) = 0x00;
1.1 root 6322: }
6323: break;
1.1.1.21 root 6324: case 0x0a: // check remote handle
6325: REG16(DX) = 0x00; // FIXME
6326: break;
1.1 root 6327: case 0x0b: // set retry count
6328: break;
1.1.1.22 root 6329: case 0x0c: // generic character device request
6330: if(REG8(CL) == 0x45) {
6331: // set iteration (retry) count
6332: iteration_count = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX));
6333: } else if(REG8(CL) == 0x4a) {
6334: // select code page
6335: active_code_page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2);
6336: msdos_nls_tables_update();
6337: } else if(REG8(CL) == 0x65) {
6338: // get iteration (retry) count
6339: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX)) = iteration_count;
6340: } else if(REG8(CL) == 0x6a) {
6341: // query selected code page
6342: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = 2; // FIXME
6343: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 2) = active_code_page;
6344:
6345: CPINFO info;
6346: GetCPInfo(active_code_page, &info);
6347:
6348: if(info.MaxCharSize != 1) {
6349: for(int i = 0;; i++) {
6350: UINT8 lo = info.LeadByte[2 * i + 0];
6351: UINT8 hi = info.LeadByte[2 * i + 1];
6352:
6353: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4 + 4 * i + 0) = lo;
6354: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 4 + 4 * i + 2) = hi;
6355: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0) + 4;
6356:
6357: if(lo == 0 && hi == 0) {
6358: break;
6359: }
6360: }
6361: }
6362: } else if(REG8(CL) == 0x7f) {
6363: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x00) = 0;
6364: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x01) = 0;
6365: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x02) = 14;
6366: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x04) = 1;
6367: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x06) = 1;
6368: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x07) = 0;
6369: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x08) = 4;
6370: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0a) = 8 * (*(UINT16 *)(mem + 0x44a));
6371: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0c) = 16 * (*(UINT8 *)(mem + 0x484) + 1);
6372: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x0e) = *(UINT16 *)(mem + 0x44a);
6373: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(DX) + 0x10) = *(UINT8 *)(mem + 0x484) + 1;
6374: } else {
6375: 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));
6376: REG16(AX) = 0x01; // invalid function
6377: m_CF = 1;
6378: }
6379: break;
6380: case 0x0d: // generic block device request
6381: if(REG8(CL) == 0x40) {
6382: // set device parameters
6383: } else if(REG8(CL) == 0x46) {
6384: // set volume serial number
6385: } else if(REG8(CL) == 0x4a) {
6386: // lock logical volume
6387: } else if(REG8(CL) == 0x4b) {
6388: // lock physical volume
6389: } else if(REG8(CL) == 0x60) {
6390: // get device parameters
6391: char dev[] = "\\\\.\\A:";
6392: dev[4] = 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
6393:
6394: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
6395: if(hFile != INVALID_HANDLE_VALUE) {
6396: DISK_GEOMETRY geo;
6397: DWORD dwSize;
6398: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
6399: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x07; // ???
6400: switch(geo.MediaType) {
6401: case F5_360_512:
6402: case F5_320_512:
6403: case F5_320_1024:
6404: case F5_180_512:
6405: case F5_160_512:
6406: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x00; // 320K/360K disk
6407: break;
6408: case F5_1Pt2_512:
6409: case F3_1Pt2_512:
6410: case F3_1Pt23_1024:
6411: case F5_1Pt23_1024:
6412: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x01; // 1.2M disk
6413: break;
6414: case F3_720_512:
6415: case F3_640_512:
6416: case F5_640_512:
6417: case F5_720_512:
6418: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x02; // 720K disk
6419: break;
6420: case F8_256_128:
6421: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x03; // single-density 8-inch disk
6422: break;
6423: case FixedMedia:
6424: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // fixed disk
6425: break;
6426: case F3_1Pt44_512:
6427: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x07; // (DOS 3.3+) other type of block device, normally 1.44M floppy
6428: break;
6429: case F3_2Pt88_512:
6430: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x09; // (DOS 5+) 2.88M floppy
6431: break;
6432: default:
6433: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // fixed disk
6434: // *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x05; // (DOS 3.3+) other type of block device, normally 1.44M floppy
6435: break;
6436: }
6437: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x02) = (geo.MediaType == FixedMedia) ? 0x01 : 0x00;
6438: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04) = (geo.Cylinders.QuadPart > 0xffff) ? 0xffff : geo.Cylinders.QuadPart;
6439: switch(geo.MediaType) {
6440: case F5_360_512:
6441: case F5_320_512:
6442: case F5_320_1024:
6443: case F5_180_512:
6444: case F5_160_512:
6445: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06) = 0x01; // 320K/360K disk
6446: break;
6447: default:
6448: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06) = 0x00; // other drive types
6449: break;
6450: }
6451: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x00) = geo.BytesPerSector;
6452: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x02) = geo.SectorsPerTrack * geo.TracksPerCylinder;
6453: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x03) = 0;
6454: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x05) = 0;
6455: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x06) = 0;
6456: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x08) = 0;
6457: switch(geo.MediaType) {
6458: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K)
6459: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xff;
6460: break;
6461: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K)
6462: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfe;
6463: break;
6464: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K)
6465: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfd;
6466: break;
6467: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K)
6468: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xfc;
6469: break;
6470: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M)
6471: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5")
6472: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf9;
6473: break;
6474: case FixedMedia: // hard disk
6475: case RemovableMedia:
6476: case Unknown:
6477: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf8;
6478: break;
6479: default:
6480: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0a) = 0xf0;
6481: break;
6482: }
6483: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0d) = geo.SectorsPerTrack;
6484: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x0f) = 1;
6485: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x11) = 0;
6486: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x15) = geo.TracksPerCylinder * geo.Cylinders.QuadPart;
6487: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07 + 0x1f) = geo.Cylinders.QuadPart;
6488: // 21h BYTE device type
6489: // 22h WORD device attributes (removable or not, etc)
6490: } else {
6491: REG16(AX) = 0x0f; // invalid drive
6492: m_CF = 1;
6493: }
6494: CloseHandle(hFile);
6495: } else {
6496: REG16(AX) = 0x0f; // invalid drive
6497: m_CF = 1;
6498: }
6499: } else if(REG8(CL) == 0x66) {
6500: // get volume serial number
6501: char path[] = "A:\\";
6502: char volume_label[MAX_PATH];
6503: DWORD serial_number = 0;
6504: char file_system[MAX_PATH];
6505:
6506: path[0] = 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1;
6507:
6508: if(GetVolumeInformation(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) {
6509: *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0;
6510: *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x02) = serial_number;
6511: memset(mem + SREG_BASE(DS) + REG16(SI) + 0x06, 0x20, 11);
6512: memcpy(mem + SREG_BASE(DS) + REG16(SI) + 0x06, volume_label, min(strlen(volume_label), 11));
6513: memset(mem + SREG_BASE(DS) + REG16(SI) + 0x11, 0x20, 8);
6514: memcpy(mem + SREG_BASE(DS) + REG16(SI) + 0x11, file_system, min(strlen(file_system), 8));
6515: } else {
6516: REG16(AX) = 0x0f; // invalid drive
6517: m_CF = 1;
6518: }
6519: } else if(REG8(CL) == 0x67) {
6520: // get access flag
6521: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0;
6522: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 1;
6523: } else if(REG8(CL) == 0x68) {
6524: // sense media type
6525: char dev[64];
6526: sprintf(dev, "\\\\.\\%c:", 'A' + (REG8(BL) ? REG8(BL) : _getdrive()) - 1);
6527:
6528: HANDLE hFile = CreateFile(dev, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
6529: if(hFile != INVALID_HANDLE_VALUE) {
6530: DISK_GEOMETRY geo;
6531: DWORD dwSize;
6532: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
6533: switch(geo.MediaType) {
6534: case F3_720_512:
6535: case F5_720_512:
6536: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
6537: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x02;
6538: break;
6539: case F3_1Pt44_512:
6540: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
6541: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x07;
6542: break;
6543: case F3_2Pt88_512:
6544: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x01;
6545: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x09;
6546: break;
6547: default:
6548: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00) = 0x00;
6549: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x01) = 0x00; // ???
6550: break;
6551: }
6552: } else {
6553: REG16(AX) = 0x0f; // invalid drive
6554: m_CF = 1;
6555: }
6556: CloseHandle(hFile);
6557: } else {
6558: REG16(AX) = 0x0f; // invalid drive
6559: m_CF = 1;
6560: }
6561: } else if(REG8(CL) == 0x6a) {
6562: // unlock logical volume
6563: } else if(REG8(CL) == 0x6b) {
6564: // unlock physical volume
6565: } else {
6566: 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));
6567: REG16(AX) = 0x01; // invalid function
6568: m_CF = 1;
6569: }
6570: break;
6571: case 0x0e: // get logical drive map
6572: {
6573: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
6574: if(!(GetLogicalDrives() & bits)) {
6575: REG16(AX) = 0x0f; // invalid drive
6576: m_CF = 1;
6577: } else {
6578: REG8(AL) = 0;
6579: }
6580: }
6581: break;
6582: case 0x0f: // set logical drive map
6583: {
6584: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
6585: if(!(GetLogicalDrives() & bits)) {
6586: REG16(AX) = 0x0f; // invalid drive
6587: m_CF = 1;
6588: }
6589: }
6590: break;
6591: case 0x10: // query generic ioctrl capability (handle)
6592: switch(REG8(CL)) {
6593: case 0x45:
6594: case 0x4a:
6595: case 0x65:
6596: case 0x6a:
6597: case 0x7f:
6598: REG16(AX) = 0x0000; // supported
6599: break;
6600: default:
6601: REG8(AL) = 0x01; // ioctl capability not available
6602: m_CF = 1;
6603: break;
6604: }
6605: break;
6606: case 0x11: // query generic ioctrl capability (drive)
6607: switch(REG8(CL)) {
6608: case 0x40:
6609: case 0x46:
6610: case 0x4a:
6611: case 0x4b:
6612: case 0x60:
6613: case 0x66:
6614: case 0x67:
6615: case 0x68:
6616: case 0x6a:
6617: case 0x6b:
6618: REG16(AX) = 0x0000; // supported
6619: break;
6620: default:
6621: REG8(AL) = 0x01; // ioctl capability not available
6622: m_CF = 1;
6623: break;
6624: }
6625: break;
6626: case 0x12: // determine dos type
6627: case 0x51: // concurrent dos v3.2+ - installation check
6628: case 0x52: // determine dos type/get dr dos versuin
6629: REG16(AX) = 0x01; // this is not DR-DOS
6630: m_CF = 1;
6631: break;
1.1 root 6632: default:
1.1.1.22 root 6633: 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 6634: REG16(AX) = 0x01;
1.1.1.3 root 6635: m_CF = 1;
1.1 root 6636: break;
6637: }
6638: }
6639:
6640: inline void msdos_int_21h_45h()
6641: {
6642: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 6643: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 6644:
1.1.1.20 root 6645: if(fd < process->max_files && file_handler[fd].valid) {
6646: int dup_fd = _dup(fd);
6647: if(dup_fd != -1) {
6648: REG16(AX) = dup_fd;
6649: msdos_file_handler_dup(dup_fd, fd, current_psp);
6650: // msdos_psp_set_file_table(dup_fd, fd, current_psp);
6651: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp);
1.1 root 6652: } else {
6653: REG16(AX) = errno;
1.1.1.3 root 6654: m_CF = 1;
1.1 root 6655: }
6656: } else {
6657: REG16(AX) = 0x06;
1.1.1.3 root 6658: m_CF = 1;
1.1 root 6659: }
6660: }
6661:
6662: inline void msdos_int_21h_46h()
6663: {
6664: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 6665: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
6666: int dup_fd = REG16(CX);
6667: int tmp_fd = msdos_psp_get_file_table(REG16(CX), current_psp);
1.1 root 6668:
1.1.1.20 root 6669: if(REG16(BX) == REG16(CX)) {
6670: REG16(AX) = 0x06;
6671: m_CF = 1;
6672: } else if(fd < process->max_files && file_handler[fd].valid && dup_fd < process->max_files) {
6673: if(tmp_fd < process->max_files && file_handler[tmp_fd].valid) {
6674: _close(tmp_fd);
6675: msdos_file_handler_close(tmp_fd);
6676: msdos_psp_set_file_table(dup_fd, 0x0ff, current_psp);
6677: }
6678: if(_dup2(fd, dup_fd) != -1) {
6679: msdos_file_handler_dup(dup_fd, fd, current_psp);
6680: // msdos_psp_set_file_table(dup_fd, fd, current_psp);
6681: msdos_psp_set_file_table(dup_fd, dup_fd, current_psp);
1.1 root 6682: } else {
6683: REG16(AX) = errno;
1.1.1.3 root 6684: m_CF = 1;
1.1 root 6685: }
6686: } else {
6687: REG16(AX) = 0x06;
1.1.1.3 root 6688: m_CF = 1;
1.1 root 6689: }
6690: }
6691:
6692: inline void msdos_int_21h_47h(int lfn)
6693: {
6694: char path[MAX_PATH];
6695:
6696: if(_getdcwd(REG8(DL), path, MAX_PATH) != NULL) {
6697: if(path[1] == ':') {
6698: // the returned path does not include a drive or the initial backslash
1.1.1.3 root 6699: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), (lfn ? path : msdos_short_path(path)) + 3);
1.1 root 6700: } else {
1.1.1.3 root 6701: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn ? path : msdos_short_path(path));
1.1 root 6702: }
6703: } else {
6704: REG16(AX) = errno;
1.1.1.3 root 6705: m_CF = 1;
1.1 root 6706: }
6707: }
6708:
6709: inline void msdos_int_21h_48h()
6710: {
1.1.1.19 root 6711: int seg, umb_linked;
1.1 root 6712:
1.1.1.8 root 6713: if((malloc_strategy & 0xf0) == 0x00) {
1.1.1.19 root 6714: // unlink umb not to allocate memory in umb
6715: if((umb_linked = msdos_mem_get_umb_linked()) != 0) {
6716: msdos_mem_unlink_umb();
6717: }
1.1.1.8 root 6718: if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
6719: REG16(AX) = seg;
6720: } else {
6721: REG16(AX) = 0x08;
6722: REG16(BX) = msdos_mem_get_free(first_mcb, 0);
6723: m_CF = 1;
6724: }
1.1.1.19 root 6725: if(umb_linked != 0) {
6726: msdos_mem_link_umb();
6727: }
1.1.1.8 root 6728: } else if((malloc_strategy & 0xf0) == 0x40) {
6729: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
6730: REG16(AX) = seg;
6731: } else {
6732: REG16(AX) = 0x08;
6733: REG16(BX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
6734: m_CF = 1;
6735: }
6736: } else if((malloc_strategy & 0xf0) == 0x80) {
6737: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
6738: REG16(AX) = seg;
6739: } else if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
6740: REG16(AX) = seg;
6741: } else {
6742: REG16(AX) = 0x08;
6743: REG16(BX) = max(msdos_mem_get_free(UMB_TOP >> 4, 0), msdos_mem_get_free(first_mcb, 0));
6744: m_CF = 1;
6745: }
1.1 root 6746: }
6747: }
6748:
6749: inline void msdos_int_21h_49h()
6750: {
1.1.1.14 root 6751: int mcb_seg = SREG(ES) - 1;
6752: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
6753:
6754: if(mcb->mz == 'M' || mcb->mz == 'Z') {
6755: msdos_mem_free(SREG(ES));
6756: } else {
6757: REG16(AX) = 9;
6758: m_CF = 1;
6759: }
1.1 root 6760: }
6761:
6762: inline void msdos_int_21h_4ah()
6763: {
1.1.1.14 root 6764: int mcb_seg = SREG(ES) - 1;
6765: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1 root 6766: int max_paragraphs;
6767:
1.1.1.14 root 6768: if(mcb->mz == 'M' || mcb->mz == 'Z') {
6769: if(msdos_mem_realloc(SREG(ES), REG16(BX), &max_paragraphs)) {
6770: REG16(AX) = 0x08;
6771: REG16(BX) = max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs;
6772: m_CF = 1;
6773: }
6774: } else {
6775: REG16(AX) = 7;
1.1.1.3 root 6776: m_CF = 1;
1.1 root 6777: }
6778: }
6779:
6780: inline void msdos_int_21h_4bh()
6781: {
1.1.1.3 root 6782: char *command = (char *)(mem + SREG_BASE(DS) + REG16(DX));
6783: param_block_t *param = (param_block_t *)(mem + SREG_BASE(ES) + REG16(BX));
1.1 root 6784:
6785: switch(REG8(AL)) {
6786: case 0x00:
6787: case 0x01:
6788: if(msdos_process_exec(command, param, REG8(AL))) {
6789: REG16(AX) = 0x02;
1.1.1.3 root 6790: m_CF = 1;
1.1 root 6791: }
6792: break;
1.1.1.14 root 6793: case 0x03:
6794: {
6795: int fd;
6796: if((fd = _open(command, _O_RDONLY | _O_BINARY)) == -1) {
6797: REG16(AX) = 0x02;
6798: m_CF = 1;
6799: break;
6800: }
6801: int size = _read(fd, file_buffer, sizeof(file_buffer));
6802: _close(fd);
6803:
6804: UINT16 *overlay = (UINT16 *)param;
6805:
6806: // check exe header
6807: exe_header_t *header = (exe_header_t *)file_buffer;
6808: int header_size = 0;
6809: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
6810: header_size = header->header_size * 16;
6811: // relocation
6812: int start_seg = overlay[1];
6813: for(int i = 0; i < header->relocations; i++) {
6814: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
6815: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
6816: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
6817: }
6818: }
6819: memcpy(mem + (overlay[0] << 4), file_buffer + header_size, size - header_size);
6820: }
6821: break;
1.1 root 6822: default:
1.1.1.22 root 6823: 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 6824: REG16(AX) = 0x01;
1.1.1.3 root 6825: m_CF = 1;
1.1 root 6826: break;
6827: }
6828: }
6829:
6830: inline void msdos_int_21h_4ch()
6831: {
6832: msdos_process_terminate(current_psp, REG8(AL), 1);
6833: }
6834:
6835: inline void msdos_int_21h_4dh()
6836: {
6837: REG16(AX) = retval;
6838: }
6839:
6840: inline void msdos_int_21h_4eh()
6841: {
6842: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 6843: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
6844: find_t *find = (find_t *)(mem + dta_laddr);
1.1.1.3 root 6845: char *path = msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 6846: WIN32_FIND_DATA fd;
6847:
1.1.1.14 root 6848: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
6849: find->find_magic = FIND_MAGIC;
6850: find->dta_index = dtainfo - dtalist;
1.1 root 6851: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 6852: dtainfo->allowable_mask = REG8(CL);
6853: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 6854:
1.1.1.14 root 6855: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
6856: dtainfo->allowable_mask &= ~8;
1.1 root 6857: }
1.1.1.14 root 6858: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
6859: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 6860: !msdos_find_file_has_8dot3name(&fd)) {
6861: if(!FindNextFile(dtainfo->find_handle, &fd)) {
6862: FindClose(dtainfo->find_handle);
6863: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6864: break;
6865: }
6866: }
6867: }
1.1.1.13 root 6868: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 6869: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
6870: msdos_find_file_conv_local_time(&fd);
6871: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
6872: find->size = fd.nFileSizeLow;
1.1.1.13 root 6873: strcpy(find->name, msdos_short_name(&fd));
1.1 root 6874: REG16(AX) = 0;
1.1.1.14 root 6875: } else if(dtainfo->allowable_mask & 8) {
1.1 root 6876: find->attrib = 8;
6877: find->size = 0;
6878: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 6879: dtainfo->allowable_mask &= ~8;
1.1 root 6880: REG16(AX) = 0;
6881: } else {
6882: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 6883: m_CF = 1;
1.1 root 6884: }
6885: }
6886:
6887: inline void msdos_int_21h_4fh()
6888: {
6889: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 6890: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
6891: find_t *find = (find_t *)(mem + dta_laddr);
1.1 root 6892: WIN32_FIND_DATA fd;
6893:
1.1.1.14 root 6894: if(find->find_magic != FIND_MAGIC || find->dta_index >= MAX_DTAINFO) {
6895: REG16(AX) = 0x12;
6896: m_CF = 1;
6897: return;
6898: }
6899: dtainfo_t *dtainfo = &dtalist[find->dta_index];
1.1.1.13 root 6900: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
6901: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 6902: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 6903: !msdos_find_file_has_8dot3name(&fd)) {
6904: if(!FindNextFile(dtainfo->find_handle, &fd)) {
6905: FindClose(dtainfo->find_handle);
6906: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6907: break;
6908: }
6909: }
6910: } else {
1.1.1.13 root 6911: FindClose(dtainfo->find_handle);
6912: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6913: }
6914: }
1.1.1.13 root 6915: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 6916: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
6917: msdos_find_file_conv_local_time(&fd);
6918: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
6919: find->size = fd.nFileSizeLow;
1.1.1.13 root 6920: strcpy(find->name, msdos_short_name(&fd));
1.1 root 6921: REG16(AX) = 0;
1.1.1.14 root 6922: } else if(dtainfo->allowable_mask & 8) {
1.1 root 6923: find->attrib = 8;
6924: find->size = 0;
6925: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 6926: dtainfo->allowable_mask &= ~8;
1.1 root 6927: REG16(AX) = 0;
6928: } else {
6929: REG16(AX) = 0x12;
1.1.1.3 root 6930: m_CF = 1;
1.1 root 6931: }
6932: }
6933:
6934: inline void msdos_int_21h_50h()
6935: {
1.1.1.8 root 6936: if(current_psp != REG16(BX)) {
6937: process_t *process = msdos_process_info_get(current_psp);
6938: if(process != NULL) {
6939: process->psp = REG16(BX);
6940: }
6941: current_psp = REG16(BX);
1.1.1.23 root 6942: msdos_sda_update(current_psp);
1.1.1.8 root 6943: }
1.1 root 6944: }
6945:
6946: inline void msdos_int_21h_51h()
6947: {
6948: REG16(BX) = current_psp;
6949: }
6950:
6951: inline void msdos_int_21h_52h()
6952: {
1.1.1.25 root 6953: SREG(ES) = DOS_INFO_TOP >> 4;
1.1.1.3 root 6954: i386_load_segment_descriptor(ES);
1.1.1.25 root 6955: REG16(BX) = offsetof(dos_info_t, first_dpb);
1.1 root 6956: }
6957:
6958: inline void msdos_int_21h_54h()
6959: {
6960: process_t *process = msdos_process_info_get(current_psp);
6961:
6962: REG8(AL) = process->verify;
6963: }
6964:
6965: inline void msdos_int_21h_55h()
6966: {
6967: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
6968:
6969: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
6970: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
6971: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
6972: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
6973: psp->parent_psp = current_psp;
6974: }
6975:
6976: inline void msdos_int_21h_56h(int lfn)
6977: {
6978: char src[MAX_PATH], dst[MAX_PATH];
1.1.1.3 root 6979: strcpy(src, msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn));
6980: strcpy(dst, msdos_trimmed_path((char *)(mem + SREG_BASE(ES) + REG16(DI)), lfn));
1.1 root 6981:
6982: if(rename(src, dst)) {
6983: REG16(AX) = errno;
1.1.1.3 root 6984: m_CF = 1;
1.1 root 6985: }
6986: }
6987:
6988: inline void msdos_int_21h_57h()
6989: {
6990: FILETIME time, local;
1.1.1.14 root 6991: FILETIME *ctime, *atime, *mtime;
1.1.1.21 root 6992: HANDLE hHandle;
1.1 root 6993:
1.1.1.21 root 6994: if((hHandle = (HANDLE)_get_osfhandle(REG16(BX))) == INVALID_HANDLE_VALUE) {
1.1.1.14 root 6995: REG16(AX) = (UINT16)GetLastError();
6996: m_CF = 1;
6997: return;
6998: }
6999: ctime = atime = mtime = NULL;
7000:
1.1 root 7001: switch(REG8(AL)) {
7002: case 0x00:
1.1.1.6 root 7003: case 0x01:
1.1.1.14 root 7004: mtime = &time;
1.1.1.6 root 7005: break;
7006: case 0x04:
7007: case 0x05:
1.1.1.14 root 7008: atime = &time;
1.1 root 7009: break;
1.1.1.6 root 7010: case 0x06:
7011: case 0x07:
1.1.1.14 root 7012: ctime = &time;
7013: break;
7014: default:
1.1.1.22 root 7015: 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 7016: REG16(AX) = 0x01;
7017: m_CF = 1;
7018: return;
7019: }
7020: if(REG8(AL) & 1) {
1.1 root 7021: DosDateTimeToFileTime(REG16(DX), REG16(CX), &local);
7022: LocalFileTimeToFileTime(&local, &time);
1.1.1.21 root 7023: if(!SetFileTime(hHandle, ctime, atime, mtime)) {
1.1 root 7024: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 7025: m_CF = 1;
1.1 root 7026: }
1.1.1.14 root 7027: } else {
1.1.1.21 root 7028: if(!GetFileTime(hHandle, ctime, atime, mtime)) {
1.1.1.14 root 7029: // assume a device and use the current time
7030: GetSystemTimeAsFileTime(&time);
7031: }
7032: FileTimeToLocalFileTime(&time, &local);
7033: FileTimeToDosDateTime(&local, ®16(DX), ®16(CX));
1.1 root 7034: }
7035: }
7036:
7037: inline void msdos_int_21h_58h()
7038: {
7039: switch(REG8(AL)) {
7040: case 0x00:
1.1.1.7 root 7041: REG16(AX) = malloc_strategy;
7042: break;
7043: case 0x01:
1.1.1.24 root 7044: // switch(REG16(BX)) {
7045: switch(REG8(BL)) {
1.1.1.7 root 7046: case 0x0000:
7047: case 0x0001:
7048: case 0x0002:
7049: case 0x0040:
7050: case 0x0041:
7051: case 0x0042:
7052: case 0x0080:
7053: case 0x0081:
7054: case 0x0082:
7055: malloc_strategy = REG16(BX);
1.1.1.23 root 7056: msdos_sda_update(current_psp);
1.1.1.7 root 7057: break;
7058: default:
1.1.1.22 root 7059: 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 7060: REG16(AX) = 0x01;
7061: m_CF = 1;
7062: break;
7063: }
7064: break;
7065: case 0x02:
1.1.1.19 root 7066: REG8(AL) = msdos_mem_get_umb_linked() ? 1 : 0;
1.1.1.7 root 7067: break;
7068: case 0x03:
1.1.1.24 root 7069: // switch(REG16(BX)) {
7070: switch(REG8(BL)) {
1.1.1.7 root 7071: case 0x0000:
1.1.1.19 root 7072: msdos_mem_unlink_umb();
7073: break;
1.1.1.7 root 7074: case 0x0001:
1.1.1.19 root 7075: msdos_mem_link_umb();
1.1.1.7 root 7076: break;
7077: default:
1.1.1.22 root 7078: 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 7079: REG16(AX) = 0x01;
7080: m_CF = 1;
7081: break;
7082: }
1.1 root 7083: break;
7084: default:
1.1.1.22 root 7085: 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 7086: REG16(AX) = 0x01;
1.1.1.3 root 7087: m_CF = 1;
1.1 root 7088: break;
7089: }
7090: }
7091:
7092: inline void msdos_int_21h_59h()
7093: {
1.1.1.23 root 7094: sda_t *sda = (sda_t *)(mem + SDA_TOP);
7095:
7096: REG16(AX) = sda->extended_error_code;
7097: REG8(BH) = sda->error_class;
7098: REG8(BL) = sda->suggested_action;
7099: REG8(CH) = sda->locus_of_last_error;
1.1 root 7100: }
7101:
7102: inline void msdos_int_21h_5ah()
7103: {
1.1.1.3 root 7104: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 7105: int len = strlen(path);
7106: char tmp[MAX_PATH];
7107:
7108: if(GetTempFileName(path, "TMP", 0, tmp)) {
7109: int fd = _open(tmp, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
7110:
7111: SetFileAttributes(tmp, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
7112: REG16(AX) = fd;
7113: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 7114: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 7115:
7116: strcpy(path, tmp);
7117: int dx = REG16(DX) + len;
1.1.1.3 root 7118: int ds = SREG(DS);
1.1 root 7119: while(dx > 0xffff) {
7120: dx -= 0x10;
7121: ds++;
7122: }
7123: REG16(DX) = dx;
1.1.1.3 root 7124: SREG(DS) = ds;
7125: i386_load_segment_descriptor(DS);
1.1 root 7126: } else {
7127: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 7128: m_CF = 1;
1.1 root 7129: }
7130: }
7131:
7132: inline void msdos_int_21h_5bh()
7133: {
1.1.1.3 root 7134: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 7135:
1.1.1.24 root 7136: if(msdos_is_existing_file(path)) {
1.1 root 7137: // already exists
7138: REG16(AX) = 0x50;
1.1.1.3 root 7139: m_CF = 1;
1.1 root 7140: } else {
7141: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
7142:
7143: if(fd != -1) {
7144: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
7145: REG16(AX) = fd;
7146: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 7147: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 7148: } else {
7149: REG16(AX) = errno;
1.1.1.3 root 7150: m_CF = 1;
1.1 root 7151: }
7152: }
7153: }
7154:
7155: inline void msdos_int_21h_5ch()
7156: {
7157: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 7158: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 7159:
1.1.1.20 root 7160: if(fd < process->max_files && file_handler[fd].valid) {
1.1 root 7161: if(REG8(AL) == 0 || REG8(AL) == 1) {
7162: static int modes[2] = {_LK_LOCK, _LK_UNLCK};
1.1.1.20 root 7163: UINT32 pos = _tell(fd);
7164: _lseek(fd, (REG16(CX) << 16) | REG16(DX), SEEK_SET);
7165: if(_locking(fd, modes[REG8(AL)], (REG16(SI) << 16) | REG16(DI))) {
1.1 root 7166: REG16(AX) = errno;
1.1.1.3 root 7167: m_CF = 1;
1.1 root 7168: }
1.1.1.20 root 7169: _lseek(fd, pos, SEEK_SET);
1.1.1.26! root 7170:
1.1 root 7171: // some seconds may be passed in _locking()
7172: hardware_update();
7173: } else {
7174: REG16(AX) = 0x01;
1.1.1.3 root 7175: m_CF = 1;
1.1 root 7176: }
7177: } else {
7178: REG16(AX) = 0x06;
1.1.1.3 root 7179: m_CF = 1;
1.1 root 7180: }
7181: }
7182:
1.1.1.22 root 7183: inline void msdos_int_21h_5dh()
7184: {
7185: switch(REG8(AL)) {
7186: case 0x06: // get address of dos swappable data area
1.1.1.23 root 7187: SREG(DS) = (SDA_TOP >> 4);
7188: i386_load_segment_descriptor(DS);
7189: REG16(SI) = offsetof(sda_t, crit_error_flag);
7190: REG16(CX) = 0x80;
7191: REG16(DX) = 0x1a;
7192: break;
7193: case 0x0b: // get dos swappable data areas
1.1.1.22 root 7194: REG16(AX) = 0x01;
7195: m_CF = 1;
7196: break;
7197: case 0x08: // set redirected printer mode
7198: case 0x09: // flush redirected printer output
7199: case 0x0a: // set extended error information
7200: break;
7201: default:
7202: 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));
7203: REG16(AX) = 0x01;
7204: m_CF = 1;
7205: break;
7206: }
7207: }
7208:
1.1 root 7209: inline void msdos_int_21h_60h(int lfn)
7210: {
1.1.1.14 root 7211: char full[MAX_PATH], *path;
7212:
1.1 root 7213: if(lfn) {
1.1.1.14 root 7214: char *name;
7215: *full = '\0';
1.1.1.3 root 7216: GetFullPathName((char *)(mem + SREG_BASE(DS) + REG16(SI)), MAX_PATH, full, &name);
1.1.1.14 root 7217: switch(REG8(CL)) {
7218: case 1:
7219: GetShortPathName(full, full, MAX_PATH);
7220: my_strupr(full);
7221: break;
7222: case 2:
7223: GetLongPathName(full, full, MAX_PATH);
7224: break;
7225: }
7226: path = full;
7227: } else {
7228: path = msdos_short_full_path((char *)(mem + SREG_BASE(DS) + REG16(SI)));
7229: }
7230: if(*path != '\0') {
7231: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), path);
1.1 root 7232: } else {
1.1.1.14 root 7233: REG16(AX) = (UINT16)GetLastError();
7234: m_CF = 1;
1.1 root 7235: }
7236: }
7237:
7238: inline void msdos_int_21h_61h()
7239: {
7240: REG8(AL) = 0;
7241: }
7242:
7243: inline void msdos_int_21h_62h()
7244: {
7245: REG16(BX) = current_psp;
7246: }
7247:
7248: inline void msdos_int_21h_63h()
7249: {
7250: switch(REG8(AL)) {
7251: case 0x00:
1.1.1.3 root 7252: SREG(DS) = (DBCS_TABLE >> 4);
7253: i386_load_segment_descriptor(DS);
1.1 root 7254: REG16(SI) = (DBCS_TABLE & 0x0f);
7255: REG8(AL) = 0x00;
7256: break;
1.1.1.22 root 7257: case 0x01: // set korean input mode
7258: case 0x02: // get korean input mode
7259: REG8(AL) = 0xff; // not supported
7260: break;
1.1 root 7261: default:
1.1.1.22 root 7262: 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 7263: REG16(AX) = 0x01;
1.1.1.3 root 7264: m_CF = 1;
1.1 root 7265: break;
7266: }
7267: }
7268:
1.1.1.25 root 7269: UINT16 get_extended_country_info(UINT8 func)
1.1 root 7270: {
1.1.1.25 root 7271: switch(func) {
1.1.1.17 root 7272: case 0x01:
7273: if(REG16(CX) >= 5) {
1.1.1.19 root 7274: UINT8 data[1 + 2 + 2 + 2 + sizeof(country_info_t)];
1.1.1.17 root 7275: if(REG16(CX) > sizeof(data)) // cx = actual transfer size
7276: REG16(CX) = sizeof(data);
7277: ZeroMemory(data, sizeof(data));
7278: data[0] = 0x01;
7279: *(UINT16 *)(data + 1) = REG16(CX) - 3;
1.1.1.19 root 7280: *(UINT16 *)(data + 3) = get_country_info((country_info_t*)(data + 7));
1.1.1.17 root 7281: *(UINT16 *)(data + 5) = active_code_page;
7282: memcpy(mem + SREG_BASE(ES) + REG16(DI), data, REG16(CX));
1.1.1.25 root 7283: // REG16(AX) = active_code_page;
1.1.1.17 root 7284: } else {
1.1.1.25 root 7285: return(0x08); // insufficient memory
1.1.1.17 root 7286: }
7287: break;
7288: case 0x02:
7289: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x02;
7290: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (UPPERTABLE_TOP & 0x0f);
7291: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (UPPERTABLE_TOP >> 4);
1.1.1.25 root 7292: // REG16(AX) = active_code_page;
1.1.1.17 root 7293: REG16(CX) = 0x05;
7294: break;
1.1.1.23 root 7295: case 0x03:
7296: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x02;
7297: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (LOWERTABLE_TOP & 0x0f);
7298: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (LOWERTABLE_TOP >> 4);
1.1.1.25 root 7299: // REG16(AX) = active_code_page;
1.1.1.23 root 7300: REG16(CX) = 0x05;
7301: break;
1.1.1.17 root 7302: case 0x04:
7303: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x04;
7304: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_UPPERTABLE_TOP & 0x0f);
7305: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_UPPERTABLE_TOP >> 4);
1.1.1.25 root 7306: // REG16(AX) = active_code_page;
1.1.1.17 root 7307: REG16(CX) = 0x05;
7308: break;
7309: case 0x05:
7310: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x05;
7311: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (FILENAME_TERMINATOR_TOP & 0x0f);
7312: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (FILENAME_TERMINATOR_TOP >> 4);
1.1.1.25 root 7313: // REG16(AX) = active_code_page;
1.1.1.17 root 7314: REG16(CX) = 0x05;
7315: break;
7316: case 0x06:
7317: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x06;
7318: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (COLLATING_TABLE_TOP & 0x0f);
7319: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (COLLATING_TABLE_TOP >> 4);
1.1.1.25 root 7320: // REG16(AX) = active_code_page;
1.1.1.17 root 7321: REG16(CX) = 0x05;
7322: break;
1.1 root 7323: case 0x07:
1.1.1.3 root 7324: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x07;
7325: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (DBCS_TOP & 0x0f);
7326: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (DBCS_TOP >> 4);
1.1.1.25 root 7327: // REG16(AX) = active_code_page;
1.1 root 7328: REG16(CX) = 0x05;
7329: break;
1.1.1.25 root 7330: default:
7331: return(0x01); // function number invalid
7332: }
7333: return(0x00);
7334: }
7335:
7336: inline void msdos_int_21h_65h()
7337: {
7338: char tmp[0x10000];
7339:
7340: switch(REG8(AL)) {
7341: case 0x01:
7342: case 0x02:
7343: case 0x03:
7344: case 0x04:
7345: case 0x05:
7346: case 0x06:
7347: case 0x07:
7348: {
7349: UINT16 result = get_extended_country_info(REG8(AL));
7350: if(result) {
7351: REG16(AX) = result;
7352: m_CF = 1;
7353: } else {
7354: REG16(AX) = active_code_page; // FIXME: is this correct???
7355: }
7356: }
7357: break;
1.1 root 7358: case 0x20:
1.1.1.25 root 7359: case 0xa0:
1.1.1.19 root 7360: memset(tmp, 0, sizeof(tmp));
7361: tmp[0] = REG8(DL);
1.1 root 7362: my_strupr(tmp);
7363: REG8(DL) = tmp[0];
7364: break;
7365: case 0x21:
1.1.1.25 root 7366: case 0xa1:
1.1 root 7367: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 7368: memcpy(tmp, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 7369: my_strupr(tmp);
1.1.1.3 root 7370: memcpy(mem + SREG_BASE(DS) + REG16(DX), tmp, REG16(CX));
1.1 root 7371: break;
7372: case 0x22:
1.1.1.25 root 7373: case 0xa2:
1.1.1.3 root 7374: my_strupr((char *)(mem + SREG_BASE(DS) + REG16(DX)));
1.1 root 7375: break;
1.1.1.25 root 7376: case 0x23:
7377: // FIXME: need to check multi-byte (kanji) charactre?
7378: if(REG8(DL) == 'N' || REG8(DL) == 'n' || (REG8(DL) == 0x82 && REG8(DH) == 0x78) || (REG8(DL) == 0x82 && REG8(DH) == 0x99)) {
7379: // 8278h/8299h: multi-byte (kanji) Y and y
7380: REG16(AX) = 0x00;
7381: } else if(REG8(DL) == 'Y' || REG8(DL) == 'y' || (REG8(DL) == 0x82 && REG8(DH) == 0x6d) || (REG8(DL) == 0x82 && REG8(DH) == 0x8e)) {
7382: // 826dh/828eh: multi-byte (kanji) N and n
7383: REG16(AX) = 0x01;
7384: } else {
7385: REG16(AX) = 0x02;
7386: }
7387: break;
1.1 root 7388: default:
1.1.1.22 root 7389: 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 7390: REG16(AX) = 0x01;
1.1.1.3 root 7391: m_CF = 1;
1.1 root 7392: break;
7393: }
7394: }
7395:
7396: inline void msdos_int_21h_66h()
7397: {
7398: switch(REG8(AL)) {
7399: case 0x01:
7400: REG16(BX) = active_code_page;
7401: REG16(DX) = system_code_page;
7402: break;
7403: case 0x02:
7404: if(active_code_page == REG16(BX)) {
7405: REG16(AX) = 0xeb41;
7406: } else if(_setmbcp(REG16(BX)) == 0) {
7407: active_code_page = REG16(BX);
1.1.1.17 root 7408: msdos_nls_tables_update();
1.1 root 7409: REG16(AX) = 0xeb41;
7410: } else {
7411: REG16(AX) = 0x25;
1.1.1.3 root 7412: m_CF = 1;
1.1 root 7413: }
7414: break;
7415: default:
1.1.1.22 root 7416: 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 7417: REG16(AX) = 0x01;
1.1.1.3 root 7418: m_CF = 1;
1.1 root 7419: break;
7420: }
7421: }
7422:
7423: inline void msdos_int_21h_67h()
7424: {
7425: process_t *process = msdos_process_info_get(current_psp);
7426:
7427: if(REG16(BX) <= MAX_FILES) {
7428: process->max_files = max(REG16(BX), 20);
7429: } else {
7430: REG16(AX) = 0x08;
1.1.1.3 root 7431: m_CF = 1;
1.1 root 7432: }
7433: }
7434:
7435: inline void msdos_int_21h_68h()
7436: {
7437: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 7438: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
1.1 root 7439:
1.1.1.20 root 7440: if(fd < process->max_files && file_handler[fd].valid) {
7441: // fflush(_fdopen(fd, ""));
1.1 root 7442: } else {
7443: REG16(AX) = 0x06;
1.1.1.3 root 7444: m_CF = 1;
1.1 root 7445: }
7446: }
7447:
7448: inline void msdos_int_21h_69h()
7449: {
1.1.1.3 root 7450: drive_info_t *info = (drive_info_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 7451: char path[] = "A:\\";
7452: char volume_label[MAX_PATH];
7453: DWORD serial_number = 0;
7454: char file_system[MAX_PATH];
7455:
7456: if(REG8(BL) == 0) {
7457: path[0] = 'A' + _getdrive() - 1;
7458: } else {
7459: path[0] = 'A' + REG8(BL) - 1;
7460: }
7461:
7462: switch(REG8(AL)) {
7463: case 0x00:
7464: if(GetVolumeInformation(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) {
7465: info->info_level = 0;
7466: info->serial_number = serial_number;
7467: memset(info->volume_label, 0x20, 11);
7468: memcpy(info->volume_label, volume_label, min(strlen(volume_label), 11));
7469: memset(info->file_system, 0x20, 8);
7470: memcpy(info->file_system, file_system, min(strlen(file_system), 8));
7471: } else {
7472: REG16(AX) = errno;
1.1.1.3 root 7473: m_CF = 1;
1.1 root 7474: }
7475: break;
7476: case 0x01:
7477: REG16(AX) = 0x03;
1.1.1.3 root 7478: m_CF = 1;
1.1 root 7479: }
7480: }
7481:
7482: inline void msdos_int_21h_6ah()
7483: {
7484: REG8(AH) = 0x68;
7485: msdos_int_21h_68h();
7486: }
7487:
7488: inline void msdos_int_21h_6bh()
7489: {
7490: REG8(AL) = 0;
7491: }
7492:
7493: inline void msdos_int_21h_6ch(int lfn)
7494: {
1.1.1.3 root 7495: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn);
1.1 root 7496: int mode = REG8(BL) & 0x03;
7497:
7498: if(mode < 0x03) {
1.1.1.24 root 7499: if(msdos_is_existing_file(path) || msdos_is_driver_name(path)) {
1.1 root 7500: // file exists
7501: if(REG8(DL) & 1) {
1.1.1.11 root 7502: int fd = -1;
7503: UINT16 info;
1.1 root 7504:
1.1.1.11 root 7505: if(msdos_is_con_path(path)) {
1.1.1.13 root 7506: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 7507: info = 0x80d3;
1.1.1.14 root 7508: } else if(msdos_is_nul_path(path)) {
7509: fd = msdos_open("NUL", file_mode[mode].mode);
7510: info = 0x80d3;
1.1.1.24 root 7511: } else if(msdos_is_driver_name(path)) {
1.1.1.20 root 7512: fd = msdos_open("NUL", file_mode[mode].mode);
7513: info = 0x80d3;
1.1.1.11 root 7514: } else {
1.1.1.13 root 7515: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 7516: info = msdos_drive_number(path);
7517: }
1.1 root 7518: if(fd != -1) {
7519: REG16(AX) = fd;
7520: REG16(CX) = 1;
1.1.1.11 root 7521: msdos_file_handler_open(fd, path, _isatty(fd), mode, info, current_psp);
1.1.1.20 root 7522: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 7523: } else {
7524: REG16(AX) = errno;
1.1.1.3 root 7525: m_CF = 1;
1.1 root 7526: }
7527: } else if(REG8(DL) & 2) {
7528: int attr = GetFileAttributes(path);
7529: int fd = -1;
1.1.1.11 root 7530: UINT16 info;
1.1 root 7531:
1.1.1.11 root 7532: if(msdos_is_con_path(path)) {
1.1.1.13 root 7533: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 7534: info = 0x80d3;
1.1.1.14 root 7535: } else if(msdos_is_nul_path(path)) {
7536: fd = msdos_open("NUL", file_mode[mode].mode);
7537: info = 0x80d3;
1.1.1.24 root 7538: } else if(msdos_is_driver_name(path)) {
1.1.1.20 root 7539: fd = msdos_open("NUL", file_mode[mode].mode);
7540: info = 0x80d3;
1.1 root 7541: } else {
7542: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
1.1.1.11 root 7543: info = msdos_drive_number(path);
1.1 root 7544: }
7545: if(fd != -1) {
7546: if(attr == -1) {
7547: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
7548: }
7549: SetFileAttributes(path, attr);
7550: REG16(AX) = fd;
7551: REG16(CX) = 3;
1.1.1.11 root 7552: msdos_file_handler_open(fd, path, _isatty(fd), 2, info, current_psp);
1.1.1.20 root 7553: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 7554: } else {
7555: REG16(AX) = errno;
1.1.1.3 root 7556: m_CF = 1;
1.1 root 7557: }
7558: } else {
7559: REG16(AX) = 0x50;
1.1.1.3 root 7560: m_CF = 1;
1.1 root 7561: }
7562: } else {
7563: // file not exists
7564: if(REG8(DL) & 0x10) {
7565: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
7566:
7567: if(fd != -1) {
7568: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
7569: REG16(AX) = fd;
7570: REG16(CX) = 2;
7571: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
1.1.1.20 root 7572: msdos_psp_set_file_table(fd, fd, current_psp);
1.1 root 7573: } else {
7574: REG16(AX) = errno;
1.1.1.3 root 7575: m_CF = 1;
1.1 root 7576: }
7577: } else {
7578: REG16(AX) = 0x02;
1.1.1.3 root 7579: m_CF = 1;
1.1 root 7580: }
7581: }
7582: } else {
7583: REG16(AX) = 0x0c;
1.1.1.3 root 7584: m_CF = 1;
1.1 root 7585: }
7586: }
7587:
7588: inline void msdos_int_21h_710dh()
7589: {
7590: // reset drive
7591: }
7592:
1.1.1.17 root 7593: inline void msdos_int_21h_7141h(int lfn)
7594: {
7595: if(REG16(SI) == 0) {
7596: msdos_int_21h_41h(lfn);
7597: return;
7598: }
7599: if(REG16(SI) != 1) {
7600: REG16(AX) = 5;
7601: m_CF = 1;
7602: }
7603: /* wild card and matching attributes... */
7604: char tmp[MAX_PATH * 2];
7605: // copy search pathname (and quick check overrun)
7606: ZeroMemory(tmp, sizeof(tmp));
7607: tmp[MAX_PATH - 1] = '\0';
7608: tmp[MAX_PATH] = 1;
7609: strncpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(DX)), MAX_PATH);
7610:
7611: if(tmp[MAX_PATH - 1] != '\0' || tmp[MAX_PATH] != 1) {
7612: REG16(AX) = 1;
7613: m_CF = 1;
7614: return;
7615: }
7616: for(char *s = tmp; *s; ++s) {
7617: if(*s == '/') {
7618: *s = '\\';
7619: }
7620: }
7621: char *tmp_name = (char *)_mbsrchr((unsigned char *)tmp, '\\');
7622: if(tmp_name) {
7623: ++tmp_name;
7624: } else {
7625: tmp_name = strchr(tmp, ':');
7626: tmp_name = tmp_name ? tmp_name + 1 : tmp;
7627: }
7628:
7629: WIN32_FIND_DATAA fd;
7630: HANDLE fh = FindFirstFileA(tmp, &fd);
7631: if(fh == INVALID_HANDLE_VALUE) {
7632: REG16(AX) = 2;
7633: m_CF = 1;
7634: return;
7635: }
7636: do {
7637: if(msdos_find_file_check_attribute(fd.dwFileAttributes, REG8(CL), REG8(CH)) && msdos_find_file_has_8dot3name(&fd)) {
7638: strcpy(tmp_name, fd.cFileName);
7639: if(remove(msdos_trimmed_path(tmp, lfn))) {
7640: REG16(AX) = 5;
7641: m_CF = 1;
7642: break;
7643: }
7644: }
7645: } while(FindNextFileA(fh, &fd));
7646: if(!m_CF) {
7647: if(GetLastError() != ERROR_NO_MORE_FILES) {
7648: m_CF = 1;
7649: REG16(AX) = 2;
7650: }
7651: }
7652: FindClose(fh);
7653: }
7654:
1.1 root 7655: inline void msdos_int_21h_714eh()
7656: {
7657: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 7658: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
7659: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 7660: WIN32_FIND_DATA fd;
7661:
1.1.1.13 root 7662: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
7663: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
7664: FindClose(dtainfo->find_handle);
7665: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7666: }
7667: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 7668: dtainfo->allowable_mask = REG8(CL);
7669: dtainfo->required_mask = REG8(CH);
7670: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 7671:
1.1.1.14 root 7672: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
7673: dtainfo->allowable_mask &= ~8;
1.1 root 7674: }
1.1.1.14 root 7675: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
7676: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 7677: if(!FindNextFile(dtainfo->find_handle, &fd)) {
7678: FindClose(dtainfo->find_handle);
7679: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7680: break;
7681: }
7682: }
7683: }
1.1.1.13 root 7684: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 7685: find->attrib = fd.dwFileAttributes;
7686: msdos_find_file_conv_local_time(&fd);
7687: if(REG16(SI) == 0) {
7688: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
7689: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
7690: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
7691: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
7692: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
7693: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
7694: } else {
7695: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
7696: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
7697: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
7698: }
7699: find->size_hi = fd.nFileSizeHigh;
7700: find->size_lo = fd.nFileSizeLow;
7701: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 7702: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14 root 7703: REG16(AX) = dtainfo - dtalist + 1;
7704: } else if(dtainfo->allowable_mask & 8) {
1.1 root 7705: // volume label
7706: find->attrib = 8;
7707: find->size_hi = find->size_lo = 0;
7708: strcpy(find->full_name, process->volume_label);
7709: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 7710: dtainfo->allowable_mask &= ~8;
7711: REG16(AX) = dtainfo - dtalist + 1;
1.1 root 7712: } else {
7713: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 7714: m_CF = 1;
1.1 root 7715: }
7716: }
7717:
7718: inline void msdos_int_21h_714fh()
7719: {
7720: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 7721: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 7722: WIN32_FIND_DATA fd;
7723:
1.1.1.14 root 7724: if(REG16(BX) - 1u >= MAX_DTAINFO) {
7725: REG16(AX) = 6;
1.1.1.13 root 7726: m_CF = 1;
7727: return;
7728: }
1.1.1.14 root 7729: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 7730: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
7731: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 7732: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 7733: if(!FindNextFile(dtainfo->find_handle, &fd)) {
7734: FindClose(dtainfo->find_handle);
7735: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7736: break;
7737: }
7738: }
7739: } else {
1.1.1.13 root 7740: FindClose(dtainfo->find_handle);
7741: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7742: }
7743: }
1.1.1.13 root 7744: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 7745: find->attrib = fd.dwFileAttributes;
7746: msdos_find_file_conv_local_time(&fd);
7747: if(REG16(SI) == 0) {
7748: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
7749: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
7750: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
7751: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
7752: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
7753: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
7754: } else {
7755: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
7756: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
7757: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
7758: }
7759: find->size_hi = fd.nFileSizeHigh;
7760: find->size_lo = fd.nFileSizeLow;
7761: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 7762: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14 root 7763: } else if(dtainfo->allowable_mask & 8) {
1.1 root 7764: // volume label
7765: find->attrib = 8;
7766: find->size_hi = find->size_lo = 0;
7767: strcpy(find->full_name, process->volume_label);
7768: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 7769: dtainfo->allowable_mask &= ~8;
1.1 root 7770: } else {
7771: REG16(AX) = 0x12;
1.1.1.3 root 7772: m_CF = 1;
1.1 root 7773: }
7774: }
7775:
7776: inline void msdos_int_21h_71a0h()
7777: {
7778: DWORD max_component_len, file_sys_flag;
7779:
1.1.1.14 root 7780: 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))) {
7781: REG16(BX) = (UINT16)file_sys_flag & (FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK | FILE_VOLUME_IS_COMPRESSED);
7782: REG16(BX) |= 0x4000; // supports LFN functions
1.1 root 7783: REG16(CX) = (UINT16)max_component_len; // 255
7784: REG16(DX) = (UINT16)max_component_len + 5; // 260
7785: } else {
7786: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 7787: m_CF = 1;
1.1 root 7788: }
7789: }
7790:
7791: inline void msdos_int_21h_71a1h()
7792: {
1.1.1.14 root 7793: if(REG16(BX) - 1u >= MAX_DTAINFO) {
7794: REG16(AX) = 6;
1.1.1.13 root 7795: m_CF = 1;
7796: return;
7797: }
1.1.1.14 root 7798: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 7799: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
7800: FindClose(dtainfo->find_handle);
7801: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 7802: }
7803: }
7804:
7805: inline void msdos_int_21h_71a6h()
7806: {
7807: process_t *process = msdos_process_info_get(current_psp);
1.1.1.20 root 7808: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
7809:
1.1.1.3 root 7810: UINT8 *buffer = (UINT8 *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 7811: struct _stat64 status;
7812: DWORD serial_number = 0;
7813:
1.1.1.20 root 7814: if(fd < process->max_files && file_handler[fd].valid) {
7815: if(_fstat64(fd, &status) == 0) {
7816: if(file_handler[fd].path[1] == ':') {
1.1 root 7817: // NOTE: we need to consider the network file path "\\host\share\"
7818: char volume[] = "A:\\";
1.1.1.20 root 7819: volume[0] = file_handler[fd].path[1];
1.1 root 7820: GetVolumeInformation(volume, NULL, 0, &serial_number, NULL, NULL, NULL, 0);
7821: }
1.1.1.20 root 7822: *(UINT32 *)(buffer + 0x00) = GetFileAttributes(file_handler[fd].path);
1.1 root 7823: *(UINT32 *)(buffer + 0x04) = (UINT32)(status.st_ctime & 0xffffffff);
7824: *(UINT32 *)(buffer + 0x08) = (UINT32)((status.st_ctime >> 32) & 0xffffffff);
7825: *(UINT32 *)(buffer + 0x0c) = (UINT32)(status.st_atime & 0xffffffff);
7826: *(UINT32 *)(buffer + 0x10) = (UINT32)((status.st_atime >> 32) & 0xffffffff);
7827: *(UINT32 *)(buffer + 0x14) = (UINT32)(status.st_mtime & 0xffffffff);
7828: *(UINT32 *)(buffer + 0x18) = (UINT32)((status.st_mtime >> 32) & 0xffffffff);
7829: *(UINT32 *)(buffer + 0x1c) = serial_number;
7830: *(UINT32 *)(buffer + 0x20) = (UINT32)((status.st_size >> 32) & 0xffffffff);
7831: *(UINT32 *)(buffer + 0x24) = (UINT32)(status.st_size & 0xffffffff);
7832: *(UINT32 *)(buffer + 0x28) = status.st_nlink;
1.1.1.14 root 7833: // this is dummy id and it will be changed when it is reopened...
1.1 root 7834: *(UINT32 *)(buffer + 0x2c) = 0;
1.1.1.20 root 7835: *(UINT32 *)(buffer + 0x30) = file_handler[fd].id;
1.1 root 7836: } else {
7837: REG16(AX) = errno;
1.1.1.3 root 7838: m_CF = 1;
1.1 root 7839: }
7840: } else {
7841: REG16(AX) = 0x06;
1.1.1.3 root 7842: m_CF = 1;
1.1 root 7843: }
7844: }
7845:
7846: inline void msdos_int_21h_71a7h()
7847: {
7848: switch(REG8(BL)) {
7849: case 0x00:
1.1.1.3 root 7850: if(!FileTimeToDosDateTime((FILETIME *)(mem + SREG_BASE(DS) + REG16(SI)), ®16(DX), ®16(CX))) {
1.1 root 7851: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 7852: m_CF = 1;
1.1 root 7853: }
7854: break;
7855: case 0x01:
7856: // NOTE: we need to check BH that shows 10-millisecond untils past time in CX
1.1.1.3 root 7857: if(!DosDateTimeToFileTime(REG16(DX), REG16(CX), (FILETIME *)(mem + SREG_BASE(ES) + REG16(DI)))) {
1.1 root 7858: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 7859: m_CF = 1;
1.1 root 7860: }
7861: break;
7862: default:
1.1.1.22 root 7863: 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 7864: REG16(AX) = 0x01;
1.1.1.3 root 7865: m_CF = 1;
1.1 root 7866: break;
7867: }
7868: }
7869:
7870: inline void msdos_int_21h_71a8h()
7871: {
7872: if(REG8(DH) == 0) {
7873: char tmp[MAX_PATH], fcb[MAX_PATH];
1.1.1.3 root 7874: strcpy(tmp, msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 7875: memset(fcb, 0x20, sizeof(fcb));
7876: int len = strlen(tmp);
1.1.1.21 root 7877: for(int i = 0, pos = 0; i < len; i++) {
1.1 root 7878: if(tmp[i] == '.') {
7879: pos = 8;
7880: } else {
7881: if(msdos_lead_byte_check(tmp[i])) {
7882: fcb[pos++] = tmp[i++];
7883: }
7884: fcb[pos++] = tmp[i];
7885: }
7886: }
1.1.1.3 root 7887: memcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), fcb, 11);
1.1 root 7888: } else {
1.1.1.3 root 7889: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 7890: }
7891: }
7892:
1.1.1.22 root 7893: inline void msdos_int_21h_71aah()
7894: {
7895: char drv[] = "A:", path[MAX_PATH];
7896: char *hoge=(char *)(mem + SREG_BASE(DS) + REG16(DX));
7897:
7898: if(REG8(BL) == 0) {
7899: drv[0] = 'A' + _getdrive() - 1;
7900: } else {
7901: drv[0] = 'A' + REG8(BL) - 1;
7902: }
7903: switch(REG8(BH)) {
7904: case 0x00:
7905: if(DefineDosDevice(0, drv, (char *)(mem + SREG_BASE(DS) + REG16(DX))) == 0) {
7906: DWORD bits = 1 << ((REG8(BL) ? REG8(BL) : _getdrive()) - 1);
7907: if(GetLogicalDrives() & bits) {
7908: REG16(AX) = 0x0f; // invalid drive
7909: } else {
7910: REG16(AX) = 0x03; // path not found
7911: }
7912: m_CF = 1;
7913: }
7914: break;
7915: case 0x01:
7916: if(DefineDosDevice(DDD_REMOVE_DEFINITION, drv, NULL) == 0) {
7917: REG16(AX) = 0x0f; // invalid drive
7918: m_CF = 1;
7919: }
7920: break;
7921: case 0x02:
7922: if(QueryDosDevice(drv, path, MAX_PATH) == 0) {
7923: REG16(AX) = 0x0f; // invalid drive
7924: m_CF = 1;
7925: } else if(strncmp(path, "\\??\\", 4) != 0) {
7926: REG16(AX) = 0x0f; // invalid drive
7927: m_CF = 1;
7928: } else {
7929: strcpy((char *)(mem + SREG_BASE(DS) + REG16(DX)), path + 4);
7930: }
7931: break;
7932: default:
7933: 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));
7934: REG16(AX) = 0x01;
7935: m_CF = 1;
7936: break;
7937: }
7938: }
7939:
1.1.1.14 root 7940: inline void msdos_int_21h_7300h()
7941: {
7942: if(REG8(AL) == 0) {
7943: REG8(AL) = REG8(CL);
7944: REG8(AH) = 0;
7945: } else {
7946: REG16(AX) = 0x01;
7947: m_CF = 1;
7948: }
7949: }
7950:
7951: inline void msdos_int_21h_7302h()
7952: {
7953: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
7954: UINT16 seg, ofs;
7955:
7956: if(REG16(CX) < 0x3f) {
7957: REG8(AL) = 0x18;
7958: m_CF = 1;
7959: } else if(!msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
7960: REG8(AL) = 0xff;
7961: m_CF = 1;
7962: } else {
7963: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 2, mem + (seg << 4) + ofs, sizeof(dpb_t));
7964: }
7965: }
7966:
1.1 root 7967: inline void msdos_int_21h_7303h()
7968: {
1.1.1.3 root 7969: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
7970: ext_space_info_t *info = (ext_space_info_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 7971: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
7972:
7973: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
7974: info->size_of_structure = sizeof(ext_space_info_t);
7975: info->structure_version = 0;
7976: info->sectors_per_cluster = sectors_per_cluster;
7977: info->bytes_per_sector = bytes_per_sector;
7978: info->available_clusters_on_drive = free_clusters;
7979: info->total_clusters_on_drive = total_clusters;
7980: info->available_sectors_on_drive = sectors_per_cluster * free_clusters;
7981: info->total_sectors_on_drive = sectors_per_cluster * total_clusters;
7982: info->available_allocation_units = free_clusters; // ???
7983: info->total_allocation_units = total_clusters; // ???
7984: } else {
7985: REG16(AX) = errno;
1.1.1.3 root 7986: m_CF = 1;
1.1 root 7987: }
7988: }
7989:
7990: inline void msdos_int_25h()
7991: {
7992: UINT16 seg, ofs;
7993: DWORD dwSize;
7994:
1.1.1.3 root 7995: #if defined(HAS_I386)
7996: I386OP(pushf)();
7997: #else
7998: PREFIX86(_pushf());
7999: #endif
1.1 root 8000:
8001: if(!(REG8(AL) < 26)) {
8002: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 8003: m_CF = 1;
1.1 root 8004: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
8005: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 8006: m_CF = 1;
1.1 root 8007: } else {
8008: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
8009: char dev[64];
8010: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
8011:
8012: HANDLE hFile = CreateFile(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
8013: if(hFile == INVALID_HANDLE_VALUE) {
8014: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 8015: m_CF = 1;
1.1 root 8016: } else {
1.1.1.19 root 8017: UINT32 top_sector = REG16(DX);
8018: UINT16 sector_num = REG16(CX);
8019: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX);
8020:
8021: if(sector_num == 0xffff) {
8022: top_sector = *(UINT32 *)(mem + buffer_addr + 0);
8023: sector_num = *(UINT16 *)(mem + buffer_addr + 4);
8024: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6);
8025: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8);
8026: buffer_addr = (seg << 4) + ofs;
8027: }
8028: // if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
8029: // REG8(AL) = 0x02; // drive not ready
8030: // m_CF = 1;
8031: // } else
8032: if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1.1 root 8033: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 8034: m_CF = 1;
1.1.1.19 root 8035: } else if(ReadFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 8036: REG8(AL) = 0x0b; // read error
1.1.1.3 root 8037: m_CF = 1;
1.1 root 8038: }
8039: CloseHandle(hFile);
8040: }
8041: }
8042: }
8043:
8044: inline void msdos_int_26h()
8045: {
8046: // this operation may cause serious damage for drives, so always returns error...
8047: UINT16 seg, ofs;
8048: DWORD dwSize;
8049:
1.1.1.3 root 8050: #if defined(HAS_I386)
8051: I386OP(pushf)();
8052: #else
8053: PREFIX86(_pushf());
8054: #endif
1.1 root 8055:
8056: if(!(REG8(AL) < 26)) {
8057: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 8058: m_CF = 1;
1.1 root 8059: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
8060: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 8061: m_CF = 1;
1.1 root 8062: } else {
8063: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
8064: char dev[64];
8065: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
8066:
8067: if(dpb->media_type == 0xf8) {
8068: // this drive is not a floppy
1.1.1.6 root 8069: // if(!(((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag & 0x40)) {
8070: // fatalerror("This application tried the absolute disk write to drive %c:\n", 'A' + REG8(AL));
8071: // }
1.1 root 8072: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 8073: m_CF = 1;
1.1 root 8074: } else {
8075: HANDLE hFile = CreateFile(dev, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
8076: if(hFile == INVALID_HANDLE_VALUE) {
8077: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 8078: m_CF = 1;
1.1 root 8079: } else {
1.1.1.19 root 8080: UINT32 top_sector = REG16(DX);
8081: UINT16 sector_num = REG16(CX);
8082: UINT32 buffer_addr = SREG_BASE(DS) + REG16(BX);
8083:
8084: if(sector_num == 0xffff) {
8085: top_sector = *(UINT32 *)(mem + buffer_addr + 0);
8086: sector_num = *(UINT16 *)(mem + buffer_addr + 4);
8087: UINT16 ofs = *(UINT16 *)(mem + buffer_addr + 6);
8088: UINT16 seg = *(UINT16 *)(mem + buffer_addr + 8);
8089: buffer_addr = (seg << 4) + ofs;
8090: }
1.1 root 8091: if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
8092: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 8093: m_CF = 1;
1.1.1.19 root 8094: } else if(SetFilePointer(hFile, top_sector * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1.1 root 8095: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 8096: m_CF = 1;
1.1.1.19 root 8097: } else if(WriteFile(hFile, mem + buffer_addr, sector_num * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 8098: REG8(AL) = 0x0a; // write error
1.1.1.3 root 8099: m_CF = 1;
1.1 root 8100: }
8101: CloseHandle(hFile);
8102: }
8103: }
8104: }
8105: }
8106:
8107: inline void msdos_int_27h()
8108: {
1.1.1.14 root 8109: msdos_mem_realloc(SREG(CS), (REG16(DX) + 15) >> 4, NULL);
1.1.1.3 root 8110: msdos_process_terminate(SREG(CS), retval | 0x300, 0);
1.1.1.14 root 8111:
8112: // int_21h_4bh succeeded
8113: m_CF = 0;
1.1 root 8114: }
8115:
8116: inline void msdos_int_29h()
8117: {
1.1.1.14 root 8118: #if 1
8119: // need to check escape sequences
1.1 root 8120: msdos_putch(REG8(AL));
1.1.1.14 root 8121: #else
8122: DWORD num;
8123: vram_flush();
1.1.1.23 root 8124: WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ®8(AL), 1, &num, NULL);
1.1.1.14 root 8125: cursor_moved = true;
8126: #endif
1.1 root 8127: }
8128:
8129: inline void msdos_int_2eh()
8130: {
8131: char tmp[MAX_PATH], command[MAX_PATH], opt[MAX_PATH];
8132: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 8133: strcpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(SI)));
1.1 root 8134: char *token = my_strtok(tmp, " ");
8135: strcpy(command, token);
8136: strcpy(opt, token + strlen(token) + 1);
8137:
8138: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
8139: param->env_seg = 0;
8140: param->cmd_line.w.l = 44;
8141: param->cmd_line.w.h = (WORK_TOP >> 4);
8142: param->fcb1.w.l = 24;
8143: param->fcb1.w.h = (WORK_TOP >> 4);
8144: param->fcb2.w.l = 24;
8145: param->fcb2.w.h = (WORK_TOP >> 4);
8146:
8147: memset(mem + WORK_TOP + 24, 0x20, 20);
8148:
8149: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
8150: cmd_line->len = strlen(opt);
8151: strcpy(cmd_line->cmd, opt);
8152: cmd_line->cmd[cmd_line->len] = 0x0d;
8153:
8154: msdos_process_exec(command, param, 0);
8155: REG8(AL) = 0;
8156: }
8157:
1.1.1.22 root 8158: inline void msdos_int_2fh_01h()
8159: {
8160: switch(REG8(AL)) {
8161: case 0x00:
8162: REG8(AL) = 0x01; // print.com is not installed, can't install
8163: break;
8164: default:
8165: 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));
8166: REG16(AX) = 0x01;
8167: m_CF = 1;
8168: break;
8169: }
8170: }
8171:
8172: inline void msdos_int_2fh_05h()
8173: {
8174: switch(REG8(AL)) {
8175: case 0x00:
8176: REG8(AL) = 0x01; // critical error handler is not installed, can't install
8177: break;
8178: default:
8179: 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));
8180: REG16(AX) = 0x01;
8181: m_CF = 1;
8182: break;
8183: }
8184: }
8185:
8186: inline void msdos_int_2fh_06h()
8187: {
8188: switch(REG8(AL)) {
8189: case 0x00:
8190: REG8(AL) = 0x01; // assign is not installed, can't install
8191: break;
8192: default:
8193: 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));
8194: REG16(AX) = 0x01;
8195: m_CF = 1;
8196: break;
8197: }
8198: }
8199:
8200: inline void msdos_int_2fh_08h()
8201: {
8202: switch(REG8(AL)) {
8203: case 0x00:
8204: REG8(AL) = 0x01; // driver.sys is not installed, can't install
8205: break;
8206: default:
8207: unimplemented_2fh("int %02Xh (AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X DS=%04X ES=%04X)\n", 0x2f, REG16(AX), REG16(BX), REG16(CX), REG16(DX), REG16(SI), REG16(DI), SREG(DS), SREG(ES));
8208: REG16(AX) = 0x01;
8209: m_CF = 1;
8210: break;
8211: }
8212: }
8213:
8214: inline void msdos_int_2fh_10h()
8215: {
8216: switch(REG8(AL)) {
8217: case 0x00:
8218: REG8(AL) = 0x01; // share is not installed, can't install
8219: break;
8220: default:
8221: 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));
8222: REG16(AX) = 0x01;
8223: m_CF = 1;
8224: break;
8225: }
8226: }
8227:
8228: inline void msdos_int_2fh_11h()
8229: {
8230: switch(REG8(AL)) {
8231: case 0x00:
8232: REG8(AL) = 0x01; // mscdex is not installed, can't install
8233: break;
8234: default:
8235: 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));
8236: REG16(AX) = 0x01;
8237: m_CF = 1;
8238: break;
8239: }
8240: }
8241:
1.1.1.21 root 8242: inline void msdos_int_2fh_12h()
8243: {
8244: switch(REG8(AL)) {
1.1.1.22 root 8245: case 0x00:
8246: REG8(AL) = 0xff;
8247: break;
1.1.1.21 root 8248: case 0x16:
8249: if(REG16(BX) < 20) {
8250: SREG(ES) = SFT_TOP >> 4;
8251: i386_load_segment_descriptor(ES);
8252: REG16(DI) = 6 + 0x3b * REG16(BX);
8253:
8254: // update system file table
8255: UINT8* sft = mem + SFT_TOP + 6 + 0x3b * REG16(BX);
8256: if(file_handler[REG16(BX)].valid) {
8257: int count = 0;
8258: for(int i = 0; i < 20; i++) {
8259: if(msdos_psp_get_file_table(i, current_psp) == REG16(BX)) {
8260: count++;
8261: }
8262: }
8263: *(UINT16 *)(sft + 0x00) = count ? count : 0xffff;
8264: *(UINT32 *)(sft + 0x15) = _tell(REG16(BX));
8265: _lseek(REG16(BX), 0, SEEK_END);
8266: *(UINT32 *)(sft + 0x11) = _tell(REG16(BX));
8267: _lseek(REG16(BX), *(UINT32 *)(sft + 0x15), SEEK_SET);
8268: } else {
8269: memset(sft, 0, 0x3b);
8270: }
8271: } else {
8272: REG16(AX) = 0x06;
8273: m_CF = 1;
8274: }
8275: break;
8276: case 0x20:
8277: {
8278: int fd = msdos_psp_get_file_table(REG16(BX), current_psp);
8279:
8280: if(fd < 20) {
8281: SREG(ES) = current_psp;
8282: i386_load_segment_descriptor(ES);
8283: REG16(DI) = offsetof(psp_t, file_table) + fd;
8284: } else {
8285: REG16(AX) = 0x06;
8286: m_CF = 1;
8287: }
8288: }
8289: break;
1.1.1.22 root 8290: case 0x2e:
8291: if(REG8(DL) == 0x00 || REG8(DL) == 0x02 || REG8(DL) == 0x04 || REG8(DL) == 0x06) {
8292: SREG(ES) = ERR_TABLE_TOP >> 4;
8293: i386_load_segment_descriptor(ES);
8294: REG16(DI) = 0;
8295: }
8296: break;
8297: default:
8298: 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));
8299: REG16(AX) = 0x01;
8300: m_CF = 1;
8301: break;
8302: }
8303: }
8304:
8305: inline void msdos_int_2fh_14h()
8306: {
8307: switch(REG8(AL)) {
8308: case 0x00:
1.1.1.25 root 8309: REG8(AL) = 0xff; // nlsfunc.com is installed
8310: break;
8311: case 0x01:
8312: case 0x03:
8313: REG8(AL) = 0x00;
8314: active_code_page = REG16(BX);
8315: msdos_nls_tables_update();
8316: break;
8317: case 0x02:
8318: REG8(AL) = get_extended_country_info(REG16(BP));
8319: break;
8320: case 0x04:
8321: REG8(AL) = 0x00;
8322: get_country_info((country_info_t *)(mem + SREG_BASE(ES) + REG16(DI)));
1.1.1.22 root 8323: break;
8324: default:
8325: 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));
8326: REG16(AX) = 0x01;
8327: m_CF = 1;
8328: break;
8329: }
8330: }
8331:
8332: inline void msdos_int_2fh_15h()
8333: {
8334: switch(REG8(AL)) {
8335: case 0x00:
8336: // function not supported, do not clear AX
8337: break;
8338: case 0x0b:
8339: // mscdex.exe is not installed
8340: break;
8341: case 0xff:
8342: // corelcdx is not installed
8343: break;
1.1.1.21 root 8344: default:
1.1.1.22 root 8345: 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 8346: REG16(AX) = 0x01;
8347: m_CF = 1;
8348: break;
8349: }
8350: }
8351:
1.1 root 8352: inline void msdos_int_2fh_16h()
8353: {
8354: switch(REG8(AL)) {
8355: case 0x00:
1.1.1.14 root 8356: if(no_windows) {
8357: REG8(AL) = 0;
8358: } else {
1.1 root 8359: OSVERSIONINFO osvi;
8360: ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
8361: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
8362: GetVersionEx(&osvi);
8363: REG8(AL) = osvi.dwMajorVersion;
8364: REG8(AH) = osvi.dwMinorVersion;
8365: }
8366: break;
1.1.1.22 root 8367: case 0x0a:
8368: if(!no_windows) {
8369: OSVERSIONINFO osvi;
8370: ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
8371: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
8372: GetVersionEx(&osvi);
8373: REG16(AX) = 0x0000;
8374: REG8(BH) = osvi.dwMajorVersion;
8375: REG8(BL) = osvi.dwMinorVersion;
8376: REG16(CX) = 0x0003; // enhanced
8377: }
8378: break;
8379: case 0x0e:
8380: case 0x0f:
8381: case 0x11:
8382: case 0x12:
8383: case 0x13:
8384: case 0x14:
8385: case 0x87:
8386: // function not supported, do not clear AX
8387: break;
1.1.1.14 root 8388: case 0x80:
8389: Sleep(10);
8390: hardware_update();
8391: REG8(AL) = 0;
8392: break;
1.1.1.22 root 8393: case 0x8e:
8394: REG16(AX) = 0x00; // failed
8395: break;
1.1.1.20 root 8396: case 0x8f:
8397: switch(REG8(DH)) {
8398: case 0x00:
8399: case 0x02:
8400: case 0x03:
8401: REG16(AX) = 0x00;
8402: break;
8403: case 0x01:
8404: REG16(AX) = 0x168f;
8405: break;
8406: }
8407: break;
1.1 root 8408: default:
1.1.1.22 root 8409: 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));
8410: REG16(AX) = 0x01;
8411: m_CF = 1;
8412: break;
8413: }
8414: }
8415:
8416: inline void msdos_int_2fh_19h()
8417: {
8418: switch(REG8(AL)) {
8419: case 0x00:
8420: // shellb.com is not installed
8421: REG8(AL) = 0x00;
8422: break;
8423: case 0x01:
8424: case 0x02:
8425: case 0x03:
8426: case 0x04:
8427: REG16(AX) = 0x01;
8428: m_CF = 1;
8429: break;
8430: default:
8431: 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 8432: REG16(AX) = 0x01;
1.1.1.3 root 8433: m_CF = 1;
1.1 root 8434: break;
8435: }
8436: }
8437:
8438: inline void msdos_int_2fh_1ah()
8439: {
8440: switch(REG8(AL)) {
8441: case 0x00:
8442: // ansi.sys is installed
8443: REG8(AL) = 0xff;
8444: break;
8445: default:
1.1.1.22 root 8446: 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));
8447: REG16(AX) = 0x01;
8448: m_CF = 1;
8449: break;
8450: }
8451: }
8452:
8453: inline void msdos_int_2fh_1bh()
8454: {
8455: switch(REG8(AL)) {
8456: case 0x00:
8457: // xma2ems.sys is not installed
8458: REG8(AL) = 0x00;
8459: break;
8460: default:
8461: 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 8462: REG16(AX) = 0x01;
1.1.1.3 root 8463: m_CF = 1;
1.1 root 8464: break;
8465: }
8466: }
8467:
8468: inline void msdos_int_2fh_43h()
8469: {
8470: switch(REG8(AL)) {
8471: case 0x00:
1.1.1.19 root 8472: // xms is installed ?
8473: #ifdef SUPPORT_XMS
8474: if(support_xms) {
8475: REG8(AL) = 0x80;
8476: } else
8477: #endif
8478: REG8(AL) = 0x00;
8479: break;
8480: case 0x10:
8481: SREG(ES) = XMS_TOP >> 4;
8482: i386_load_segment_descriptor(ES);
1.1.1.26! root 8483: REG16(BX) = 0x15;
1.1 root 8484: break;
8485: default:
1.1.1.22 root 8486: 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));
8487: REG16(AX) = 0x01;
8488: m_CF = 1;
8489: break;
8490: }
8491: }
8492:
8493: inline void msdos_int_2fh_46h()
8494: {
8495: switch(REG8(AL)) {
8496: case 0x80:
8497: // windows v3.0 is not installed
8498: break;
8499: default:
8500: 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));
8501: REG16(AX) = 0x01;
8502: m_CF = 1;
8503: break;
8504: }
8505: }
8506:
8507: inline void msdos_int_2fh_48h()
8508: {
8509: switch(REG8(AL)) {
8510: case 0x00:
8511: // doskey is not installed
8512: break;
8513: case 0x10:
8514: msdos_int_21h_0ah();
8515: REG16(AX) = 0x00;
8516: break;
8517: default:
8518: 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 8519: REG16(AX) = 0x01;
1.1.1.3 root 8520: m_CF = 1;
1.1 root 8521: break;
8522: }
8523: }
8524:
8525: inline void msdos_int_2fh_4ah()
8526: {
1.1.1.19 root 8527: // hma is not installed
1.1 root 8528: switch(REG8(AL)) {
8529: case 0x01:
8530: case 0x02:
1.1.1.19 root 8531: // hma is not used
1.1 root 8532: REG16(BX) = 0;
1.1.1.3 root 8533: SREG(ES) = 0xffff;
8534: i386_load_segment_descriptor(ES);
1.1 root 8535: REG16(DI) = 0xffff;
8536: break;
1.1.1.19 root 8537: case 0x03:
8538: // unable to allocate
8539: REG16(DI) = 0xffff;
8540: break;
8541: case 0x04:
8542: // function not supported, do not clear AX
8543: break;
1.1.1.22 root 8544: case 0x10: // smartdrv installation check
8545: case 0x11: // dblspace installation check
8546: break;
8547: default:
8548: 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));
8549: REG16(AX) = 0x01;
8550: m_CF = 1;
8551: break;
8552: }
8553: }
8554:
8555: inline void msdos_int_2fh_4bh()
8556: {
8557: switch(REG8(AL)) {
1.1.1.24 root 8558: case 0x01:
1.1.1.22 root 8559: case 0x02:
1.1.1.24 root 8560: // task switcher not loaded
8561: break;
8562: case 0x03:
8563: // this call is available from within DOSSHELL even if the task switcher is not installed
8564: REG16(AX) = REG16(BX) = 0x0000; // no more avaiable switcher id
1.1.1.22 root 8565: break;
1.1 root 8566: default:
1.1.1.22 root 8567: 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 8568: REG16(AX) = 0x01;
1.1.1.3 root 8569: m_CF = 1;
1.1 root 8570: break;
8571: }
8572: }
8573:
8574: inline void msdos_int_2fh_4fh()
8575: {
8576: switch(REG8(AL)) {
8577: case 0x00:
8578: REG16(AX) = 0;
8579: REG8(DL) = 1; // major version
8580: REG8(DH) = 0; // minor version
8581: break;
8582: case 0x01:
8583: REG16(AX) = 0;
8584: REG16(BX) = active_code_page;
8585: break;
8586: default:
1.1.1.22 root 8587: 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));
8588: REG16(AX) = 0x01;
8589: m_CF = 1;
8590: break;
8591: }
8592: }
8593:
8594: inline void msdos_int_2fh_55h()
8595: {
8596: switch(REG8(AL)) {
8597: case 0x00:
8598: case 0x01:
8599: // 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));
8600: break;
8601: default:
8602: 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 8603: REG16(AX) = 0x01;
1.1.1.3 root 8604: m_CF = 1;
1.1 root 8605: break;
8606: }
8607: }
8608:
1.1.1.24 root 8609: inline void msdos_int_2fh_adh()
8610: {
8611: switch(REG8(AL)) {
8612: case 0x00:
8613: // display.sys is installed
8614: REG8(AL) = 0xff;
8615: REG16(BX) = 0x100; // ???
8616: break;
8617: case 0x01:
8618: active_code_page = REG16(BX);
8619: msdos_nls_tables_update();
8620: REG16(AX) = 0x01;
8621: break;
8622: case 0x02:
8623: REG16(BX) = active_code_page;
8624: break;
8625: case 0x03:
8626: // FIXME
8627: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 1;
8628: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2) = 3;
8629: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4) = 1;
8630: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 6) = active_code_page;
8631: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 8) = active_code_page;
8632: break;
8633: case 0x80:
8634: break; // keyb.com is not installed
8635: default:
8636: 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));
8637: REG16(AX) = 0x01;
8638: m_CF = 1;
8639: break;
8640: }
8641: }
8642:
1.1 root 8643: inline void msdos_int_2fh_aeh()
8644: {
8645: switch(REG8(AL)) {
8646: case 0x00:
8647: REG8(AL) = 0;
8648: break;
8649: case 0x01:
8650: {
8651: char command[MAX_PATH];
8652: memset(command, 0, sizeof(command));
1.1.1.3 root 8653: memcpy(command, mem + SREG_BASE(DS) + REG16(SI) + 1, mem[SREG_BASE(DS) + REG16(SI)]);
1.1 root 8654:
8655: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
8656: param->env_seg = 0;
8657: param->cmd_line.w.l = 44;
8658: param->cmd_line.w.h = (WORK_TOP >> 4);
8659: param->fcb1.w.l = 24;
8660: param->fcb1.w.h = (WORK_TOP >> 4);
8661: param->fcb2.w.l = 24;
8662: param->fcb2.w.h = (WORK_TOP >> 4);
8663:
8664: memset(mem + WORK_TOP + 24, 0x20, 20);
8665:
8666: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
1.1.1.3 root 8667: cmd_line->len = mem[SREG_BASE(DS) + REG16(BX) + 1];
8668: memcpy(cmd_line->cmd, mem + SREG_BASE(DS) + REG16(BX) + 2, cmd_line->len);
1.1 root 8669: cmd_line->cmd[cmd_line->len] = 0x0d;
8670:
8671: if(msdos_process_exec(command, param, 0)) {
8672: REG16(AX) = 0x02;
1.1.1.3 root 8673: m_CF = 1;
1.1 root 8674: }
8675: }
8676: break;
8677: default:
1.1.1.22 root 8678: 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 8679: REG16(AX) = 0x01;
1.1.1.3 root 8680: m_CF = 1;
1.1 root 8681: break;
8682: }
8683: }
8684:
8685: inline void msdos_int_2fh_b7h()
8686: {
8687: switch(REG8(AL)) {
8688: case 0x00:
8689: // append is not installed
8690: REG8(AL) = 0;
8691: break;
1.1.1.22 root 8692: case 0x07:
8693: case 0x11:
8694: break;
1.1 root 8695: default:
1.1.1.22 root 8696: 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 8697: REG16(AX) = 0x01;
1.1.1.3 root 8698: m_CF = 1;
1.1 root 8699: break;
8700: }
8701: }
8702:
1.1.1.24 root 8703: inline void msdos_int_33h_0000h()
8704: {
8705: REG16(AX) = 0xffff; // hardware/driver installed
8706: REG16(BX) = MAX_MOUSE_BUTTONS;
8707: }
8708:
8709: inline void msdos_int_33h_0001h()
8710: {
8711: if(!mouse.active) {
8712: if(!(dwConsoleMode & ENABLE_MOUSE_INPUT)) {
8713: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode | ENABLE_MOUSE_INPUT);
8714: }
8715: mouse.active = true;
8716: pic[1].imr &= ~0x10; // enable irq12
8717: }
8718: }
8719:
8720: inline void msdos_int_33h_0002h()
8721: {
8722: if(mouse.active) {
8723: if(!(dwConsoleMode & ENABLE_MOUSE_INPUT)) {
8724: SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwConsoleMode);
8725: }
8726: mouse.active = false;
8727: pic[1].imr |= 0x10; // disable irq12
8728: }
8729: }
8730:
8731: inline void msdos_int_33h_0003h()
8732: {
8733: REG16(BX) = mouse.get_buttons();
8734: REG16(CX) = max(mouse.min_position.x, min(mouse.max_position.x, mouse.position.x));
8735: REG16(DX) = max(mouse.min_position.y, min(mouse.max_position.y, mouse.position.y));
8736: }
8737:
8738: inline void msdos_int_33h_0005h()
8739: {
8740: if(REG16(BX) < MAX_MOUSE_BUTTONS) {
8741: int idx = REG16(BX);
8742: REG16(BX) = mouse.buttons[idx].pressed_times;
8743: REG16(CX) = max(mouse.min_position.x, min(mouse.max_position.x, mouse.buttons[idx].pressed_position.x));
8744: REG16(DX) = max(mouse.min_position.y, min(mouse.max_position.y, mouse.buttons[idx].pressed_position.y));
8745: mouse.buttons[idx].pressed_times = 0;
8746: } else {
8747: REG16(BX) = REG16(CX) = REG16(DX) = 0x0000;
8748: }
8749: REG16(AX) = mouse.get_buttons();
8750: }
8751:
8752: inline void msdos_int_33h_0006h()
8753: {
8754: if(REG16(BX) < MAX_MOUSE_BUTTONS) {
8755: int idx = REG16(BX);
8756: REG16(BX) = mouse.buttons[idx].released_times;
8757: REG16(CX) = max(mouse.min_position.x, min(mouse.max_position.x, mouse.buttons[idx].released_position.x));
8758: REG16(DX) = max(mouse.min_position.y, min(mouse.max_position.y, mouse.buttons[idx].released_position.y));
8759: mouse.buttons[idx].released_times = 0;
8760: } else {
8761: REG16(BX) = REG16(CX) = REG16(DX) = 0x0000;
8762: }
8763: REG16(AX) = mouse.get_buttons();
8764: }
8765:
8766: inline void msdos_int_33h_0007h()
8767: {
8768: mouse.min_position.x = min(REG16(CX), REG16(DX));
8769: mouse.max_position.x = max(REG16(CX), REG16(DX));
8770: }
8771:
8772: inline void msdos_int_33h_0008h()
8773: {
8774: mouse.min_position.y = min(REG16(CX), REG16(DX));
8775: mouse.max_position.y = max(REG16(CX), REG16(DX));
8776: }
8777:
8778: inline void msdos_int_33h_0009h()
8779: {
8780: mouse.hot_spot[0] = REG16(BX);
8781: mouse.hot_spot[1] = REG16(CX);
8782: }
8783:
8784: inline void msdos_int_33h_000bh()
8785: {
8786: int dx = (mouse.position.x - mouse.prev_position.x) * mouse.mickey.x / 8;
8787: int dy = (mouse.position.y - mouse.prev_position.y) * mouse.mickey.y / 8;
8788: mouse.prev_position.x = mouse.position.x;
8789: mouse.prev_position.y = mouse.position.y;
8790: REG16(CX) = dx;
8791: REG16(DX) = dy;
8792: }
8793:
8794: inline void msdos_int_33h_000ch()
8795: {
8796: mouse.call_mask = REG16(CX);
8797: mouse.call_addr.w.l = REG16(DX);
8798: mouse.call_addr.w.h = SREG(ES);
8799: }
8800:
8801: inline void msdos_int_33h_000fh()
8802: {
8803: mouse.mickey.x = REG16(CX);
8804: mouse.mickey.y = REG16(DX);
8805: }
8806:
8807: inline void msdos_int_33h_0011h()
8808: {
8809: REG16(AX) = 0xffff;
8810: REG16(BX) = MAX_MOUSE_BUTTONS;
8811: }
8812:
8813: inline void msdos_int_33h_0014h()
8814: {
8815: UINT16 old_mask = mouse.call_mask;
8816: UINT16 old_ofs = mouse.call_addr.w.l;
8817: UINT16 old_seg = mouse.call_addr.w.h;
8818:
8819: mouse.call_mask = REG16(CX);
8820: mouse.call_addr.w.l = REG16(DX);
8821: mouse.call_addr.w.h = SREG(ES);
8822:
8823: REG16(CX) = old_mask;
8824: REG16(DX) = old_ofs;
8825: SREG(ES) = old_seg;
8826: i386_load_segment_descriptor(ES);
8827: }
8828:
8829: inline void msdos_int_33h_0015h()
8830: {
8831: REG16(BX) = sizeof(mouse);
8832: }
8833:
8834: inline void msdos_int_33h_0016h()
8835: {
8836: memcpy(mem + SREG_BASE(ES) + REG16(DX), &mouse, sizeof(mouse));
8837: }
8838:
8839: inline void msdos_int_33h_0017h()
8840: {
8841: memcpy(&mouse, mem + SREG_BASE(ES) + REG16(DX), sizeof(mouse));
8842: }
8843:
8844: inline void msdos_int_33h_001ah()
8845: {
8846: mouse.sensitivity[0] = REG16(BX);
8847: mouse.sensitivity[1] = REG16(CX);
8848: mouse.sensitivity[2] = REG16(DX);
8849: }
8850:
8851: inline void msdos_int_33h_001bh()
8852: {
8853: REG16(BX) = mouse.sensitivity[0];
8854: REG16(CX) = mouse.sensitivity[1];
8855: REG16(DX) = mouse.sensitivity[2];
8856: }
8857:
8858: inline void msdos_int_33h_001dh()
8859: {
8860: mouse.display_page = REG16(BX);
8861: }
8862:
8863: inline void msdos_int_33h_001eh()
8864: {
8865: REG16(BX) = mouse.display_page;
8866: }
8867:
8868: inline void msdos_int_33h_0021h()
8869: {
8870: REG16(AX) = 0xffff;
8871: REG16(BX) = MAX_MOUSE_BUTTONS;
8872: }
8873:
8874: inline void msdos_int_33h_0022h()
8875: {
8876: mouse.language = REG16(BX);
8877: }
8878:
8879: inline void msdos_int_33h_0023h()
8880: {
8881: REG16(BX) = mouse.language;
8882: }
8883:
8884: inline void msdos_int_33h_0024h()
8885: {
8886: REG16(BX) = 0x0805; // V8.05
8887: REG16(CX) = 0x0400; // PS/2
8888: }
8889:
8890: inline void msdos_int_33h_0026h()
8891: {
8892: REG16(BX) = 0x0000;
8893: REG16(CX) = mouse.max_position.x;
8894: REG16(DX) = mouse.max_position.y;
8895: }
8896:
8897: inline void msdos_int_33h_002ah()
8898: {
8899: REG16(AX) = mouse.active ? 0 : 0xffff;
8900: REG16(BX) = mouse.hot_spot[0];
8901: REG16(CX) = mouse.hot_spot[1];
8902: REG16(DX) = 4; // PS/2
8903: }
8904:
8905: inline void msdos_int_33h_0031h()
8906: {
8907: REG16(AX) = mouse.min_position.x;
8908: REG16(BX) = mouse.min_position.y;
8909: REG16(CX) = mouse.max_position.x;
8910: REG16(DX) = mouse.max_position.y;
8911: }
8912:
8913: inline void msdos_int_33h_0032h()
8914: {
8915: REG16(AX) = 0;
8916: // REG16(AX) |= 0x8000; // 0025h
8917: REG16(AX) |= 0x4000; // 0026h
8918: // REG16(AX) |= 0x2000; // 0027h
8919: // REG16(AX) |= 0x1000; // 0028h
8920: // REG16(AX) |= 0x0800; // 0029h
8921: REG16(AX) |= 0x0400; // 002ah
8922: // REG16(AX) |= 0x0200; // 002bh
8923: // REG16(AX) |= 0x0100; // 002ch
8924: // REG16(AX) |= 0x0080; // 002dh
8925: // REG16(AX) |= 0x0040; // 002eh
8926: REG16(AX) |= 0x0020; // 002fh
8927: // REG16(AX) |= 0x0010; // 0030h
8928: REG16(AX) |= 0x0008; // 0031h
8929: REG16(AX) |= 0x0004; // 0032h
8930: // REG16(AX) |= 0x0002; // 0033h
8931: // REG16(AX) |= 0x0001; // 0034h
8932: }
8933:
1.1.1.19 root 8934: inline void msdos_int_67h_40h()
8935: {
8936: if(!support_ems) {
8937: REG8(AH) = 0x84;
8938: } else {
8939: REG8(AH) = 0x00;
8940: }
8941: }
8942:
8943: inline void msdos_int_67h_41h()
8944: {
8945: if(!support_ems) {
8946: REG8(AH) = 0x84;
8947: } else {
8948: REG8(AH) = 0x00;
8949: REG16(BX) = EMS_TOP >> 4;
8950: }
8951: }
8952:
8953: inline void msdos_int_67h_42h()
8954: {
8955: if(!support_ems) {
8956: REG8(AH) = 0x84;
8957: } else {
8958: REG8(AH) = 0x00;
8959: REG16(BX) = free_ems_pages;
8960: REG16(DX) = MAX_EMS_PAGES;
8961: }
8962: }
8963:
8964: inline void msdos_int_67h_43h()
8965: {
8966: if(!support_ems) {
8967: REG8(AH) = 0x84;
8968: } else if(REG16(BX) > MAX_EMS_PAGES) {
8969: REG8(AH) = 0x87;
8970: } else if(REG16(BX) > free_ems_pages) {
8971: REG8(AH) = 0x88;
8972: } else if(REG16(BX) == 0) {
8973: REG8(AH) = 0x89;
8974: } else {
8975: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
8976: if(!ems_handles[i].allocated) {
8977: ems_allocate_pages(i, REG16(BX));
8978: REG8(AH) = 0x00;
8979: REG16(DX) = i;
8980: return;
8981: }
8982: }
8983: REG8(AH) = 0x85;
8984: }
8985: }
8986:
8987: inline void msdos_int_67h_44h()
8988: {
8989: if(!support_ems) {
8990: REG8(AH) = 0x84;
8991: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
8992: REG8(AH) = 0x83;
8993: } else if(!(REG16(BX) == 0xffff || REG16(BX) < ems_handles[REG16(DX)].pages)) {
8994: REG8(AH) = 0x8a;
8995: // } else if(!(REG8(AL) < 4)) {
8996: // REG8(AH) = 0x8b;
8997: } else if(REG16(BX) == 0xffff) {
8998: ems_unmap_page(REG8(AL) & 3);
8999: REG8(AH) = 0x00;
9000: } else {
9001: ems_map_page(REG8(AL) & 3, REG16(DX), REG16(BX));
9002: REG8(AH) = 0x00;
9003: }
9004: }
9005:
9006: inline void msdos_int_67h_45h()
9007: {
9008: if(!support_ems) {
9009: REG8(AH) = 0x84;
9010: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
9011: REG8(AH) = 0x83;
9012: } else {
9013: ems_release_pages(REG16(DX));
9014: REG8(AH) = 0x00;
9015: }
9016: }
9017:
9018: inline void msdos_int_67h_46h()
9019: {
9020: if(!support_ems) {
9021: REG8(AH) = 0x84;
9022: } else {
9023: REG16(AX) = 0x0032; // EMS 3.2
9024: // REG16(AX) = 0x0040; // EMS 4.0
9025: }
9026: }
9027:
9028: inline void msdos_int_67h_47h()
9029: {
9030: // NOTE: the map data should be stored in the specified ems page, not process data
9031: process_t *process = msdos_process_info_get(current_psp);
9032:
9033: if(!support_ems) {
9034: REG8(AH) = 0x84;
9035: // } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
9036: // REG8(AH) = 0x83;
9037: } else if(process->ems_pages_stored) {
9038: REG8(AH) = 0x8d;
9039: } else {
9040: for(int i = 0; i < 4; i++) {
9041: process->ems_pages[i].handle = ems_pages[i].handle;
9042: process->ems_pages[i].page = ems_pages[i].page;
9043: process->ems_pages[i].mapped = ems_pages[i].mapped;
9044: }
9045: process->ems_pages_stored = true;
9046: REG8(AH) = 0x00;
9047: }
9048: }
9049:
9050: inline void msdos_int_67h_48h()
9051: {
9052: // NOTE: the map data should be restored from the specified ems page, not process data
9053: process_t *process = msdos_process_info_get(current_psp);
9054:
9055: if(!support_ems) {
9056: REG8(AH) = 0x84;
9057: // } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
9058: // REG8(AH) = 0x83;
9059: } else if(!process->ems_pages_stored) {
9060: REG8(AH) = 0x8e;
9061: } else {
9062: for(int i = 0; i < 4; i++) {
9063: if(process->ems_pages[i].mapped) {
9064: ems_map_page(i, process->ems_pages[i].handle, process->ems_pages[i].page);
9065: } else {
9066: ems_unmap_page(i);
9067: }
9068: }
9069: process->ems_pages_stored = false;
9070: REG8(AH) = 0x00;
9071: }
9072: }
9073:
9074: inline void msdos_int_67h_4bh()
9075: {
9076: if(!support_ems) {
9077: REG8(AH) = 0x84;
9078: } else {
9079: REG8(AH) = 0x00;
9080: REG16(BX) = 0;
9081: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
9082: if(ems_handles[i].allocated) {
9083: REG16(BX)++;
9084: }
9085: }
9086: }
9087: }
9088:
9089: inline void msdos_int_67h_4ch()
9090: {
9091: if(!support_ems) {
9092: REG8(AH) = 0x84;
9093: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
9094: REG8(AH) = 0x83;
9095: } else {
9096: REG8(AH) = 0x00;
9097: REG16(BX) = ems_handles[REG16(DX)].pages;
9098: }
9099: }
9100:
9101: inline void msdos_int_67h_4dh()
9102: {
9103: if(!support_ems) {
9104: REG8(AH) = 0x84;
9105: } else {
9106: REG8(AH) = 0x00;
9107: REG16(BX) = 0;
9108: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
9109: if(ems_handles[i].allocated) {
9110: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 0) = i;
9111: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * REG16(BX) + 2) = ems_handles[i].pages;
9112: REG16(BX)++;
9113: }
9114: }
9115: }
9116: }
9117:
1.1.1.20 root 9118: inline void msdos_int_67h_4eh()
9119: {
9120: if(!support_ems) {
9121: REG8(AH) = 0x84;
9122: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01 || REG8(AL) == 0x02) {
9123: if(REG8(AL) == 0x00 || REG8(AL) == 0x02) {
9124: // save page map
9125: for(int i = 0; i < 4; i++) {
9126: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = ems_pages[i].mapped ? ems_pages[i].handle : 0xffff;
9127: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = ems_pages[i].mapped ? ems_pages[i].page : 0xffff;
9128: }
9129: }
9130: if(REG8(AL) == 0x01 || REG8(AL) == 0x02) {
9131: // restore page map
9132: for(int i = 0; i < 4; i++) {
9133: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0);
9134: UINT16 page = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2);
9135:
9136: if(handle < MAX_EMS_HANDLES && ems_handles[handle].allocated && page < ems_handles[handle].pages) {
9137: ems_map_page(i, handle, page);
9138: } else {
9139: ems_unmap_page(i);
9140: }
9141: }
9142: }
9143: REG8(AH) = 0x00;
9144: } else if(REG8(AL) == 0x03) {
9145: REG8(AH) = 0x00;
1.1.1.21 root 9146: REG8(AL) = 4 * 4;
9147: } else {
1.1.1.22 root 9148: 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 9149: REG8(AH) = 0x8f;
9150: }
9151: }
9152:
9153: inline void msdos_int_67h_4fh()
9154: {
9155: if(!support_ems) {
9156: REG8(AH) = 0x84;
9157: } else if(REG8(AL) == 0x00) {
9158: int count = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI));
9159:
9160: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI)) = count;
9161: for(int i = 0; i < count; i++) {
9162: UINT16 segment = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 2 * i);
9163: UINT16 physical = ((segment << 4) - EMS_TOP) / 0x4000;
9164:
9165: // if(!(physical < 4)) {
9166: // REG8(AH) = 0x8b;
9167: // return;
9168: // }
9169: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 0) = segment;
9170: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 2) = ems_pages[physical & 3].handle;
9171: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 2 + 6 * i + 4) = ems_pages[physical & 3].mapped ? ems_pages[physical & 3].page : 0xffff;
9172: }
9173: REG8(AH) = 0x00;
9174: } else if(REG8(AL) == 0x01) {
9175: int count = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI));
9176:
9177: for(int i = 0; i < count; i++) {
9178: UINT16 segment = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 0);
9179: UINT16 physical = ((segment << 4) - EMS_TOP) / 0x4000;
9180: UINT16 handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 2);
9181: UINT16 logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 2 + 6 * i + 4);
9182:
9183: // if(!(physical < 4)) {
9184: // REG8(AH) = 0x8b;
9185: // return;
9186: // } else
9187: if(!(handle < MAX_EMS_HANDLES && ems_handles[handle].allocated)) {
9188: REG8(AH) = 0x83;
9189: return;
9190: } else if(logical == 0xffff) {
9191: ems_unmap_page(physical & 3);
9192: } else if(logical < ems_handles[handle].pages) {
9193: ems_map_page(physical & 3, handle, logical);
9194: } else {
9195: REG8(AH) = 0x8a;
9196: return;
9197: }
9198: }
9199: REG8(AH) = 0x00;
9200: } else if(REG8(AL) == 0x02) {
9201: REG8(AH) = 0x00;
9202: REG8(AL) = 2 + REG16(BX) * 6;
1.1.1.20 root 9203: } else {
1.1.1.22 root 9204: 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 9205: REG8(AH) = 0x8f;
9206: }
9207: }
9208:
9209: inline void msdos_int_67h_50h()
9210: {
9211: if(!support_ems) {
9212: REG8(AH) = 0x84;
9213: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
9214: REG8(AH) = 0x83;
9215: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
9216: for(int i = 0; i < REG16(CX); i++) {
9217: int logical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 0);
9218: int physical = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 4 * i + 2);
9219:
9220: if(REG8(AL) == 0x01) {
9221: physical = ((physical << 4) - EMS_TOP) / 0x4000;
9222: }
9223: // if(!(physical < 4)) {
9224: // REG8(AH) = 0x8b;
9225: // return;
9226: // } else
9227: if(logical == 0xffff) {
9228: ems_unmap_page(physical & 3);
9229: } else if(logical < ems_handles[REG16(DX)].pages) {
9230: ems_map_page(physical & 3, REG16(DX), logical);
9231: } else {
9232: REG8(AH) = 0x8a;
9233: return;
9234: }
9235: }
9236: REG8(AH) = 0x00;
9237: } else {
1.1.1.22 root 9238: 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 9239: REG8(AH) = 0x8f;
9240: }
9241: }
9242:
1.1.1.19 root 9243: inline void msdos_int_67h_51h()
9244: {
9245: if(!support_ems) {
9246: REG8(AH) = 0x84;
9247: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
9248: REG8(AH) = 0x83;
9249: } else if(REG16(BX) > MAX_EMS_PAGES) {
9250: REG8(AH) = 0x87;
9251: } else if(REG16(BX) > free_ems_pages + ems_handles[REG16(DX)].pages) {
9252: REG8(AH) = 0x88;
9253: } else {
9254: ems_reallocate_pages(REG16(DX), REG16(BX));
9255: REG8(AH) = 0x00;
9256: }
9257: }
9258:
1.1.1.20 root 9259: inline void msdos_int_67h_52h()
9260: {
9261: if(!support_ems) {
9262: REG8(AH) = 0x84;
9263: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
9264: REG8(AH) = 0x83;
9265: } else if(REG8(AL) == 0x00) {
9266: REG8(AL) = 0x00; // handle is volatile
9267: REG8(AH) = 0x00;
9268: } else if(REG8(AL) == 0x01) {
9269: if(REG8(BL) == 0x00) {
9270: REG8(AH) = 0x00;
9271: } else {
9272: REG8(AH) = 0x90; // undefined attribute type
9273: }
9274: } else if(REG8(AL) == 0x02) {
9275: REG8(AL) = 0x00; // only volatile handles supported
9276: REG8(AH) = 0x00;
9277: } else {
1.1.1.22 root 9278: 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 9279: REG8(AH) = 0x8f;
9280: }
9281: }
9282:
1.1.1.19 root 9283: inline void msdos_int_67h_53h()
9284: {
9285: if(!support_ems) {
9286: REG8(AH) = 0x84;
9287: } else if(!(REG16(DX) < MAX_EMS_HANDLES && ems_handles[REG16(DX)].allocated)) {
9288: REG8(AH) = 0x83;
9289: } else if(REG8(AL) == 0x00) {
9290: memcpy(mem + SREG_BASE(ES) + REG16(DI), ems_handles[REG16(DX)].name, 8);
9291: REG8(AH) = 0x00;
9292: } else if(REG8(AL) == 0x01) {
9293: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
9294: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) {
9295: REG8(AH) = 0xa1;
9296: return;
9297: }
9298: }
9299: REG8(AH) = 0x00;
9300: memcpy(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8);
9301: } else {
1.1.1.22 root 9302: 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 9303: REG8(AH) = 0x8f;
1.1.1.19 root 9304: }
9305: }
9306:
9307: inline void msdos_int_67h_54h()
9308: {
9309: if(!support_ems) {
9310: REG8(AH) = 0x84;
9311: } else if(REG8(AL) == 0x00) {
9312: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
9313: if(ems_handles[i].allocated) {
9314: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, ems_handles[i].name, 10);
9315: } else {
9316: memset(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 2, 0, 10);
9317: }
9318: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 10 * i + 0) = i;
9319: }
9320: REG8(AH) = 0x00;
9321: REG8(AL) = MAX_EMS_HANDLES;
9322: } else if(REG8(AL) == 0x01) {
9323: REG8(AH) = 0xa0; // not found
9324: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
9325: if(ems_handles[i].allocated && memcmp(ems_handles[REG16(DX)].name, mem + SREG_BASE(DS) + REG16(SI), 8) == 0) {
9326: REG8(AH) = 0x00;
9327: REG16(DX) = i;
9328: break;
9329: }
9330: }
9331: } else if(REG8(AL) == 0x02) {
9332: REG8(AH) = 0x00;
9333: REG16(BX) = MAX_EMS_HANDLES;
9334: } else {
1.1.1.22 root 9335: 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 9336: REG8(AH) = 0x8f;
9337: }
9338: }
9339:
9340: inline void msdos_int_67h_57h_tmp()
9341: {
9342: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00);
9343: UINT8 src_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04);
9344: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x05);
9345: UINT16 src_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x07);
9346: UINT16 src_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x09);
9347: UINT8 dest_type = *(UINT8 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0b);
9348: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c);
9349: UINT16 dest_ofs = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0e);
9350: UINT16 dest_seg = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x10);
9351:
9352: UINT8 *src_buffer, *dest_buffer;
9353: UINT32 src_addr, dest_addr;
9354: UINT32 src_addr_max, dest_addr_max;
9355:
9356: if(src_type == 0) {
9357: src_buffer = mem;
9358: src_addr = (src_seg << 4) + src_ofs;
9359: src_addr_max = MAX_MEM;
9360: } else {
9361: if(!(src_handle < MAX_EMS_HANDLES && ems_handles[src_handle].allocated)) {
9362: REG8(AH) = 0x83;
9363: return;
9364: } else if(!(src_seg < ems_handles[src_handle].pages)) {
9365: REG8(AH) = 0x8a;
9366: return;
9367: }
9368: src_buffer = ems_handles[src_handle].buffer + 0x4000 * src_seg;
9369: src_addr = src_ofs;
9370: src_addr_max = 0x4000;
9371: }
9372: if(dest_type == 0) {
9373: dest_buffer = mem;
9374: dest_addr = (dest_seg << 4) + dest_ofs;
9375: dest_addr_max = MAX_MEM;
9376: } else {
9377: if(!(dest_handle < MAX_EMS_HANDLES && ems_handles[dest_handle].allocated)) {
9378: REG8(AH) = 0x83;
9379: return;
9380: } else if(!(dest_seg < ems_handles[dest_handle].pages)) {
9381: REG8(AH) = 0x8a;
9382: return;
9383: }
9384: dest_buffer = ems_handles[dest_handle].buffer + 0x4000 * dest_seg;
9385: dest_addr = dest_ofs;
9386: dest_addr_max = 0x4000;
9387: }
9388: for(int i = 0; i < copy_length; i++) {
9389: if(src_addr < src_addr_max && dest_addr < dest_addr_max) {
9390: if(REG8(AL) == 0x00) {
9391: dest_buffer[dest_addr++] = src_buffer[src_addr++];
9392: } else if(REG8(AL) == 0x01) {
9393: UINT8 tmp = dest_buffer[dest_addr];
9394: dest_buffer[dest_addr++] = src_buffer[src_addr];
9395: src_buffer[src_addr++] = tmp;
9396: }
9397: } else {
9398: REG8(AH) = 0x93;
9399: return;
9400: }
9401: }
9402: REG8(AH) = 0x80;
9403: }
9404:
9405: inline void msdos_int_67h_57h()
9406: {
9407: if(!support_ems) {
9408: REG8(AH) = 0x84;
9409: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
9410: struct {
9411: UINT16 handle;
9412: UINT16 page;
9413: bool mapped;
9414: } tmp_pages[4];
9415:
9416: // unmap pages to copy memory data to ems buffer
9417: for(int i = 0; i < 4; i++) {
9418: tmp_pages[i].handle = ems_pages[i].handle;
9419: tmp_pages[i].page = ems_pages[i].page;
9420: tmp_pages[i].mapped = ems_pages[i].mapped;
9421: ems_unmap_page(i);
9422: }
9423:
9424: // run move/exchange operation
9425: msdos_int_67h_57h_tmp();
9426:
9427: // restore unmapped pages
9428: for(int i = 0; i < 4; i++) {
9429: if(tmp_pages[i].mapped) {
9430: ems_map_page(i, tmp_pages[i].handle, tmp_pages[i].page);
9431: }
9432: }
9433: } else {
1.1.1.22 root 9434: 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 9435: REG8(AH) = 0x8f;
9436: }
9437: }
9438:
9439: inline void msdos_int_67h_58h()
9440: {
9441: if(!support_ems) {
9442: REG8(AH) = 0x84;
9443: } else if(REG8(AL) == 0x00) {
9444: for(int i = 0; i < 4; i++) {
9445: *(UINT16 *)(mem +SREG_BASE(ES) + REG16(DI) + 4 * i + 0) = (EMS_TOP + 0x4000 * i) >> 4;
9446: *(UINT16 *)(mem +SREG_BASE(ES) + REG16(DI) + 4 * i + 2) = i;
9447: }
9448: REG8(AH) = 0x00;
9449: REG16(CX) = 4;
9450: } else if(REG8(AL) == 0x01) {
9451: REG8(AH) = 0x00;
9452: REG16(CX) = 4;
9453: } else {
1.1.1.22 root 9454: 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 9455: REG8(AH) = 0x8f;
9456: }
9457: }
9458:
9459: inline void msdos_int_67h_5ah()
9460: {
9461: if(!support_ems) {
1.1.1.19 root 9462: REG8(AH) = 0x84;
1.1.1.20 root 9463: } else if(REG16(BX) > MAX_EMS_PAGES) {
9464: REG8(AH) = 0x87;
9465: } else if(REG16(BX) > free_ems_pages) {
9466: REG8(AH) = 0x88;
9467: // } else if(REG16(BX) == 0) {
9468: // REG8(AH) = 0x89;
9469: } else if(REG8(AL) == 0x00 || REG8(AL) == 0x01) {
9470: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
9471: if(!ems_handles[i].allocated) {
9472: ems_allocate_pages(i, REG16(BX));
9473: REG8(AH) = 0x00;
9474: REG16(DX) = i;
9475: return;
9476: }
9477: }
9478: REG8(AH) = 0x85;
9479: } else {
1.1.1.22 root 9480: 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 9481: REG8(AH) = 0x8f;
1.1.1.19 root 9482: }
9483: }
9484:
9485: #ifdef SUPPORT_XMS
9486:
1.1.1.26! root 9487: inline void msdos_xms_init()
! 9488: {
! 9489: memset(xms_handles, 0, sizeof(xms_handles));
! 9490: xms_a20_local_enb_count = 0;
! 9491: }
! 9492:
1.1.1.19 root 9493: inline void msdos_call_xms_00h()
9494: {
9495: REG16(AX) = 0x0270; // V2.70
9496: REG16(BX) = 0x0000;
9497: // REG16(DX) = 0x0000; // hma does not exist
9498: REG16(DX) = 0x0001; // hma does exist
9499: }
9500:
9501: inline void msdos_call_xms_01h()
9502: {
9503: REG16(AX) = 0x0000;
9504: // REG8(BL) = 0x90; // hma does not exist
9505: REG8(BL) = 0x91; // hma is already used
9506: }
9507:
9508: inline void msdos_call_xms_02h()
9509: {
9510: REG16(AX) = 0x0000;
9511: // REG8(BL) = 0x90; // hma does not exist
9512: REG8(BL) = 0x91; // hma is already used
9513: }
9514:
9515: inline void msdos_call_xms_03h()
9516: {
9517: i386_set_a20_line(1);
9518: REG16(AX) = 0x0001;
9519: REG8(BL) = 0x00;
9520: }
9521:
9522: inline void msdos_call_xms_04h()
9523: {
1.1.1.21 root 9524: i386_set_a20_line(0);
9525: REG16(AX) = 0x0001;
9526: REG8(BL) = 0x00;
1.1.1.19 root 9527: }
9528:
9529: inline void msdos_call_xms_05h()
9530: {
9531: i386_set_a20_line(1);
9532: REG16(AX) = 0x0001;
9533: REG8(BL) = 0x00;
1.1.1.21 root 9534: xms_a20_local_enb_count++;
1.1.1.19 root 9535: }
9536:
9537: void msdos_call_xms_06h()
9538: {
1.1.1.21 root 9539: if(xms_a20_local_enb_count > 0) {
9540: xms_a20_local_enb_count--;
9541: }
9542: if(xms_a20_local_enb_count == 0) {
1.1.1.19 root 9543: i386_set_a20_line(0);
1.1.1.21 root 9544: }
9545: if((m_a20_mask >> 20) & 1) {
1.1.1.19 root 9546: REG16(AX) = 0x0000;
9547: REG8(BL) = 0x94;
1.1.1.21 root 9548: } else {
9549: REG16(AX) = 0x0001;
9550: REG8(BL) = 0x00;
1.1.1.19 root 9551: }
9552: }
9553:
9554: inline void msdos_call_xms_07h()
9555: {
9556: REG16(AX) = (m_a20_mask >> 20) & 1;
9557: REG8(BL) = 0x00;
9558: }
9559:
9560: inline void msdos_call_xms_08h()
9561: {
9562: REG16(AX) = REG16(DX) = 0x0000;
9563:
9564: int mcb_seg = EMB_TOP >> 4;
9565:
9566: while(1) {
9567: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
9568:
9569: if(mcb->psp == 0) {
9570: if(REG16(AX) < mcb->size_kb()) {
9571: REG16(AX) = mcb->size_kb();
9572: }
9573: REG16(DX) += mcb->size_kb();
9574: }
9575: if(mcb->mz == 'Z') {
9576: break;
9577: }
9578: mcb_seg += 1 + mcb->paragraphs();
9579: }
9580:
9581: if(REG16(AX) == 0 && REG16(DX) == 0) {
9582: REG8(BL) = 0xa0;
9583: } else {
9584: REG8(BL) = 0x00;
9585: }
9586: }
9587:
9588: inline void msdos_call_xms_09h()
9589: {
9590: for(int i = 1; i <= MAX_XMS_HANDLES; i++) {
9591: if(!xms_handles[i].allocated) {
9592: if((xms_handles[i].seg = msdos_mem_alloc(EMB_TOP >> 4, REG16(DX) * 64, 0)) != -1) {
9593: xms_handles[i].size_kb = REG16(DX);
9594: xms_handles[i].lock = 0;
9595: xms_handles[i].allocated = true;
9596:
9597: REG16(AX) = 0x0001;
9598: REG16(DX) = i;
9599: REG8(BL) = 0x00;
9600: } else {
9601: REG16(AX) = REG16(DX) = 0x0000;
9602: REG8(BL) = 0xa0;
9603: }
9604: return;
9605: }
9606: }
9607: REG16(AX) = REG16(DX) = 0x0000;
9608: REG8(BL) = 0xa1;
9609: }
9610:
9611: inline void msdos_call_xms_0ah()
9612: {
9613: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
9614: REG16(AX) = 0x0000;
9615: REG8(BL) = 0xa2;
9616: } else if(xms_handles[REG16(DX)].lock > 0) {
9617: REG16(AX) = 0x0000;
9618: REG8(BL) = 0xab;
9619: } else {
9620: msdos_mem_free(xms_handles[REG16(DX)].seg);
9621: xms_handles[REG16(DX)].allocated = false;
9622:
9623: REG16(AX) = 0x0001;
9624: REG8(BL) = 0x00;
9625: }
9626: }
9627:
9628: inline void msdos_call_xms_0bh()
9629: {
9630: UINT32 copy_length = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x00);
9631: UINT16 src_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x04);
9632: UINT32 src_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x06);
9633: UINT16 dest_handle = *(UINT16 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0a);
9634: UINT32 dest_addr = *(UINT32 *)(mem + SREG_BASE(DS) + REG16(SI) + 0x0c);
9635:
9636: UINT8 *src_buffer, *dest_buffer;
9637: UINT32 src_addr_max, dest_addr_max;
9638:
9639: if(src_handle == 0) {
9640: src_buffer = mem;
9641: src_addr = (((src_addr >> 16) & 0xffff) << 4) + (src_addr & 0xffff);
9642: src_addr_max = MAX_MEM;
9643: } else {
9644: if(!(src_handle >= 1 && src_handle <= MAX_XMS_HANDLES && xms_handles[src_handle].allocated)) {
9645: REG16(AX) = 0x0000;
9646: REG8(BL) = 0xa3;
9647: return;
9648: }
9649: src_buffer = mem + (xms_handles[src_handle].seg << 4);
9650: src_addr_max = xms_handles[src_handle].size_kb * 1024;
9651: }
9652: if(dest_handle == 0) {
9653: dest_buffer = mem;
9654: dest_addr = (((dest_addr >> 16) & 0xffff) << 4) + (dest_addr & 0xffff);
9655: dest_addr_max = MAX_MEM;
9656: } else {
9657: if(!(dest_handle >= 1 && dest_handle <= MAX_XMS_HANDLES && xms_handles[dest_handle].allocated)) {
9658: REG16(AX) = 0x0000;
9659: REG8(BL) = 0xa5;
9660: return;
9661: }
9662: dest_buffer = mem + (xms_handles[dest_handle].seg << 4);
9663: dest_addr_max = xms_handles[dest_handle].size_kb * 1024;
9664: }
9665: for(int i = 0; i < copy_length; i++) {
9666: if(src_addr < src_addr_max && dest_addr < dest_addr_max) {
9667: dest_buffer[dest_addr++] = src_buffer[src_addr++];
9668: } else {
9669: break;
9670: }
9671: }
9672: REG16(AX) = 0x0001;
9673: REG8(BL) = 0x00;
9674: }
9675:
9676: inline void msdos_call_xms_0ch()
9677: {
9678: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
9679: REG16(AX) = 0x0000;
9680: REG8(BL) = 0xa2;
9681: } else {
9682: xms_handles[REG16(DX)].lock++;
9683: REG16(AX) = 0x0001;
9684: REG8(BL) = 0x00;
9685: UINT32 addr = xms_handles[REG16(DX)].seg << 4;
9686: REG16(DX) = (addr >> 16) & 0xffff;
9687: REG16(BX) = (addr ) & 0xffff;
9688: }
9689: }
9690:
9691: inline void msdos_call_xms_0dh()
9692: {
9693: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
9694: REG16(AX) = 0x0000;
9695: REG8(BL) = 0xa2;
9696: } else if(!(xms_handles[REG16(DX)].lock > 0)) {
9697: REG16(AX) = 0x0000;
9698: REG8(BL) = 0xaa;
9699: } else {
9700: xms_handles[REG16(DX)].lock--;
9701: REG16(AX) = 0x0001;
9702: REG8(BL) = 0x00;
9703: }
9704: }
9705:
9706: inline void msdos_call_xms_0eh()
9707: {
9708: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
9709: REG16(AX) = 0x0000;
9710: REG8(BL) = 0xa2;
9711: } else {
9712: REG16(AX) = 0x0001;
9713: REG8(BH) = xms_handles[REG16(DX)].lock;
9714: REG8(BL) = 0x00;
9715: for(int i = 1; i <= MAX_XMS_HANDLES; i++) {
9716: if(!xms_handles[i].allocated) {
9717: REG8(BL)++;
9718: }
9719: }
9720: REG16(DX) = xms_handles[REG16(DX)].size_kb;
9721: }
9722: }
9723:
9724: inline void msdos_call_xms_0fh()
9725: {
9726: if(!(REG16(DX) >= 1 && REG16(DX) <= MAX_XMS_HANDLES && xms_handles[REG16(DX)].allocated)) {
9727: REG16(AX) = 0x0000;
9728: REG8(BL) = 0xa2;
9729: } else if(xms_handles[REG16(DX)].lock > 0) {
9730: REG16(AX) = 0x0000;
9731: REG8(BL) = 0xab;
9732: } else if(msdos_mem_realloc(xms_handles[REG16(DX)].seg, REG16(BX) * 64, NULL)) {
9733: REG16(AX) = 0x0000;
9734: REG8(BL) = 0xa0;
9735: } else {
9736: REG16(AX) = 0x0001;
9737: REG8(BL) = 0x00;
9738: }
9739: }
9740:
9741: inline void msdos_call_xms_10h()
9742: {
9743: int seg;
9744:
9745: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(DX), 0)) != -1) {
9746: REG16(AX) = 0x0001;
9747: REG16(BX) = seg;
9748: } else {
9749: REG16(AX) = 0x0000;
9750: REG8(BL) = 0xb0;
9751: REG16(DX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
9752: }
9753: }
9754:
9755: inline void msdos_call_xms_11h()
9756: {
9757: int mcb_seg = REG16(DX) - 1;
9758: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
9759:
9760: if(mcb->mz == 'M' || mcb->mz == 'Z') {
9761: msdos_mem_free(REG16(DX));
9762: REG16(AX) = 0x0001;
9763: REG8(BL) = 0x00;
9764: } else {
9765: REG16(AX) = 0x0000;
9766: REG8(BL) = 0xb2;
9767: }
9768: }
9769:
9770: inline void msdos_call_xms_12h()
9771: {
9772: int mcb_seg = REG16(DX) - 1;
9773: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
9774: int max_paragraphs;
9775:
9776: if(mcb->mz == 'M' || mcb->mz == 'Z') {
9777: if(!msdos_mem_realloc(REG16(DX), REG16(BX), &max_paragraphs)) {
9778: REG16(AX) = 0x0001;
9779: REG8(BL) = 0x00;
9780: } else {
9781: REG16(AX) = 0x0000;
9782: REG8(BL) = 0xb0;
9783: REG16(DX) = max_paragraphs;
9784: }
9785: } else {
9786: REG16(AX) = 0x0000;
9787: REG8(BL) = 0xb2;
9788: }
9789: }
9790:
9791: #endif
9792:
1.1.1.26! root 9793: UINT16 msdos_get_equipment()
! 9794: {
! 9795: static UINT16 equip = 0;
! 9796:
! 9797: if(equip == 0) {
! 9798: #ifdef SUPPORT_FPU
! 9799: equip |= (1 << 1); // 80x87 coprocessor installed
! 9800: #endif
! 9801: equip |= (1 << 2); // pointing device installed (PS/2)
! 9802: equip |= (2 << 4); // initial video mode (80x25 color)
! 9803: // equip |= (1 << 8); // 0 if DMA installed
! 9804: equip |= (2 << 9); // number of serial ports
! 9805: equip |= (3 << 14); // number of printer ports (NOTE: this number is 3 on Windows 98 SE though only LPT1 exists)
! 9806: }
! 9807: return(equip);
! 9808: }
! 9809:
1.1 root 9810: void msdos_syscall(unsigned num)
9811: {
1.1.1.22 root 9812: #ifdef ENABLE_DEBUG_SYSCALL
9813: if(num == 0x68) {
9814: // dummy interrupt for EMS (int 67h)
9815: 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));
9816: } else if(num == 0x69) {
9817: // dummy interrupt for XMS (call far)
9818: 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));
9819: } else if(num == 0x6a) {
9820: // dummy interrupt for case map routine pointed in the country info
9821: } else {
9822: 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));
9823: }
9824: #endif
1.1.1.26! root 9825: ctrl_c_pressed = ctrl_c_detected = false;
1.1.1.22 root 9826:
1.1 root 9827: switch(num) {
9828: case 0x00:
9829: error("division by zero\n");
9830: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
9831: break;
9832: case 0x04:
9833: error("overflow\n");
9834: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
9835: break;
9836: case 0x06:
9837: // NOTE: ish.com has illegal instruction...
1.1.1.14 root 9838: if(!ignore_illegal_insn) {
9839: error("illegal instruction\n");
9840: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
9841: } else {
9842: #if defined(HAS_I386)
9843: m_eip++;
9844: #else
9845: m_pc++;
9846: #endif
9847: }
1.1 root 9848: break;
1.1.1.8 root 9849: case 0x08:
1.1.1.14 root 9850: // pcbios_irq0(); // this causes too slow emulation...
1.1.1.8 root 9851: case 0x09:
9852: case 0x0a:
9853: case 0x0b:
9854: case 0x0c:
9855: case 0x0d:
9856: case 0x0e:
9857: case 0x0f:
9858: // EOI
9859: pic[0].isr &= ~(1 << (num - 0x08));
9860: pic_update();
9861: break;
1.1 root 9862: case 0x10:
9863: // PC BIOS - Video
1.1.1.14 root 9864: if(!restore_console_on_exit) {
1.1.1.15 root 9865: change_console_size(scr_width, scr_height);
1.1 root 9866: }
1.1.1.3 root 9867: m_CF = 0;
1.1 root 9868: switch(REG8(AH)) {
1.1.1.16 root 9869: case 0x00: pcbios_int_10h_00h(); break;
1.1 root 9870: case 0x01: pcbios_int_10h_01h(); break;
9871: case 0x02: pcbios_int_10h_02h(); break;
9872: case 0x03: pcbios_int_10h_03h(); break;
9873: case 0x05: pcbios_int_10h_05h(); break;
9874: case 0x06: pcbios_int_10h_06h(); break;
9875: case 0x07: pcbios_int_10h_07h(); break;
9876: case 0x08: pcbios_int_10h_08h(); break;
9877: case 0x09: pcbios_int_10h_09h(); break;
9878: case 0x0a: pcbios_int_10h_0ah(); break;
9879: case 0x0b: break;
9880: case 0x0c: break;
9881: case 0x0d: break;
9882: case 0x0e: pcbios_int_10h_0eh(); break;
9883: case 0x0f: pcbios_int_10h_0fh(); break;
9884: case 0x10: break;
1.1.1.14 root 9885: case 0x11: pcbios_int_10h_11h(); break;
9886: case 0x12: pcbios_int_10h_12h(); break;
1.1 root 9887: case 0x13: pcbios_int_10h_13h(); break;
9888: case 0x18: REG8(AL) = 0x86; break;
1.1.1.14 root 9889: case 0x1a: pcbios_int_10h_1ah(); break;
1.1.1.24 root 9890: case 0x1b: REG8(AL) = 0x00; break; // functionality/state information is not supported
9891: case 0x1c: REG8(AL) = 0x00; break; // save/restore video state is not supported
1.1 root 9892: case 0x1d: pcbios_int_10h_1dh(); break;
1.1.1.24 root 9893: case 0x1e: REG8(AL) = 0x00; break; // flat-panel functions are not supported
9894: case 0x1f: REG8(AL) = 0x00; break; // xga functions are not supported
1.1.1.22 root 9895: case 0x4f: pcbios_int_10h_4fh(); break;
9896: case 0x80: m_CF = 1; break; // unknown
9897: case 0x81: m_CF = 1; break; // unknown
1.1 root 9898: case 0x82: pcbios_int_10h_82h(); break;
1.1.1.22 root 9899: case 0x83: pcbios_int_10h_83h(); break;
9900: case 0x8b: break;
9901: case 0x8c: m_CF = 1; break; // unknown
9902: case 0x8d: m_CF = 1; break; // unknown
9903: case 0x8e: m_CF = 1; break; // unknown
9904: case 0x90: pcbios_int_10h_90h(); break;
9905: case 0x91: pcbios_int_10h_91h(); break;
9906: case 0x92: break;
9907: case 0x93: break;
9908: case 0xef: pcbios_int_10h_efh(); break;
1.1.1.24 root 9909: case 0xfa: break; // ega register interface library is not installed
1.1 root 9910: case 0xfe: pcbios_int_10h_feh(); break;
9911: case 0xff: pcbios_int_10h_ffh(); break;
9912: default:
1.1.1.22 root 9913: 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));
9914: m_CF = 1;
1.1 root 9915: break;
9916: }
9917: break;
9918: case 0x11:
9919: // PC BIOS - Get Equipment List
1.1.1.26! root 9920: REG16(AX) = msdos_get_equipment();
1.1 root 9921: break;
9922: case 0x12:
9923: // PC BIOS - Get Memory Size
9924: REG16(AX) = MEMORY_END / 1024;
9925: break;
9926: case 0x13:
9927: // PC BIOS - Disk
1.1.1.22 root 9928: // 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 9929: REG8(AH) = 0xff;
1.1.1.3 root 9930: m_CF = 1;
1.1 root 9931: break;
9932: case 0x14:
9933: // PC BIOS - Serial I/O
1.1.1.25 root 9934: switch(REG8(AH)) {
9935: case 0x00: pcbios_int_14h_00h(); break;
9936: case 0x01: pcbios_int_14h_01h(); break;
9937: case 0x02: pcbios_int_14h_02h(); break;
9938: case 0x03: pcbios_int_14h_03h(); break;
9939: case 0x04: pcbios_int_14h_04h(); break;
9940: case 0x05: pcbios_int_14h_05h(); break;
9941: default:
9942: 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));
9943: break;
9944: }
1.1 root 9945: break;
9946: case 0x15:
9947: // PC BIOS
1.1.1.3 root 9948: m_CF = 0;
1.1 root 9949: switch(REG8(AH)) {
1.1.1.14 root 9950: case 0x10: pcbios_int_15h_10h(); break;
1.1 root 9951: case 0x23: pcbios_int_15h_23h(); break;
9952: case 0x24: pcbios_int_15h_24h(); break;
1.1.1.24 root 9953: case 0x41: break;
1.1 root 9954: case 0x49: pcbios_int_15h_49h(); break;
1.1.1.22 root 9955: case 0x50: pcbios_int_15h_50h(); break;
1.1 root 9956: case 0x86: pcbios_int_15h_86h(); break;
9957: case 0x87: pcbios_int_15h_87h(); break;
9958: case 0x88: pcbios_int_15h_88h(); break;
9959: case 0x89: pcbios_int_15h_89h(); break;
1.1.1.21 root 9960: case 0x8a: pcbios_int_15h_8ah(); break;
1.1.1.22 root 9961: case 0xc0: // PS/2 ???
9962: case 0xc1:
9963: case 0xc2:
9964: REG8(AH) = 0x86;
9965: m_CF = 1;
9966: break;
1.1.1.3 root 9967: #if defined(HAS_I386)
1.1 root 9968: case 0xc9: pcbios_int_15h_c9h(); break;
1.1.1.3 root 9969: #endif
1.1 root 9970: case 0xca: pcbios_int_15h_cah(); break;
1.1.1.22 root 9971: case 0xe8: pcbios_int_15h_e8h(); break;
1.1 root 9972: default:
1.1.1.22 root 9973: 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));
9974: REG8(AH) = 0x86;
1.1.1.3 root 9975: m_CF = 1;
1.1 root 9976: break;
9977: }
9978: break;
9979: case 0x16:
9980: // PC BIOS - Keyboard
1.1.1.3 root 9981: m_CF = 0;
1.1 root 9982: switch(REG8(AH)) {
9983: case 0x00: pcbios_int_16h_00h(); break;
9984: case 0x01: pcbios_int_16h_01h(); break;
9985: case 0x02: pcbios_int_16h_02h(); break;
9986: case 0x03: pcbios_int_16h_03h(); break;
9987: case 0x05: pcbios_int_16h_05h(); break;
9988: case 0x10: pcbios_int_16h_00h(); break;
9989: case 0x11: pcbios_int_16h_01h(); break;
9990: case 0x12: pcbios_int_16h_12h(); break;
9991: case 0x13: pcbios_int_16h_13h(); break;
9992: case 0x14: pcbios_int_16h_14h(); break;
1.1.1.24 root 9993: case 0x55: pcbios_int_16h_55h(); break;
1.1.1.22 root 9994: case 0xda: break; // unknown
9995: case 0xff: break; // unknown
1.1 root 9996: default:
1.1.1.22 root 9997: 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 9998: break;
9999: }
10000: break;
10001: case 0x17:
10002: // PC BIOS - Printer
1.1.1.22 root 10003: // 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 10004: break;
10005: case 0x1a:
10006: // PC BIOS - Timer
1.1.1.3 root 10007: m_CF = 0;
1.1 root 10008: switch(REG8(AH)) {
10009: case 0x00: pcbios_int_1ah_00h(); break;
10010: case 0x01: break;
10011: case 0x02: pcbios_int_1ah_02h(); break;
10012: case 0x03: break;
10013: case 0x04: pcbios_int_1ah_04h(); break;
10014: case 0x05: break;
10015: case 0x0a: pcbios_int_1ah_0ah(); break;
10016: case 0x0b: break;
1.1.1.14 root 10017: case 0x35: break; // Word Perfect Third Party Interface?
10018: case 0x36: break; // Word Perfect Third Party Interface
10019: case 0x70: break; // SNAP? (Simple Network Application Protocol)
1.1 root 10020: default:
1.1.1.22 root 10021: 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 10022: break;
10023: }
10024: break;
10025: case 0x20:
1.1.1.3 root 10026: msdos_process_terminate(SREG(CS), retval, 1);
1.1 root 10027: break;
10028: case 0x21:
10029: // MS-DOS System Call
1.1.1.3 root 10030: m_CF = 0;
1.1 root 10031: switch(REG8(AH)) {
10032: case 0x00: msdos_int_21h_00h(); break;
10033: case 0x01: msdos_int_21h_01h(); break;
10034: case 0x02: msdos_int_21h_02h(); break;
10035: case 0x03: msdos_int_21h_03h(); break;
10036: case 0x04: msdos_int_21h_04h(); break;
10037: case 0x05: msdos_int_21h_05h(); break;
10038: case 0x06: msdos_int_21h_06h(); break;
10039: case 0x07: msdos_int_21h_07h(); break;
10040: case 0x08: msdos_int_21h_08h(); break;
10041: case 0x09: msdos_int_21h_09h(); break;
10042: case 0x0a: msdos_int_21h_0ah(); break;
10043: case 0x0b: msdos_int_21h_0bh(); break;
10044: case 0x0c: msdos_int_21h_0ch(); break;
10045: case 0x0d: msdos_int_21h_0dh(); break;
10046: case 0x0e: msdos_int_21h_0eh(); break;
1.1.1.14 root 10047: case 0x0f: msdos_int_21h_0fh(); break;
10048: case 0x10: msdos_int_21h_10h(); break;
1.1 root 10049: case 0x11: msdos_int_21h_11h(); break;
10050: case 0x12: msdos_int_21h_12h(); break;
10051: case 0x13: msdos_int_21h_13h(); break;
1.1.1.16 root 10052: case 0x14: msdos_int_21h_14h(); break;
10053: case 0x15: msdos_int_21h_15h(); break;
1.1.1.14 root 10054: case 0x16: msdos_int_21h_16h(); break;
1.1.1.16 root 10055: case 0x17: msdos_int_21h_17h(); break;
1.1 root 10056: case 0x18: msdos_int_21h_18h(); break;
10057: case 0x19: msdos_int_21h_19h(); break;
10058: case 0x1a: msdos_int_21h_1ah(); break;
10059: case 0x1b: msdos_int_21h_1bh(); break;
10060: case 0x1c: msdos_int_21h_1ch(); break;
10061: case 0x1d: msdos_int_21h_1dh(); break;
10062: case 0x1e: msdos_int_21h_1eh(); break;
10063: case 0x1f: msdos_int_21h_1fh(); break;
10064: case 0x20: msdos_int_21h_20h(); break;
1.1.1.14 root 10065: case 0x21: msdos_int_21h_21h(); break;
10066: case 0x22: msdos_int_21h_22h(); break;
1.1.1.16 root 10067: case 0x23: msdos_int_21h_23h(); break;
10068: case 0x24: msdos_int_21h_24h(); break;
1.1 root 10069: case 0x25: msdos_int_21h_25h(); break;
10070: case 0x26: msdos_int_21h_26h(); break;
1.1.1.16 root 10071: case 0x27: msdos_int_21h_27h(); break;
10072: case 0x28: msdos_int_21h_28h(); break;
1.1 root 10073: case 0x29: msdos_int_21h_29h(); break;
10074: case 0x2a: msdos_int_21h_2ah(); break;
10075: case 0x2b: msdos_int_21h_2bh(); break;
10076: case 0x2c: msdos_int_21h_2ch(); break;
10077: case 0x2d: msdos_int_21h_2dh(); break;
10078: case 0x2e: msdos_int_21h_2eh(); break;
10079: case 0x2f: msdos_int_21h_2fh(); break;
10080: case 0x30: msdos_int_21h_30h(); break;
10081: case 0x31: msdos_int_21h_31h(); break;
10082: case 0x32: msdos_int_21h_32h(); break;
10083: case 0x33: msdos_int_21h_33h(); break;
1.1.1.23 root 10084: case 0x34: msdos_int_21h_34h(); break;
1.1 root 10085: case 0x35: msdos_int_21h_35h(); break;
10086: case 0x36: msdos_int_21h_36h(); break;
10087: case 0x37: msdos_int_21h_37h(); break;
1.1.1.14 root 10088: case 0x38: msdos_int_21h_38h(); break;
1.1 root 10089: case 0x39: msdos_int_21h_39h(0); break;
10090: case 0x3a: msdos_int_21h_3ah(0); break;
10091: case 0x3b: msdos_int_21h_3bh(0); break;
10092: case 0x3c: msdos_int_21h_3ch(); break;
10093: case 0x3d: msdos_int_21h_3dh(); break;
10094: case 0x3e: msdos_int_21h_3eh(); break;
10095: case 0x3f: msdos_int_21h_3fh(); break;
10096: case 0x40: msdos_int_21h_40h(); break;
10097: case 0x41: msdos_int_21h_41h(0); break;
10098: case 0x42: msdos_int_21h_42h(); break;
10099: case 0x43: msdos_int_21h_43h(0); break;
10100: case 0x44: msdos_int_21h_44h(); break;
10101: case 0x45: msdos_int_21h_45h(); break;
10102: case 0x46: msdos_int_21h_46h(); break;
10103: case 0x47: msdos_int_21h_47h(0); break;
10104: case 0x48: msdos_int_21h_48h(); break;
10105: case 0x49: msdos_int_21h_49h(); break;
10106: case 0x4a: msdos_int_21h_4ah(); break;
10107: case 0x4b: msdos_int_21h_4bh(); break;
10108: case 0x4c: msdos_int_21h_4ch(); break;
10109: case 0x4d: msdos_int_21h_4dh(); break;
10110: case 0x4e: msdos_int_21h_4eh(); break;
10111: case 0x4f: msdos_int_21h_4fh(); break;
10112: case 0x50: msdos_int_21h_50h(); break;
10113: case 0x51: msdos_int_21h_51h(); break;
10114: case 0x52: msdos_int_21h_52h(); break;
10115: // 0x53: translate bios parameter block to drive param bock
10116: case 0x54: msdos_int_21h_54h(); break;
10117: case 0x55: msdos_int_21h_55h(); break;
10118: case 0x56: msdos_int_21h_56h(0); break;
10119: case 0x57: msdos_int_21h_57h(); break;
10120: case 0x58: msdos_int_21h_58h(); break;
10121: case 0x59: msdos_int_21h_59h(); break;
10122: case 0x5a: msdos_int_21h_5ah(); break;
10123: case 0x5b: msdos_int_21h_5bh(); break;
10124: case 0x5c: msdos_int_21h_5ch(); break;
1.1.1.22 root 10125: case 0x5d: msdos_int_21h_5dh(); break;
1.1 root 10126: // 0x5e: ms-network
10127: // 0x5f: ms-network
10128: case 0x60: msdos_int_21h_60h(0); break;
10129: case 0x61: msdos_int_21h_61h(); break;
10130: case 0x62: msdos_int_21h_62h(); break;
10131: case 0x63: msdos_int_21h_63h(); break;
10132: // 0x64: set device driver lockahead flag
10133: case 0x65: msdos_int_21h_65h(); break;
10134: case 0x66: msdos_int_21h_66h(); break;
10135: case 0x67: msdos_int_21h_67h(); break;
10136: case 0x68: msdos_int_21h_68h(); break;
10137: case 0x69: msdos_int_21h_69h(); break;
10138: case 0x6a: msdos_int_21h_6ah(); break;
10139: case 0x6b: msdos_int_21h_6bh(); break;
10140: case 0x6c: msdos_int_21h_6ch(0); break;
10141: // 0x6d: find first rom program
10142: // 0x6e: find next rom program
10143: // 0x6f: get/set rom scan start address
10144: // 0x70: windows95 get/set internationalization information
10145: case 0x71:
10146: // windows95 long filename functions
10147: switch(REG8(AL)) {
10148: case 0x0d: msdos_int_21h_710dh(); break;
10149: case 0x39: msdos_int_21h_39h(1); break;
10150: case 0x3a: msdos_int_21h_3ah(1); break;
10151: case 0x3b: msdos_int_21h_3bh(1); break;
1.1.1.17 root 10152: case 0x41: msdos_int_21h_7141h(1); break;
1.1 root 10153: case 0x43: msdos_int_21h_43h(1); break;
10154: case 0x47: msdos_int_21h_47h(1); break;
10155: case 0x4e: msdos_int_21h_714eh(); break;
10156: case 0x4f: msdos_int_21h_714fh(); break;
10157: case 0x56: msdos_int_21h_56h(1); break;
10158: case 0x60: msdos_int_21h_60h(1); break;
10159: case 0x6c: msdos_int_21h_6ch(1); break;
10160: case 0xa0: msdos_int_21h_71a0h(); break;
10161: case 0xa1: msdos_int_21h_71a1h(); break;
10162: case 0xa6: msdos_int_21h_71a6h(); break;
10163: case 0xa7: msdos_int_21h_71a7h(); break;
10164: case 0xa8: msdos_int_21h_71a8h(); break;
10165: // 0xa9: server create/open file
1.1.1.22 root 10166: case 0xaa: msdos_int_21h_71aah(); break;
1.1 root 10167: default:
1.1.1.22 root 10168: 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 10169: REG16(AX) = 0x7100;
1.1.1.3 root 10170: m_CF = 1;
1.1 root 10171: break;
10172: }
10173: break;
10174: // 0x72: Windows95 beta - LFN FindClose
10175: case 0x73:
10176: // windows95 fat32 functions
10177: switch(REG8(AL)) {
1.1.1.14 root 10178: case 0x00: msdos_int_21h_7300h(); break;
10179: // 0x01: set drive locking ???
10180: case 0x02: msdos_int_21h_7302h(); break;
1.1 root 10181: case 0x03: msdos_int_21h_7303h(); break;
10182: // 0x04: set dpb to use for formatting
1.1.1.25 root 10183: // 0x05: extended absolute disk read/write
1.1 root 10184: default:
1.1.1.22 root 10185: 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 10186: REG16(AX) = 0x7300;
1.1.1.3 root 10187: m_CF = 1;
1.1 root 10188: break;
10189: }
10190: break;
10191: default:
1.1.1.22 root 10192: 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 10193: REG16(AX) = 0x01;
1.1.1.3 root 10194: m_CF = 1;
1.1 root 10195: break;
10196: }
1.1.1.3 root 10197: if(m_CF) {
1.1.1.23 root 10198: sda_t *sda = (sda_t *)(mem + SDA_TOP);
10199: sda->extended_error_code = REG16(AX);
10200: switch(sda->extended_error_code) {
10201: case 4: // Too many open files
10202: case 8: // Insufficient memory
10203: sda->error_class = 1; // Out of resource
10204: break;
10205: case 5: // Access denied
10206: sda->error_class = 3; // Authorization
10207: break;
10208: case 7: // Memory control block destroyed
10209: sda->error_class = 4; // Internal
10210: break;
10211: case 2: // File not found
10212: case 3: // Path not found
10213: case 15: // Invaid drive specified
10214: case 18: // No more files
10215: sda->error_class = 8; // Not found
10216: break;
10217: case 32: // Sharing violation
10218: case 33: // Lock violation
10219: sda->error_class = 10; // Locked
10220: break;
10221: // case 16: // Removal of current directory attempted
10222: case 19: // Attempted write on protected disk
10223: case 21: // Drive not ready
10224: // case 29: // Write failure
10225: // case 30: // Read failure
10226: // case 82: // Cannot create subdirectory
10227: sda->error_class = 11; // Media
10228: break;
10229: case 80: // File already exists
10230: sda->error_class = 12; // Already exist
10231: break;
10232: default:
10233: sda->error_class = 13; // Unknown
10234: break;
10235: }
10236: sda->suggested_action = 1; // Retry
10237: sda->locus_of_last_error = 1; // Unknown
1.1 root 10238: }
1.1.1.26! root 10239: if(ctrl_c_checking && ctrl_c_detected) {
! 10240: // raise int 23h
! 10241: #if defined(HAS_I386)
! 10242: m_ext = 0; // not an external interrupt
! 10243: i386_trap(0x23, 1, 0);
! 10244: m_ext = 1;
! 10245: #else
! 10246: PREFIX86(_interrupt)(0x23);
! 10247: #endif
! 10248: }
1.1 root 10249: break;
10250: case 0x22:
10251: fatalerror("int 22h (terminate address)\n");
10252: case 0x23:
10253: msdos_process_terminate(current_psp, (retval & 0xff) | 0x100, 1);
10254: break;
10255: case 0x24:
10256: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
10257: break;
10258: case 0x25:
10259: msdos_int_25h();
10260: break;
10261: case 0x26:
10262: msdos_int_26h();
10263: break;
10264: case 0x27:
10265: msdos_int_27h();
10266: break;
10267: case 0x28:
10268: Sleep(10);
10269: break;
10270: case 0x29:
10271: msdos_int_29h();
10272: break;
10273: case 0x2e:
10274: msdos_int_2eh();
10275: break;
10276: case 0x2f:
10277: // multiplex interrupt
10278: switch(REG8(AH)) {
1.1.1.22 root 10279: case 0x00: break;
10280: case 0x01: msdos_int_2fh_01h(); break;
10281: case 0x05: msdos_int_2fh_05h(); break;
10282: case 0x06: msdos_int_2fh_06h(); break;
10283: case 0x08: msdos_int_2fh_08h(); break;
10284: case 0x10: msdos_int_2fh_10h(); break;
10285: case 0x11: msdos_int_2fh_11h(); break;
1.1.1.21 root 10286: case 0x12: msdos_int_2fh_12h(); break;
1.1.1.22 root 10287: case 0x14: msdos_int_2fh_14h(); break;
10288: case 0x15: msdos_int_2fh_15h(); break;
1.1 root 10289: case 0x16: msdos_int_2fh_16h(); break;
1.1.1.22 root 10290: case 0x19: msdos_int_2fh_19h(); break;
1.1 root 10291: case 0x1a: msdos_int_2fh_1ah(); break;
1.1.1.22 root 10292: case 0x1b: msdos_int_2fh_1bh(); break;
1.1 root 10293: case 0x43: msdos_int_2fh_43h(); break;
1.1.1.22 root 10294: case 0x46: msdos_int_2fh_46h(); break;
10295: case 0x48: msdos_int_2fh_48h(); break;
1.1 root 10296: case 0x4a: msdos_int_2fh_4ah(); break;
1.1.1.22 root 10297: case 0x4b: msdos_int_2fh_4bh(); break;
10298: case 0x4c: break; // unknown
10299: case 0x4d: break; // unknown
10300: case 0x4e: break; // unknown
1.1 root 10301: case 0x4f: msdos_int_2fh_4fh(); break;
1.1.1.22 root 10302: case 0x55: msdos_int_2fh_55h(); break;
10303: case 0x58: break; // unknown
10304: case 0x74: break; // unknown
1.1.1.24 root 10305: case 0xad: msdos_int_2fh_adh(); break;
1.1 root 10306: case 0xae: msdos_int_2fh_aeh(); break;
10307: case 0xb7: msdos_int_2fh_b7h(); break;
1.1.1.22 root 10308: case 0xe9: break; // unknown
10309: case 0xfe: break; // norton utilities ???
10310: default:
10311: 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));
10312: break;
1.1 root 10313: }
10314: break;
1.1.1.24 root 10315: case 0x33:
10316: switch(REG8(AH)) {
10317: case 0x00:
10318: // Mouse
10319: switch(REG8(AL)) {
10320: case 0x00: msdos_int_33h_0000h(); break;
10321: case 0x01: msdos_int_33h_0001h(); break;
10322: case 0x02: msdos_int_33h_0002h(); break;
10323: case 0x03: msdos_int_33h_0003h(); break;
10324: case 0x04: break; // position mouse cursor
10325: case 0x05: msdos_int_33h_0005h(); break;
10326: case 0x06: msdos_int_33h_0006h(); break;
10327: case 0x07: msdos_int_33h_0007h(); break;
10328: case 0x08: msdos_int_33h_0008h(); break;
10329: case 0x09: msdos_int_33h_0009h(); break;
10330: case 0x0a: break; // define text cursor
10331: case 0x0b: msdos_int_33h_000bh(); break;
10332: case 0x0c: msdos_int_33h_000ch(); break;
10333: case 0x0d: break; // light pen emulation on
10334: case 0x0e: break; // light pen emulation off
10335: case 0x0f: msdos_int_33h_000fh(); break;
10336: case 0x10: break; // define screen region for updating
10337: case 0x11: msdos_int_33h_0011h(); break;
10338: case 0x12: REG16(AX) = 0xffff; break; // set large graphics cursor block
10339: case 0x13: break; // define double-speed threshold
10340: case 0x14: msdos_int_33h_0014h(); break;
10341: case 0x15: msdos_int_33h_0015h(); break;
10342: case 0x16: msdos_int_33h_0016h(); break;
10343: case 0x17: msdos_int_33h_0017h(); break;
10344: case 0x1a: msdos_int_33h_001ah(); break;
10345: case 0x1b: msdos_int_33h_001bh(); break;
10346: case 0x1d: msdos_int_33h_001dh(); break;
10347: case 0x1e: msdos_int_33h_001eh(); break;
10348: case 0x21: msdos_int_33h_0021h(); break;
10349: case 0x22: msdos_int_33h_0022h(); break;
10350: case 0x23: msdos_int_33h_0023h(); break;
10351: case 0x24: msdos_int_33h_0024h(); break;
10352: case 0x26: msdos_int_33h_0026h(); break;
10353: case 0x2a: msdos_int_33h_002ah(); break;
10354: case 0x2f: break; // mouse hardware reset
10355: case 0x31: msdos_int_33h_0031h(); break;
10356: case 0x32: msdos_int_33h_0032h(); break;
10357: default:
10358: 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));
10359: break;
10360: }
10361: break;
10362: default:
10363: 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));
10364: break;
10365: }
10366: break;
1.1.1.19 root 10367: case 0x68:
10368: // dummy interrupt for EMS (int 67h)
10369: switch(REG8(AH)) {
10370: case 0x40: msdos_int_67h_40h(); break;
10371: case 0x41: msdos_int_67h_41h(); break;
10372: case 0x42: msdos_int_67h_42h(); break;
10373: case 0x43: msdos_int_67h_43h(); break;
10374: case 0x44: msdos_int_67h_44h(); break;
10375: case 0x45: msdos_int_67h_45h(); break;
10376: case 0x46: msdos_int_67h_46h(); break;
10377: case 0x47: msdos_int_67h_47h(); break;
10378: case 0x48: msdos_int_67h_48h(); break;
1.1.1.20 root 10379: // 0x49: LIM EMS - Reserved - Get I/O Port Address (Undocumented in EMS 3.2)
10380: // 0x4a: LIM EMS - Reserved - Get Translation Array (Undocumented in EMS 3.2)
1.1.1.19 root 10381: case 0x4b: msdos_int_67h_4bh(); break;
10382: case 0x4c: msdos_int_67h_4ch(); break;
10383: case 0x4d: msdos_int_67h_4dh(); break;
1.1.1.20 root 10384: case 0x4e: msdos_int_67h_4eh(); break;
1.1.1.21 root 10385: case 0x4f: msdos_int_67h_4fh(); break;
1.1.1.20 root 10386: case 0x50: msdos_int_67h_50h(); break;
1.1.1.19 root 10387: case 0x51: msdos_int_67h_51h(); break;
1.1.1.20 root 10388: case 0x52: msdos_int_67h_52h(); break;
1.1.1.19 root 10389: case 0x53: msdos_int_67h_53h(); break;
10390: case 0x54: msdos_int_67h_54h(); break;
1.1.1.20 root 10391: // 0x55: LIM EMS 4.0 - Alter Page Map And JUMP
10392: // 0x56: LIM EMS 4.0 - Alter Page Map And CALL
10393: case 0x57: msdos_int_67h_57h(); break;
10394: case 0x58: msdos_int_67h_58h(); break;
10395: // 0x59: LIM EMS 4.0 - Get Expanded Memory Hardware Information (for DOS Kernel)
10396: case 0x5a: msdos_int_67h_5ah(); break;
10397: // 0x5b: LIM EMS 4.0 - Alternate Map Register Set (for DOS Kernel)
10398: // 0x5c: LIM EMS 4.0 - Prepate Expanded Memory Hardware For Warm Boot
10399: // 0x5d: LIM EMS 4.0 - Enable/Disable OS Function Set Functions (for DOS Kernel)
1.1.1.19 root 10400: default:
1.1.1.22 root 10401: 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 10402: REG8(AH) = 0x84;
10403: break;
10404: }
10405: break;
10406: #ifdef SUPPORT_XMS
10407: case 0x69:
10408: // dummy interrupt for XMS (call far)
10409: switch(REG8(AH)) {
10410: case 0x00: msdos_call_xms_00h(); break;
10411: case 0x01: msdos_call_xms_01h(); break;
10412: case 0x02: msdos_call_xms_02h(); break;
10413: case 0x03: msdos_call_xms_03h(); break;
10414: case 0x04: msdos_call_xms_04h(); break;
10415: case 0x05: msdos_call_xms_05h(); break;
10416: case 0x06: msdos_call_xms_06h(); break;
10417: case 0x07: msdos_call_xms_07h(); break;
10418: case 0x08: msdos_call_xms_08h(); break;
10419: case 0x09: msdos_call_xms_09h(); break;
10420: case 0x0a: msdos_call_xms_0ah(); break;
10421: case 0x0b: msdos_call_xms_0bh(); break;
10422: case 0x0c: msdos_call_xms_0ch(); break;
10423: case 0x0d: msdos_call_xms_0dh(); break;
10424: case 0x0e: msdos_call_xms_0eh(); break;
10425: case 0x0f: msdos_call_xms_0fh(); break;
10426: case 0x10: msdos_call_xms_10h(); break;
10427: case 0x11: msdos_call_xms_11h(); break;
10428: case 0x12: msdos_call_xms_12h(); break;
10429: // 0x88: XMS 3.0 - Query free extended memory
10430: // 0x89: XMS 3.0 - Allocate any extended memory
10431: // 0x8e: XMS 3.0 - Get extended EMB handle information
10432: // 0x8f: XMS 3.0 - Reallocate any extended memory block
10433: default:
1.1.1.22 root 10434: 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 10435: REG16(AX) = 0x0000;
10436: REG8(BL) = 0x80;
10437: break;
10438: }
10439: break;
10440: #endif
10441: case 0x6a:
1.1.1.24 root 10442: // irq12 (mouse)
10443: mouse_push_ax = REG16(AX);
10444: mouse_push_bx = REG16(BX);
10445: mouse_push_cx = REG16(CX);
10446: mouse_push_dx = REG16(DX);
10447: mouse_push_si = REG16(SI);
10448: mouse_push_di = REG16(DI);
10449:
10450: if(mouse.active && mouse.call_addr.dw != 0) {
10451: REG16(AX) = mouse.status_irq;
10452: REG16(BX) = mouse.get_buttons();
10453: REG16(CX) = max(mouse.min_position.x, min(mouse.max_position.x, mouse.position.x));
10454: REG16(DX) = max(mouse.min_position.y, min(mouse.max_position.y, mouse.position.y));
10455: REG16(SI) = REG16(CX) * mouse.mickey.x / 8;
10456: REG16(DI) = REG16(DX) * mouse.mickey.y / 8;
10457:
10458: mem[0xfffd0 + 0x02] = 0x9a; // call far
10459: mem[0xfffd0 + 0x03] = mouse.call_addr.w.l & 0xff;
10460: mem[0xfffd0 + 0x04] = mouse.call_addr.w.l >> 8;
10461: mem[0xfffd0 + 0x05] = mouse.call_addr.w.h & 0xff;
10462: mem[0xfffd0 + 0x06] = mouse.call_addr.w.h >> 8;
10463: } else {
10464: mem[0xfffd0 + 0x02] = 0x90; // nop
10465: mem[0xfffd0 + 0x03] = 0x90; // nop
10466: mem[0xfffd0 + 0x04] = 0x90; // nop
10467: mem[0xfffd0 + 0x05] = 0x90; // nop
10468: mem[0xfffd0 + 0x06] = 0x90; // nop
10469: }
10470: break;
10471: case 0x6b:
10472: // end of irq12 (mouse)
10473: REG16(AX) = mouse_push_ax;
10474: REG16(BX) = mouse_push_bx;
10475: REG16(CX) = mouse_push_cx;
10476: REG16(DX) = mouse_push_dx;
10477: REG16(SI) = mouse_push_si;
10478: REG16(DI) = mouse_push_di;
10479:
10480: // EOI
10481: if((pic[1].isr &= ~(1 << 4)) == 0) {
10482: pic[0].isr &= ~(1 << 2); // master
10483: }
10484: pic_update();
10485: break;
10486: case 0x6c:
1.1.1.19 root 10487: // dummy interrupt for case map routine pointed in the country info
10488: if(REG8(AL) >= 0x80) {
10489: char tmp[2] = {0};
10490: tmp[0] = REG8(AL);
10491: my_strupr(tmp);
10492: REG8(AL) = tmp[0];
10493: }
10494: break;
1.1.1.8 root 10495: case 0x70:
10496: case 0x71:
10497: case 0x72:
10498: case 0x73:
10499: case 0x74:
10500: case 0x75:
10501: case 0x76:
10502: case 0x77:
10503: // EOI
10504: if((pic[1].isr &= ~(1 << (num - 0x70))) == 0) {
10505: pic[0].isr &= ~(1 << 2); // master
10506: }
10507: pic_update();
10508: break;
1.1 root 10509: default:
1.1.1.22 root 10510: // 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 10511: break;
10512: }
10513:
10514: // update cursor position
10515: if(cursor_moved) {
10516: CONSOLE_SCREEN_BUFFER_INFO csbi;
1.1.1.23 root 10517: GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
1.1.1.15 root 10518: if(!restore_console_on_exit) {
10519: scr_top = csbi.srWindow.Top;
10520: }
1.1 root 10521: mem[0x450 + mem[0x462] * 2] = csbi.dwCursorPosition.X;
1.1.1.14 root 10522: mem[0x451 + mem[0x462] * 2] = csbi.dwCursorPosition.Y - scr_top;
1.1 root 10523: cursor_moved = false;
10524: }
10525: }
10526:
10527: // init
10528:
10529: int msdos_init(int argc, char *argv[], char *envp[], int standard_env)
10530: {
10531: // init file handler
10532: memset(file_handler, 0, sizeof(file_handler));
10533: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
10534: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
10535: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
1.1.1.21 root 10536: #ifdef MAP_AUX_DEVICE_TO_FILE
1.1 root 10537: if(_open("stdaux.txt", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
1.1.1.21 root 10538: #else
10539: if(_open("NUL", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
10540: #endif
10541: msdos_file_handler_open(3, "STDAUX", 0, 2, 0x80c0, 0);
1.1 root 10542: }
1.1.1.21 root 10543: #ifdef MAP_PRN_DEVICE_TO_FILE
1.1 root 10544: if(_open("stdprn.txt", _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 4) {
1.1.1.21 root 10545: #else
10546: if(_open("NUL", _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 4) {
1.1 root 10547: #endif
1.1.1.21 root 10548: msdos_file_handler_open(4, "STDPRN", 0, 1, 0xa8c0, 0);
10549: }
1.1 root 10550: _dup2(0, DUP_STDIN);
10551: _dup2(1, DUP_STDOUT);
10552: _dup2(2, DUP_STDERR);
1.1.1.21 root 10553: _dup2(3, DUP_STDAUX);
10554: _dup2(4, DUP_STDPRN);
1.1 root 10555:
1.1.1.24 root 10556: // init mouse
10557: memset(&mouse, 0, sizeof(mouse));
10558: mouse.max_position.x = 8 * scr_width - 1;
10559: mouse.max_position.y = 8 * scr_height - 1;
10560: mouse.mickey.x = 8;
10561: mouse.mickey.y = 16;
10562:
1.1.1.26! root 10563: #ifdef SUPPORT_XMS
! 10564: // init xms
! 10565: msdos_xms_init();
! 10566: #endif
! 10567:
1.1 root 10568: // init process
10569: memset(process, 0, sizeof(process));
10570:
1.1.1.13 root 10571: // init dtainfo
10572: msdos_dta_info_init();
10573:
1.1 root 10574: // init memory
10575: memset(mem, 0, sizeof(mem));
10576:
10577: // bios data area
1.1.1.23 root 10578: HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1 root 10579: CONSOLE_SCREEN_BUFFER_INFO csbi;
10580: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 10581: CONSOLE_FONT_INFO cfi;
10582: GetCurrentConsoleFont(hStdout, FALSE, &cfi);
10583:
10584: int regen = min(scr_width * scr_height * 2, 0x8000);
10585: text_vram_top_address = TEXT_VRAM_TOP;
10586: text_vram_end_address = text_vram_top_address + regen;
10587: shadow_buffer_top_address = SHADOW_BUF_TOP;
10588: shadow_buffer_end_address = shadow_buffer_top_address + regen;
10589:
10590: if(regen > 0x4000) {
10591: regen = 0x8000;
10592: vram_pages = 1;
10593: } else if(regen > 0x2000) {
10594: regen = 0x4000;
10595: vram_pages = 2;
10596: } else if(regen > 0x1000) {
10597: regen = 0x2000;
10598: vram_pages = 4;
10599: } else {
10600: regen = 0x1000;
10601: vram_pages = 8;
10602: }
1.1 root 10603:
1.1.1.25 root 10604: *(UINT16 *)(mem + 0x400) = 0x3f8; // com1 port address
10605: *(UINT16 *)(mem + 0x402) = 0x2f8; // com2 port address
10606: // *(UINT16 *)(mem + 0x404) = 0x3e8; // com3 port address
10607: // *(UINT16 *)(mem + 0x406) = 0x2e8; // com4 port address
10608: *(UINT16 *)(mem + 0x408) = 0x378; // lpt1 port address
1.1.1.26! root 10609: // *(UINT16 *)(mem + 0x40a) = 0x278; // lpt2 port address
1.1.1.25 root 10610: // *(UINT16 *)(mem + 0x40c) = 0x3bc; // lpt3 port address
10611: *(UINT16 *)(mem + 0x40e) = EXT_BIOS_TOP >> 4;
1.1.1.26! root 10612: *(UINT16 *)(mem + 0x410) = msdos_get_equipment();
1.1 root 10613: *(UINT16 *)(mem + 0x413) = MEMORY_END / 1024;
10614: *(UINT8 *)(mem + 0x449) = 0x03;//0x73;
1.1.1.14 root 10615: *(UINT16 *)(mem + 0x44a) = csbi.dwSize.X;
10616: *(UINT16 *)(mem + 0x44c) = regen;
1.1 root 10617: *(UINT16 *)(mem + 0x44e) = 0;
10618: *(UINT8 *)(mem + 0x450) = csbi.dwCursorPosition.X;
1.1.1.14 root 10619: *(UINT8 *)(mem + 0x451) = csbi.dwCursorPosition.Y - scr_top;
1.1 root 10620: *(UINT8 *)(mem + 0x460) = 7;
10621: *(UINT8 *)(mem + 0x461) = 7;
10622: *(UINT8 *)(mem + 0x462) = 0;
10623: *(UINT16 *)(mem + 0x463) = 0x3d4;
1.1.1.19 root 10624: *(UINT8 *)(mem + 0x465) = 0x09;
10625: *(UINT32 *)(mem + 0x46c) = get_ticks_since_midnight(timeGetTime());
1.1.1.14 root 10626: *(UINT8 *)(mem + 0x484) = csbi.srWindow.Bottom - csbi.srWindow.Top;
10627: *(UINT8 *)(mem + 0x485) = cfi.dwFontSize.Y;
10628: *(UINT8 *)(mem + 0x487) = 0x60;
10629: *(UINT8 *)(mem + 0x496) = 0x10; // enhanced keyboard installed
1.1.1.25 root 10630: *(UINT16 *)(mem + EXT_BIOS_TOP) = 1;
1.1.1.14 root 10631:
10632: // initial screen
10633: SMALL_RECT rect;
10634: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
10635: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
10636: for(int y = 0, ofs1 = TEXT_VRAM_TOP, ofs2 = SHADOW_BUF_TOP; y < scr_height; y++) {
10637: for(int x = 0; x < scr_width; x++) {
10638: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Char.AsciiChar;
10639: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Attributes;
10640: }
10641: }
1.1 root 10642:
1.1.1.19 root 10643: // init mcb
1.1 root 10644: int seg = MEMORY_TOP >> 4;
1.1.1.19 root 10645:
10646: // iret table
10647: // note: int 2eh vector should address the routine in command.com,
10648: // and some softwares invite (int 2eh vector segment) - 1 must address the mcb of command.com.
10649: // so move iret table into allocated memory block
10650: // http://www5c.biglobe.ne.jp/~ecb/assembler2/2_6.html
10651: msdos_mcb_create(seg++, 'M', -1, IRET_SIZE >> 4);
10652: IRET_TOP = seg << 4;
10653: seg += IRET_SIZE >> 4;
1.1.1.25 root 10654: memset(mem + IRET_TOP, 0xcf, IRET_SIZE); // iret
1.1.1.19 root 10655:
10656: // dummy xms/ems device
10657: msdos_mcb_create(seg++, 'M', -1, XMS_SIZE >> 4);
10658: XMS_TOP = seg << 4;
10659: seg += XMS_SIZE >> 4;
10660:
10661: // environment
1.1 root 10662: msdos_mcb_create(seg++, 'M', -1, ENV_SIZE >> 4);
10663: int env_seg = seg;
10664: int ofs = 0;
1.1.1.24 root 10665: char env_path[8192] = "", *path, temp_path[MAX_PATH] = {0};
1.1 root 10666:
10667: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1.1.14 root 10668: if(_strnicmp(*p, "MSDOS_PATH=", 11) == 0) {
10669: sprintf(env_path, "%s;", *p + 11);
10670: break;
10671: }
10672: }
10673: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1.1.9 root 10674: if(_strnicmp(*p, "PATH=", 5) == 0) {
1.1.1.14 root 10675: strcat(env_path, *p + 5);
1.1.1.9 root 10676: break;
10677: }
10678: }
1.1.1.18 root 10679: if((path = getenv("MSDOS_COMSPEC")) != NULL ||
10680: (path = msdos_search_command_com(argv[0], env_path)) != NULL) {
1.1.1.15 root 10681: strcpy(comspec_path, path);
10682: }
1.1.1.24 root 10683: if((path = getenv("MSDOS_TEMP")) != NULL) {
10684: if(GetShortPathName(path, temp_path, MAX_PATH) == 0) {
10685: strcpy(temp_path, path);
10686: }
10687: }
1.1.1.15 root 10688:
1.1.1.9 root 10689: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1 root 10690: // lower to upper
10691: char tmp[ENV_SIZE], name[ENV_SIZE], value[ENV_SIZE];
10692: int value_pos = 0;
10693: strcpy(tmp, *p);
10694: for(int i = 0;; i++) {
10695: if(tmp[i] == '=') {
10696: tmp[i] = '\0';
10697: sprintf(name, ";%s;", tmp);
1.1.1.25 root 10698: my_strupr(name);
1.1 root 10699: strcpy(value, tmp + (value_pos = i + 1));
10700: tmp[i] = '=';
10701: break;
10702: } else if(tmp[i] >= 'a' && tmp[i] <= 'z') {
10703: tmp[i] = tmp[i] - 'a' + 'A';
10704: }
10705: }
1.1.1.18 root 10706: if(strncmp(tmp, "MSDOS_COMSPEC=", 14) == 0) {
10707: // ignore MSDOS_COMSPEC
1.1.1.24 root 10708: } else if(strncmp(tmp, "MSDOS_TEMP=", 11) == 0) {
10709: // ignore MSDOS_TEMP
1.1.1.18 root 10710: } else if(standard_env && strstr(";COMSPEC;INCLUDE;LIB;PATH;PROMPT;TEMP;TMP;TZ;", name) == NULL) {
10711: // ignore non standard environments
10712: } else {
1.1 root 10713: if(strncmp(tmp, "COMSPEC=", 8) == 0) {
1.1.1.14 root 10714: strcpy(tmp, "COMSPEC=C:\\COMMAND.COM");
1.1.1.24 root 10715: } else if(strncmp(tmp, "TEMP=", 5) == 0 && temp_path[0] != '\0') {
10716: sprintf(tmp, "TEMP=%s", temp_path);
10717: } else if(strncmp(tmp, "TMP=", 4) == 0 && temp_path[0] != '\0') {
10718: sprintf(tmp, "TMP=%s", temp_path);
1.1 root 10719: } else if(strncmp(tmp, "PATH=", 5) == 0 || strncmp(tmp, "TEMP=", 5) == 0 || strncmp(tmp, "TMP=", 4) == 0) {
10720: tmp[value_pos] = '\0';
10721: char *token = my_strtok(value, ";");
10722: while(token != NULL) {
10723: if(strlen(token) != 0) {
1.1.1.24 root 10724: char *path = msdos_remove_double_quote(token), short_path[MAX_PATH];
1.1.1.8 root 10725: if(strlen(path) != 0) {
1.1.1.24 root 10726: if(GetShortPathName(path, short_path, MAX_PATH) == 0) {
10727: strcat(tmp, path);
10728: } else {
10729: strcat(tmp, short_path);
10730: }
1.1.1.8 root 10731: strcat(tmp, ";");
1.1 root 10732: }
10733: }
10734: token = my_strtok(NULL, ";");
10735: }
10736: tmp[strlen(tmp) - 1] = '\0';
10737: my_strupr(tmp);
10738: }
10739: int len = strlen(tmp);
1.1.1.14 root 10740: if(ofs + len + 1 + (2 + (8 + 1 + 3)) + 2 > ENV_SIZE) {
1.1 root 10741: fatalerror("too many environments\n");
10742: }
10743: memcpy(mem + (seg << 4) + ofs, tmp, len);
10744: ofs += len + 1;
10745: }
10746: }
10747: seg += (ENV_SIZE >> 4);
10748:
10749: // psp
10750: msdos_mcb_create(seg++, 'M', -1, PSP_SIZE >> 4);
10751: current_psp = seg;
1.1.1.14 root 10752: msdos_psp_create(seg, seg + (PSP_SIZE >> 4), -1, env_seg);
1.1 root 10753: seg += (PSP_SIZE >> 4);
10754:
1.1.1.19 root 10755: // first free mcb in conventional memory
10756: msdos_mcb_create(seg, 'Z', 0, (MEMORY_END >> 4) - seg - 2);
1.1.1.8 root 10757: first_mcb = seg;
10758:
1.1.1.19 root 10759: // dummy mcb to link to umb
10760: msdos_mcb_create((MEMORY_END >> 4) - 1, 'M', -1, (UMB_TOP >> 4) - (MEMORY_END >> 4));
10761:
10762: // first free mcb in upper memory block
1.1.1.8 root 10763: msdos_mcb_create(UMB_TOP >> 4, 'Z', 0, (UMB_END >> 4) - (UMB_TOP >> 4) - 1);
1.1 root 10764:
1.1.1.19 root 10765: #ifdef SUPPORT_XMS
10766: // first free mcb in extended memory block
10767: msdos_mcb_create(EMB_TOP >> 4, 'Z', 0, (EMB_END >> 4) - (EMB_TOP >> 4) - 1);
10768: #endif
10769:
1.1.1.26! root 10770: // interrupt vector
! 10771: for(int i = 0; i < 0x80; i++) {
! 10772: *(UINT16 *)(mem + 4 * i + 0) = i;
! 10773: *(UINT16 *)(mem + 4 * i + 2) = (IRET_TOP >> 4);
! 10774: }
! 10775: *(UINT16 *)(mem + 4 * 0x08 + 0) = 0x0010; // fffd:0010 irq0 (system timer)
! 10776: *(UINT16 *)(mem + 4 * 0x08 + 2) = 0xfffd;
! 10777: *(UINT16 *)(mem + 4 * 0x22 + 0) = 0x0000; // ffff:0000 boot
! 10778: *(UINT16 *)(mem + 4 * 0x22 + 2) = 0xffff;
! 10779: *(UINT16 *)(mem + 4 * 0x67 + 0) = 0x0012; // xxxx:0012 ems
! 10780: *(UINT16 *)(mem + 4 * 0x67 + 2) = XMS_TOP >> 4;
! 10781: *(UINT16 *)(mem + 4 * 0x74 + 0) = 0x0000; // fffd:0000 irq12 (mouse)
! 10782: *(UINT16 *)(mem + 4 * 0x74 + 2) = 0xfffd;
! 10783:
! 10784: // dummy devices (CON -> ... -> CONFIG$ -> NUL -> EMMXXXX0)
! 10785: static const struct {
! 10786: UINT16 attributes;
! 10787: char *dev_name;
! 10788: } dummy_devices[] = {
! 10789: {0x8013, "CON "},
! 10790: {0x8000, "AUX "},
! 10791: {0xa0c0, "PRN "},
! 10792: {0x8008, "CLOCK$ "},
! 10793: {0x8000, "COM1 "},
! 10794: {0xa0c0, "LPT1 "},
! 10795: {0xa0c0, "LPT2 "},
! 10796: {0xa0c0, "LPT3 "},
! 10797: {0x8000, "COM2 "},
! 10798: {0x8000, "COM3 "},
! 10799: {0x8000, "COM4 "},
! 10800: {0xc000, "CONFIG$ "},
! 10801: };
! 10802: static const UINT8 dummy_device_routine[] = {
! 10803: // from NUL device of Windows 98 SE
! 10804: // or word ptr ES:[BX+03],0100
! 10805: 0x26, 0x81, 0x4f, 0x03, 0x00, 0x01,
! 10806: // retf
! 10807: 0xcb,
! 10808: };
! 10809: for(int i = 0; i < 12; i++) {
! 10810: device_t *device = (device_t *)(mem + DEVICE_TOP + 22 + 18 * i);
! 10811: if(i == 11) {
! 10812: device->next_driver.w.l = offsetof(dos_info_t, nul_device);
! 10813: device->next_driver.w.h = DOS_INFO_TOP >> 4;
! 10814: } else {
! 10815: device->next_driver.w.l = 22 + 18 * (i + 1);
! 10816: device->next_driver.w.h = DEVICE_TOP >> 4;
! 10817: }
! 10818: device->attributes = dummy_devices[i].attributes;
! 10819: device->strategy = 22 + 18 * 12;
! 10820: device->interrupt = 22 + 18 * 12 + 6;
! 10821: memcpy(device->dev_name, dummy_devices[i].dev_name, 8);
! 10822: }
! 10823: memcpy(mem + DEVICE_TOP + 22 + 18 * 12, dummy_device_routine, sizeof(dummy_device_routine));
! 10824:
1.1.1.25 root 10825: // dos info
10826: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
10827: dos_info->magic_word = 1;
10828: dos_info->first_mcb = MEMORY_TOP >> 4;
10829: dos_info->first_dpb.w.l = 0;
10830: dos_info->first_dpb.w.h = DPB_TOP >> 4;
10831: dos_info->first_sft.w.l = 0;
10832: dos_info->first_sft.w.h = SFT_TOP >> 4;
1.1.1.26! root 10833: dos_info->clock_device.w.l = 22 + 18 * 3; // CLOCK$ is the 3rd device in IO.SYS
1.1.1.25 root 10834: dos_info->clock_device.w.h = DEVICE_TOP >> 4;
1.1.1.26! root 10835: dos_info->con_device.w.l = 22 + 18 * 0; // CON is the 1st device in IO.SYS
1.1.1.25 root 10836: dos_info->con_device.w.h = DEVICE_TOP >> 4;
10837: dos_info->max_sector_len = 512;
10838: dos_info->disk_buf_info.w.l = offsetof(dos_info_t, disk_buf_heads);
10839: dos_info->disk_buf_info.w.h = DOS_INFO_TOP >> 4;
10840: dos_info->cds.w.l = 0;
10841: dos_info->cds.w.h = CDS_TOP >> 4;
10842: dos_info->fcb_table.w.l = 0;
10843: dos_info->fcb_table.w.h = FCB_TABLE_TOP >> 4;
10844: dos_info->last_drive = 'Z' - 'A' + 1;
10845: dos_info->buffers_x = 20;
10846: dos_info->buffers_y = 0;
10847: dos_info->boot_drive = 'C' - 'A' + 1;
10848: dos_info->nul_device.next_driver.w.l = 0;
10849: dos_info->nul_device.next_driver.w.h = XMS_TOP >> 4;
10850: dos_info->nul_device.attributes = 0x8004;
1.1.1.26! root 10851: dos_info->nul_device.strategy = offsetof(dos_info_t, nul_device_routine);
! 10852: dos_info->nul_device.interrupt = offsetof(dos_info_t, nul_device_routine) + 6;
1.1.1.25 root 10853: memcpy(dos_info->nul_device.dev_name, "NUL ", 8);
10854: dos_info->disk_buf_heads.w.l = 0;
10855: dos_info->disk_buf_heads.w.h = DISK_BUF_TOP >> 4;
10856: dos_info->first_umb_fcb = UMB_TOP >> 4;
10857: dos_info->first_mcb_2 = MEMORY_TOP >> 4;
1.1.1.26! root 10858: memcpy(dos_info->nul_device_routine, dummy_device_routine, sizeof(dummy_device_routine));
1.1.1.25 root 10859:
10860: char *env;
10861: if((env = getenv("LASTDRIVE")) != NULL) {
10862: if(env[0] >= 'A' && env[0] <= 'Z') {
10863: dos_info->last_drive = env[0] - 'A' + 1;
10864: } else if(env[0] >= 'a' && env[0] <= 'z') {
10865: dos_info->last_drive = env[0] - 'a' + 1;
10866: }
10867: }
10868: if((env = getenv("windir")) != NULL) {
10869: if(env[0] >= 'A' && env[0] <= 'Z') {
10870: dos_info->boot_drive = env[0] - 'A' + 1;
10871: } else if(env[0] >= 'a' && env[0] <= 'z') {
10872: dos_info->boot_drive = env[0] - 'a' + 1;
10873: }
10874: }
10875: #if defined(HAS_I386)
10876: dos_info->i386_or_later = 1;
10877: #else
10878: dos_info->i386_or_later = 0;
10879: #endif
10880: dos_info->ext_mem_size = (min(MAX_MEM, 0x4000000) - 0x100000) >> 10;
10881:
1.1.1.19 root 10882: // ems (int 67h) and xms (call far)
1.1.1.25 root 10883: device_t *xms_device = (device_t *)(mem + XMS_TOP);
10884: xms_device->next_driver.w.l = 0xffff;
10885: xms_device->next_driver.w.h = 0xffff;
10886: xms_device->attributes = 0xc000;
1.1.1.26! root 10887: xms_device->strategy = 0x18;
! 10888: xms_device->interrupt = 0x18 + 6;
1.1.1.25 root 10889: memcpy(xms_device->dev_name, "EMMXXXX0", 8);
10890:
1.1.1.26! root 10891: mem[XMS_TOP + 0x12] = 0xcd; // int 68h (dummy)
! 10892: mem[XMS_TOP + 0x13] = 0x68;
! 10893: mem[XMS_TOP + 0x14] = 0xcf; // iret
1.1.1.19 root 10894: #ifdef SUPPORT_XMS
10895: if(support_xms) {
1.1.1.26! root 10896: mem[XMS_TOP + 0x15] = 0xcd; // int 69h (dummy)
! 10897: mem[XMS_TOP + 0x16] = 0x69;
! 10898: mem[XMS_TOP + 0x17] = 0xcb; // retf
1.1.1.19 root 10899: } else
10900: #endif
1.1.1.26! root 10901: mem[XMS_TOP + 0x15] = 0xcb; // retf
! 10902: memcpy(mem + XMS_TOP + 0x18, dummy_device_routine, sizeof(dummy_device_routine));
1.1.1.19 root 10903:
1.1.1.26! root 10904: // irq12 routine (mouse)
1.1.1.24 root 10905: mem[0xfffd0 + 0x00] = 0xcd; // int 6ah (dummy)
10906: mem[0xfffd0 + 0x01] = 0x6a;
10907: mem[0xfffd0 + 0x02] = 0x9a; // call far mouse
10908: mem[0xfffd0 + 0x03] = 0xff;
10909: mem[0xfffd0 + 0x04] = 0xff;
10910: mem[0xfffd0 + 0x05] = 0xff;
10911: mem[0xfffd0 + 0x06] = 0xff;
10912: mem[0xfffd0 + 0x07] = 0xcd; // int 6bh (dummy)
10913: mem[0xfffd0 + 0x08] = 0x6b;
10914: mem[0xfffd0 + 0x09] = 0xcf; // iret
10915:
1.1.1.19 root 10916: // case map routine (call far)
1.1.1.24 root 10917: mem[0xfffd0 + 0x0c] = 0xcd; // int 6ch (dummy)
10918: mem[0xfffd0 + 0x0d] = 0x6b;
10919: mem[0xfffd0 + 0x0e] = 0xcb; // retf
1.1.1.19 root 10920:
1.1.1.26! root 10921: // irq0 routine (system time)
1.1.1.24 root 10922: mem[0xfffd0 + 0x10] = 0xcd; // int 1ch
10923: mem[0xfffd0 + 0x11] = 0x1c;
10924: mem[0xfffd0 + 0x12] = 0xea; // jmp far (IRET_TOP >> 4):0008
10925: mem[0xfffd0 + 0x13] = 0x08;
10926: mem[0xfffd0 + 0x14] = 0x00;
10927: mem[0xfffd0 + 0x15] = ((IRET_TOP >> 4) ) & 0xff;
10928: mem[0xfffd0 + 0x16] = ((IRET_TOP >> 4) >> 8) & 0xff;
1.1.1.14 root 10929:
1.1.1.26! root 10930: // boot routine
1.1 root 10931: mem[0xffff0] = 0xf4; // halt
10932: mem[0xffff1] = 0xcd; // int 21h
10933: mem[0xffff2] = 0x21;
10934: mem[0xffff3] = 0xcb; // retf
10935:
1.1.1.24 root 10936: mem[0xffff5] = '0'; // rom date
10937: mem[0xffff6] = '2';
10938: mem[0xffff7] = '/';
10939: mem[0xffff8] = '2';
10940: mem[0xffff9] = '2';
10941: mem[0xffffa] = '/';
10942: mem[0xffffb] = '0';
10943: mem[0xffffc] = '6';
10944: mem[0xffffe] = 0xfc; // machine id
10945: mem[0xfffff] = 0x00;
10946:
1.1 root 10947: // param block
10948: // + 0: param block (22bytes)
10949: // +24: fcb1/2 (20bytes)
10950: // +44: command tail (128bytes)
10951: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
10952: param->env_seg = 0;
10953: param->cmd_line.w.l = 44;
10954: param->cmd_line.w.h = (WORK_TOP >> 4);
10955: param->fcb1.w.l = 24;
10956: param->fcb1.w.h = (WORK_TOP >> 4);
10957: param->fcb2.w.l = 24;
10958: param->fcb2.w.h = (WORK_TOP >> 4);
10959:
10960: memset(mem + WORK_TOP + 24, 0x20, 20);
10961:
10962: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
10963: if(argc > 1) {
10964: sprintf(cmd_line->cmd, " %s", argv[1]);
10965: for(int i = 2; i < argc; i++) {
10966: char tmp[128];
10967: sprintf(tmp, "%s %s", cmd_line->cmd, argv[i]);
10968: strcpy(cmd_line->cmd, tmp);
10969: }
10970: cmd_line->len = (UINT8)strlen(cmd_line->cmd);
10971: } else {
10972: cmd_line->len = 0;
10973: }
10974: cmd_line->cmd[cmd_line->len] = 0x0d;
10975:
10976: // system file table
1.1.1.21 root 10977: *(UINT32 *)(mem + SFT_TOP + 0) = 0xffffffff;
10978: *(UINT16 *)(mem + SFT_TOP + 4) = 20;
1.1 root 10979:
1.1.1.19 root 10980: // disk buffer header (from DOSBox)
10981: *(UINT16 *)(mem + DISK_BUF_TOP + 0) = 0xffff; // forward ptr
10982: *(UINT16 *)(mem + DISK_BUF_TOP + 2) = 0xffff; // backward ptr
10983: *(UINT8 *)(mem + DISK_BUF_TOP + 4) = 0xff; // not in use
10984: *(UINT8 *)(mem + DISK_BUF_TOP + 10) = 0x01; // number of FATs
10985: *(UINT32 *)(mem + DISK_BUF_TOP + 13) = 0xffffffff; // pointer to DPB
10986:
1.1 root 10987: // current directory structure
10988: msdos_cds_update(_getdrive() - 1);
10989:
10990: // fcb table
10991: *(UINT32 *)(mem + FCB_TABLE_TOP + 0) = 0xffffffff;
1.1.1.14 root 10992: *(UINT16 *)(mem + FCB_TABLE_TOP + 4) = 0;
1.1 root 10993:
1.1.1.22 root 10994: // error table
10995: *(UINT8 *)(mem + ERR_TABLE_TOP + 0) = 0xff;
10996: *(UINT8 *)(mem + ERR_TABLE_TOP + 1) = 0x04;
10997: *(UINT8 *)(mem + ERR_TABLE_TOP + 2) = 0x00;
10998: *(UINT8 *)(mem + ERR_TABLE_TOP + 3) = 0x00;
10999:
1.1.1.17 root 11000: // nls stuff
11001: msdos_nls_tables_init();
1.1 root 11002:
11003: // execute command
11004: if(msdos_process_exec(argv[0], param, 0)) {
11005: fatalerror("'%s' not found\n", argv[0]);
11006: }
11007: retval = 0;
11008: return(0);
11009: }
11010:
11011: #define remove_std_file(path) { \
11012: int fd = _open(path, _O_RDONLY | _O_BINARY); \
11013: if(fd != -1) { \
11014: _lseek(fd, 0, SEEK_END); \
11015: int size = _tell(fd); \
11016: _close(fd); \
11017: if(size == 0) { \
11018: remove(path); \
11019: } \
11020: } \
11021: }
11022:
11023: void msdos_finish()
11024: {
11025: for(int i = 0; i < MAX_FILES; i++) {
11026: if(file_handler[i].valid) {
11027: _close(i);
11028: }
11029: }
1.1.1.21 root 11030: #ifdef MAP_AUX_DEVICE_TO_FILE
1.1 root 11031: remove_std_file("stdaux.txt");
1.1.1.21 root 11032: #endif
11033: #ifdef MAP_PRN_DEVICE_TO_FILE
1.1 root 11034: remove_std_file("stdprn.txt");
11035: #endif
11036: msdos_dbcs_table_finish();
11037: }
11038:
11039: /* ----------------------------------------------------------------------------
11040: PC/AT hardware emulation
11041: ---------------------------------------------------------------------------- */
11042:
11043: void hardware_init()
11044: {
1.1.1.3 root 11045: CPU_INIT_CALL(CPU_MODEL);
1.1 root 11046: CPU_RESET_CALL(CPU_MODEL);
1.1.1.14 root 11047: m_IF = 1;
1.1.1.3 root 11048: #if defined(HAS_I386)
1.1 root 11049: cpu_type = (REG32(EDX) >> 8) & 0x0f;
11050: cpu_step = (REG32(EDX) >> 0) & 0x0f;
1.1.1.3 root 11051: #endif
11052: i386_set_a20_line(0);
1.1.1.14 root 11053:
1.1.1.19 root 11054: ems_init();
1.1.1.25 root 11055: dma_init();
1.1 root 11056: pic_init();
1.1.1.25 root 11057: pio_init();
1.1.1.8 root 11058: #ifdef PIT_ALWAYS_RUNNING
11059: pit_init();
11060: #else
1.1 root 11061: pit_active = 0;
11062: #endif
1.1.1.25 root 11063: sio_init();
1.1.1.8 root 11064: cmos_init();
11065: kbd_init();
1.1 root 11066: }
11067:
1.1.1.10 root 11068: void hardware_finish()
11069: {
11070: #if defined(HAS_I386)
11071: vtlb_free(m_vtlb);
11072: #endif
1.1.1.19 root 11073: ems_finish();
1.1.1.25 root 11074: sio_finish();
1.1.1.10 root 11075: }
11076:
1.1 root 11077: void hardware_run()
11078: {
11079: int ops = 0;
11080:
1.1.1.22 root 11081: #ifdef EXPORT_DEBUG_TO_FILE
11082: fdebug = fopen("debug.log", "w");
11083: #endif
1.1.1.3 root 11084: while(!m_halted) {
1.1.1.22 root 11085: #ifdef ENABLE_DEBUG_DASM
11086: if(dasm > 0) {
1.1 root 11087: char buffer[256];
1.1.1.3 root 11088: #if defined(HAS_I386)
1.1.1.22 root 11089: UINT32 flags = get_flags();
1.1.1.19 root 11090: UINT32 eip = m_eip;
1.1.1.3 root 11091: #else
1.1.1.22 root 11092: UINT32 flags = CompressFlags();
1.1.1.19 root 11093: UINT32 eip = m_pc - SREG_BASE(CS);
1.1.1.3 root 11094: #endif
11095: UINT8 *oprom = mem + SREG_BASE(CS) + eip;
1.1 root 11096:
1.1.1.3 root 11097: #if defined(HAS_I386)
11098: if(m_operand_size) {
1.1 root 11099: CPU_DISASSEMBLE_CALL(x86_32);
1.1.1.3 root 11100: } else
11101: #endif
11102: CPU_DISASSEMBLE_CALL(x86_16);
1.1.1.22 root 11103:
11104: 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",
11105: 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,
11106: #if defined(HAS_I386)
11107: PROTECTED_MODE ? "PE" : "--",
11108: #else
11109: "--",
11110: #endif
11111: (flags & 0x40000) ? 'A' : '-',
11112: (flags & 0x20000) ? 'V' : '-',
11113: (flags & 0x10000) ? 'R' : '-',
11114: (flags & 0x04000) ? 'N' : '-',
11115: (flags & 0x02000) ? '1' : '0',
11116: (flags & 0x01000) ? '1' : '0',
11117: (flags & 0x00800) ? 'O' : '-',
11118: (flags & 0x00400) ? 'D' : '-',
11119: (flags & 0x00200) ? 'I' : '-',
11120: (flags & 0x00100) ? 'T' : '-',
11121: (flags & 0x00080) ? 'S' : '-',
11122: (flags & 0x00040) ? 'Z' : '-',
11123: (flags & 0x00010) ? 'A' : '-',
11124: (flags & 0x00004) ? 'P' : '-',
11125: (flags & 0x00001) ? 'C' : '-');
11126: fprintf(fdebug, "%04X:%04X\t%s\n", SREG(CS), (unsigned)eip, buffer);
11127: dasm--;
1.1 root 11128: }
11129: #endif
1.1.1.3 root 11130: #if defined(HAS_I386)
11131: m_cycles = 1;
1.1 root 11132: CPU_EXECUTE_CALL(i386);
1.1.1.3 root 11133: #else
11134: CPU_EXECUTE_CALL(CPU_MODEL);
11135: #endif
1.1.1.14 root 11136: #if defined(HAS_I386)
11137: if(m_eip != m_prev_eip) {
11138: #else
11139: if(m_pc != m_prevpc) {
11140: #endif
11141: iops++;
11142: }
1.1.1.8 root 11143: if(++ops == 16384) {
1.1 root 11144: hardware_update();
11145: ops = 0;
11146: }
11147: }
1.1.1.22 root 11148: #ifdef EXPORT_DEBUG_TO_FILE
11149: fclose(fdebug);
11150: #endif
1.1 root 11151: }
11152:
11153: void hardware_update()
11154: {
1.1.1.8 root 11155: static UINT32 prev_time = 0;
11156: UINT32 cur_time = timeGetTime();
11157:
11158: if(prev_time != cur_time) {
11159: // update pit and raise irq0
11160: #ifndef PIT_ALWAYS_RUNNING
11161: if(pit_active)
11162: #endif
11163: {
11164: if(pit_run(0, cur_time)) {
11165: pic_req(0, 0, 1);
11166: }
11167: pit_run(1, cur_time);
11168: pit_run(2, cur_time);
11169: }
1.1.1.24 root 11170:
1.1.1.25 root 11171: // update sio and raise irq4/3
11172: for(int c = 0; c < 2; c++) {
11173: sio_update(c);
11174: }
11175:
1.1.1.24 root 11176: // update keyboard and mouse
1.1.1.14 root 11177: static UINT32 prev_tick = 0;
11178: UINT32 cur_tick = cur_time / 32;
1.1.1.25 root 11179:
1.1.1.14 root 11180: if(prev_tick != cur_tick) {
11181: // update keyboard flags
11182: UINT8 state;
1.1.1.24 root 11183: state = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
11184: state |= (GetAsyncKeyState(VK_CAPITAL ) & 0x0001) ? 0x40 : 0;
11185: state |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x0001) ? 0x20 : 0;
11186: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
11187: state |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
11188: state |= (GetAsyncKeyState(VK_CONTROL ) & 0x8000) ? 0x04 : 0;
11189: state |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
11190: state |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
1.1.1.14 root 11191: mem[0x417] = state;
11192: state = (GetAsyncKeyState(VK_INSERT ) & 0x8000) ? 0x80 : 0;
11193: state |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
11194: state |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
11195: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
1.1.1.24 root 11196: // state |= (GetAsyncKeyState(VK_PAUSE ) & 0x0001) ? 0x08 : 0;
11197: // state |= (GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x04 : 0;
1.1.1.14 root 11198: state |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
11199: state |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
11200: mem[0x418] = state;
11201:
1.1.1.24 root 11202: // update console input if needed
11203: if(!key_changed || mouse.active) {
11204: update_console_input();
11205: }
11206:
11207: // raise irq1 if key is pressed/released
11208: if(key_changed) {
1.1.1.8 root 11209: pic_req(0, 1, 1);
1.1.1.24 root 11210: key_changed = false;
11211: }
11212:
11213: // raise irq12 if mouse status is changed
11214: if(mouse.status & mouse.call_mask) {
11215: if(mouse.active) {
11216: pic_req(1, 4, 1);
11217: mouse.status_irq = mouse.status & mouse.call_mask;
11218: }
11219: mouse.status &= ~mouse.call_mask;
1.1.1.8 root 11220: }
1.1.1.24 root 11221:
1.1.1.14 root 11222: prev_tick = cur_tick;
1.1.1.8 root 11223: }
1.1.1.24 root 11224:
1.1.1.19 root 11225: // update daily timer counter
11226: pcbios_update_daily_timer_counter(cur_time);
1.1.1.25 root 11227:
1.1.1.8 root 11228: prev_time = cur_time;
1.1 root 11229: }
11230: }
11231:
1.1.1.19 root 11232: // ems
11233:
11234: void ems_init()
11235: {
11236: memset(ems_handles, 0, sizeof(ems_handles));
11237: memset(ems_pages, 0, sizeof(ems_pages));
11238: free_ems_pages = MAX_EMS_PAGES;
11239: }
11240:
11241: void ems_finish()
11242: {
11243: for(int i = 0; i < MAX_EMS_HANDLES; i++) {
11244: if(ems_handles[i].buffer) {
11245: free(ems_handles[i].buffer);
11246: ems_handles[i].buffer = NULL;
11247: }
11248: }
11249: }
11250:
11251: void ems_allocate_pages(int handle, int pages)
11252: {
11253: if(pages > 0) {
11254: ems_handles[handle].buffer = (UINT8 *)calloc(1, 0x4000 * pages);
11255: } else {
11256: ems_handles[handle].buffer = NULL;
11257: }
11258: ems_handles[handle].pages = pages;
11259: ems_handles[handle].allocated = true;
11260: free_ems_pages -= pages;
11261: }
11262:
11263: void ems_reallocate_pages(int handle, int pages)
11264: {
11265: if(ems_handles[handle].allocated) {
11266: if(ems_handles[handle].pages != pages) {
11267: UINT8 *new_buffer = NULL;
11268:
11269: if(pages > 0) {
11270: new_buffer = (UINT8 *)calloc(1, 0x4000 * pages);
11271: }
11272: if(ems_handles[handle].buffer) {
11273: if(new_buffer) {
11274: if(pages > ems_handles[handle].pages) {
11275: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * ems_handles[handle].pages);
11276: } else {
11277: memcpy(new_buffer, ems_handles[handle].buffer, 0x4000 * pages);
11278: }
11279: }
11280: free(ems_handles[handle].buffer);
11281: ems_handles[handle].buffer = NULL;
11282: }
11283: free_ems_pages += ems_handles[handle].pages;
11284:
11285: ems_handles[handle].buffer = new_buffer;
11286: ems_handles[handle].pages = pages;
11287: free_ems_pages -= pages;
11288: }
11289: } else {
11290: ems_allocate_pages(handle, pages);
11291: }
11292: }
11293:
11294: void ems_release_pages(int handle)
11295: {
11296: if(ems_handles[handle].allocated) {
11297: if(ems_handles[handle].buffer) {
11298: free(ems_handles[handle].buffer);
11299: ems_handles[handle].buffer = NULL;
11300: }
11301: free_ems_pages += ems_handles[handle].pages;
11302: ems_handles[handle].allocated = false;
11303: }
11304: }
11305:
11306: void ems_map_page(int physical, int handle, int logical)
11307: {
11308: if(ems_pages[physical].mapped) {
11309: if(ems_pages[physical].handle == handle && ems_pages[physical].page == logical) {
11310: return;
11311: }
11312: ems_unmap_page(physical);
11313: }
11314: if(ems_handles[handle].allocated && ems_handles[handle].buffer && logical < ems_handles[handle].pages) {
11315: memcpy(mem + EMS_TOP + 0x4000 * physical, ems_handles[handle].buffer + 0x4000 * logical, 0x4000);
11316: }
11317: ems_pages[physical].handle = handle;
11318: ems_pages[physical].page = logical;
11319: ems_pages[physical].mapped = true;
11320: }
11321:
11322: void ems_unmap_page(int physical)
11323: {
11324: if(ems_pages[physical].mapped) {
11325: int handle = ems_pages[physical].handle;
11326: int logical = ems_pages[physical].page;
11327:
11328: if(ems_handles[handle].allocated && ems_handles[handle].buffer && logical < ems_handles[handle].pages) {
11329: memcpy(ems_handles[handle].buffer + 0x4000 * logical, mem + EMS_TOP + 0x4000 * physical, 0x4000);
11330: }
11331: ems_pages[physical].mapped = false;
11332: }
11333: }
11334:
1.1.1.25 root 11335: // dma
1.1 root 11336:
1.1.1.25 root 11337: void dma_init()
1.1 root 11338: {
1.1.1.26! root 11339: memset(dma, 0, sizeof(dma));
1.1.1.25 root 11340: for(int c = 0; c < 2; c++) {
1.1.1.26! root 11341: // for(int ch = 0; ch < 4; ch++) {
! 11342: // dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w = 0xffff;
! 11343: // }
1.1.1.25 root 11344: dma_reset(c);
11345: }
1.1 root 11346: }
11347:
1.1.1.25 root 11348: void dma_reset(int c)
1.1 root 11349: {
1.1.1.25 root 11350: dma[c].low_high = false;
11351: dma[c].cmd = dma[c].req = dma[c].tc = 0;
11352: dma[c].mask = 0xff;
11353: }
11354:
11355: void dma_write(int c, UINT32 addr, UINT8 data)
11356: {
11357: int ch = (addr >> 1) & 3;
11358: UINT8 bit = 1 << (data & 3);
11359:
11360: switch(addr & 0x0f) {
11361: case 0x00: case 0x02: case 0x04: case 0x06:
11362: if(dma[c].low_high) {
11363: dma[c].ch[ch].bareg.b.h = data;
1.1 root 11364: } else {
1.1.1.25 root 11365: dma[c].ch[ch].bareg.b.l = data;
11366: }
11367: dma[c].ch[ch].areg.w = dma[c].ch[ch].bareg.w;
11368: dma[c].low_high = !dma[c].low_high;
11369: break;
11370: case 0x01: case 0x03: case 0x05: case 0x07:
11371: if(dma[c].low_high) {
11372: dma[c].ch[ch].bcreg.b.h = data;
11373: } else {
11374: dma[c].ch[ch].bcreg.b.l = data;
11375: }
11376: dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w;
11377: dma[c].low_high = !dma[c].low_high;
11378: break;
11379: case 0x08:
11380: // command register
11381: dma[c].cmd = data;
11382: break;
11383: case 0x09:
11384: // dma[c].request register
11385: if(data & 4) {
11386: if(!(dma[c].req & bit)) {
11387: dma[c].req |= bit;
11388: // dma_run(c, ch);
11389: }
11390: } else {
11391: dma[c].req &= ~bit;
11392: }
11393: break;
11394: case 0x0a:
11395: // single mask register
11396: if(data & 4) {
11397: dma[c].mask |= bit;
11398: } else {
11399: dma[c].mask &= ~bit;
11400: }
11401: break;
11402: case 0x0b:
11403: // mode register
11404: dma[c].ch[data & 3].mode = data;
11405: break;
11406: case 0x0c:
11407: dma[c].low_high = false;
11408: break;
11409: case 0x0d:
11410: // clear master
11411: dma_reset(c);
11412: break;
11413: case 0x0e:
11414: // clear mask register
11415: dma[c].mask = 0;
11416: break;
11417: case 0x0f:
11418: // all mask register
11419: dma[c].mask = data & 0x0f;
11420: break;
11421: }
11422: }
11423:
11424: UINT8 dma_read(int c, UINT32 addr)
11425: {
11426: int ch = (addr >> 1) & 3;
11427: UINT8 val = 0xff;
11428:
11429: switch(addr & 0x0f) {
11430: case 0x00: case 0x02: case 0x04: case 0x06:
11431: if(dma[c].low_high) {
11432: val = dma[c].ch[ch].areg.b.h;
11433: } else {
11434: val = dma[c].ch[ch].areg.b.l;
11435: }
11436: dma[c].low_high = !dma[c].low_high;
11437: return(val);
11438: case 0x01: case 0x03: case 0x05: case 0x07:
11439: if(dma[c].low_high) {
11440: val = dma[c].ch[ch].creg.b.h;
11441: } else {
11442: val = dma[c].ch[ch].creg.b.l;
11443: }
11444: dma[c].low_high = !dma[c].low_high;
11445: return(val);
11446: case 0x08:
11447: // status register
11448: val = (dma[c].req << 4) | dma[c].tc;
11449: dma[c].tc = 0;
11450: return(val);
11451: case 0x0d:
1.1.1.26! root 11452: // temporary register (intel 82374 does not support)
1.1.1.25 root 11453: return(dma[c].tmp & 0xff);
1.1.1.26! root 11454: case 0x0f:
! 11455: // mask register (intel 82374 does support)
! 11456: return(dma[c].mask);
1.1.1.25 root 11457: }
11458: return(0xff);
11459: }
11460:
11461: void dma_page_write(int c, int ch, UINT8 data)
11462: {
11463: dma[c].ch[ch].pagereg = data;
11464: }
11465:
11466: UINT8 dma_page_read(int c, int ch)
11467: {
11468: return(dma[c].ch[ch].pagereg);
11469: }
11470:
11471: void dma_run(int c, int ch)
11472: {
11473: UINT8 bit = 1 << ch;
11474:
11475: if((dma[c].req & bit) && !(dma[c].mask & bit)) {
11476: // execute dma
11477: while(dma[c].req & bit) {
11478: if(ch == 0 && (dma[c].cmd & 0x01)) {
11479: // memory -> memory
11480: UINT32 saddr = dma[c].ch[0].areg.w | (dma[c].ch[0].pagereg << 16);
11481: UINT32 daddr = dma[c].ch[1].areg.w | (dma[c].ch[1].pagereg << 16);
11482:
11483: if(c == 0) {
11484: dma[c].tmp = read_byte(saddr);
11485: write_byte(daddr, dma[c].tmp);
11486: } else {
11487: dma[c].tmp = read_word(saddr << 1);
11488: write_word(daddr << 1, dma[c].tmp);
11489: }
11490: if(!(dma[c].cmd & 0x02)) {
11491: if(dma[c].ch[0].mode & 0x20) {
11492: dma[c].ch[0].areg.w--;
11493: if(dma[c].ch[0].areg.w == 0xffff) {
11494: dma[c].ch[0].pagereg--;
11495: }
11496: } else {
11497: dma[c].ch[0].areg.w++;
11498: if(dma[c].ch[0].areg.w == 0) {
11499: dma[c].ch[0].pagereg++;
11500: }
11501: }
11502: }
11503: if(dma[c].ch[1].mode & 0x20) {
11504: dma[c].ch[1].areg.w--;
11505: if(dma[c].ch[1].areg.w == 0xffff) {
11506: dma[c].ch[1].pagereg--;
11507: }
11508: } else {
11509: dma[c].ch[1].areg.w++;
11510: if(dma[c].ch[1].areg.w == 0) {
11511: dma[c].ch[1].pagereg++;
11512: }
11513: }
11514:
11515: // check dma condition
11516: if(dma[c].ch[0].creg.w-- == 0) {
11517: if(dma[c].ch[0].mode & 0x10) {
11518: // self initialize
11519: dma[c].ch[0].areg.w = dma[c].ch[0].bareg.w;
11520: dma[c].ch[0].creg.w = dma[c].ch[0].bcreg.w;
11521: } else {
11522: // dma[c].mask |= bit;
11523: }
11524: }
11525: if(dma[c].ch[1].creg.w-- == 0) {
11526: // terminal count
11527: if(dma[c].ch[1].mode & 0x10) {
11528: // self initialize
11529: dma[c].ch[1].areg.w = dma[c].ch[1].bareg.w;
11530: dma[c].ch[1].creg.w = dma[c].ch[1].bcreg.w;
11531: } else {
11532: dma[c].mask |= bit;
11533: }
11534: dma[c].req &= ~bit;
11535: dma[c].tc |= bit;
11536: }
11537: } else {
11538: UINT32 addr = dma[c].ch[ch].areg.w | (dma[c].ch[ch].pagereg << 16);
11539:
11540: if((dma[c].ch[ch].mode & 0x0c) == 0x00) {
11541: // verify
11542: } else if((dma[c].ch[ch].mode & 0x0c) == 0x04) {
11543: // io -> memory
11544: if(c == 0) {
11545: dma[c].tmp = read_io_byte(dma[c].ch[ch].port);
11546: write_byte(addr, dma[c].tmp);
11547: } else {
11548: dma[c].tmp = read_io_word(dma[c].ch[ch].port);
11549: write_word(addr << 1, dma[c].tmp);
11550: }
11551: } else if((dma[c].ch[ch].mode & 0x0c) == 0x08) {
11552: // memory -> io
11553: if(c == 0) {
11554: dma[c].tmp = read_byte(addr);
11555: write_io_byte(dma[c].ch[ch].port, dma[c].tmp);
11556: } else {
11557: dma[c].tmp = read_word(addr << 1);
11558: write_io_word(dma[c].ch[ch].port, dma[c].tmp);
11559: }
11560: }
11561: if(dma[c].ch[ch].mode & 0x20) {
11562: dma[c].ch[ch].areg.w--;
11563: if(dma[c].ch[ch].areg.w == 0xffff) {
11564: dma[c].ch[ch].pagereg--;
11565: }
11566: } else {
11567: dma[c].ch[ch].areg.w++;
11568: if(dma[c].ch[ch].areg.w == 0) {
11569: dma[c].ch[ch].pagereg++;
11570: }
11571: }
11572:
11573: // check dma condition
11574: if(dma[c].ch[ch].creg.w-- == 0) {
11575: // terminal count
11576: if(dma[c].ch[ch].mode & 0x10) {
11577: // self initialize
11578: dma[c].ch[ch].areg.w = dma[c].ch[ch].bareg.w;
11579: dma[c].ch[ch].creg.w = dma[c].ch[ch].bcreg.w;
11580: } else {
11581: dma[c].mask |= bit;
11582: }
11583: dma[c].req &= ~bit;
11584: dma[c].tc |= bit;
11585: } else if((dma[c].ch[ch].mode & 0xc0) == 0x40) {
11586: // single mode
11587: break;
11588: }
11589: }
11590: }
11591: }
11592: }
11593:
11594: // pic
11595:
11596: void pic_init()
11597: {
11598: memset(pic, 0, sizeof(pic));
11599: pic[0].imr = pic[1].imr = 0xff;
11600:
11601: // from bochs bios
11602: pic_write(0, 0, 0x11); // icw1 = 11h
11603: pic_write(0, 1, 0x08); // icw2 = 08h
11604: pic_write(0, 1, 0x04); // icw3 = 04h
11605: pic_write(0, 1, 0x01); // icw4 = 01h
11606: pic_write(0, 1, 0xb8); // ocw1 = b8h
11607: pic_write(1, 0, 0x11); // icw1 = 11h
11608: pic_write(1, 1, 0x70); // icw2 = 70h
11609: pic_write(1, 1, 0x02); // icw3 = 02h
11610: pic_write(1, 1, 0x01); // icw4 = 01h
11611: }
11612:
11613: void pic_write(int c, UINT32 addr, UINT8 data)
11614: {
11615: if(addr & 1) {
11616: if(pic[c].icw2_r) {
11617: // icw2
11618: pic[c].icw2 = data;
11619: pic[c].icw2_r = 0;
11620: } else if(pic[c].icw3_r) {
11621: // icw3
11622: pic[c].icw3 = data;
11623: pic[c].icw3_r = 0;
11624: } else if(pic[c].icw4_r) {
11625: // icw4
11626: pic[c].icw4 = data;
11627: pic[c].icw4_r = 0;
11628: } else {
11629: // ocw1
1.1 root 11630: pic[c].imr = data;
11631: }
11632: } else {
11633: if(data & 0x10) {
11634: // icw1
11635: pic[c].icw1 = data;
11636: pic[c].icw2_r = 1;
11637: pic[c].icw3_r = (data & 2) ? 0 : 1;
11638: pic[c].icw4_r = data & 1;
11639: pic[c].irr = 0;
11640: pic[c].isr = 0;
11641: pic[c].imr = 0;
11642: pic[c].prio = 0;
11643: if(!(pic[c].icw1 & 1)) {
11644: pic[c].icw4 = 0;
11645: }
11646: pic[c].ocw3 = 0;
11647: } else if(data & 8) {
11648: // ocw3
11649: if(!(data & 2)) {
11650: data = (data & ~1) | (pic[c].ocw3 & 1);
11651: }
11652: if(!(data & 0x40)) {
11653: data = (data & ~0x20) | (pic[c].ocw3 & 0x20);
11654: }
11655: pic[c].ocw3 = data;
11656: } else {
11657: // ocw2
11658: int level = 0;
11659: if(data & 0x40) {
11660: level = data & 7;
11661: } else {
11662: if(!pic[c].isr) {
11663: return;
11664: }
11665: level = pic[c].prio;
11666: while(!(pic[c].isr & (1 << level))) {
11667: level = (level + 1) & 7;
11668: }
11669: }
11670: if(data & 0x80) {
11671: pic[c].prio = (level + 1) & 7;
11672: }
11673: if(data & 0x20) {
11674: pic[c].isr &= ~(1 << level);
11675: }
11676: }
11677: }
11678: pic_update();
11679: }
11680:
11681: UINT8 pic_read(int c, UINT32 addr)
11682: {
11683: if(addr & 1) {
11684: return(pic[c].imr);
11685: } else {
11686: // polling mode is not supported...
11687: //if(pic[c].ocw3 & 4) {
11688: // return ???;
11689: //}
11690: if(pic[c].ocw3 & 1) {
11691: return(pic[c].isr);
11692: } else {
11693: return(pic[c].irr);
11694: }
11695: }
11696: }
11697:
11698: void pic_req(int c, int level, int signal)
11699: {
11700: if(signal) {
11701: pic[c].irr |= (1 << level);
11702: } else {
11703: pic[c].irr &= ~(1 << level);
11704: }
11705: pic_update();
11706: }
11707:
11708: int pic_ack()
11709: {
11710: // ack (INTA=L)
11711: pic[pic_req_chip].isr |= pic_req_bit;
11712: pic[pic_req_chip].irr &= ~pic_req_bit;
11713: if(pic_req_chip > 0) {
11714: // update isr and irr of master
11715: UINT8 slave = 1 << (pic[pic_req_chip].icw3 & 7);
11716: pic[pic_req_chip - 1].isr |= slave;
11717: pic[pic_req_chip - 1].irr &= ~slave;
11718: }
11719: //if(pic[pic_req_chip].icw4 & 1) {
11720: // 8086 mode
11721: int vector = (pic[pic_req_chip].icw2 & 0xf8) | pic_req_level;
11722: //} else {
11723: // // 8080 mode
11724: // UINT16 addr = (UINT16)pic[pic_req_chip].icw2 << 8;
11725: // if(pic[pic_req_chip].icw1 & 4) {
11726: // addr |= (pic[pic_req_chip].icw1 & 0xe0) | (pic_req_level << 2);
11727: // } else {
11728: // addr |= (pic[pic_req_chip].icw1 & 0xc0) | (pic_req_level << 3);
11729: // }
11730: // vector = 0xcd | (addr << 8);
11731: //}
11732: if(pic[pic_req_chip].icw4 & 2) {
11733: // auto eoi
11734: pic[pic_req_chip].isr &= ~pic_req_bit;
11735: }
11736: return(vector);
11737: }
11738:
11739: void pic_update()
11740: {
11741: for(int c = 0; c < 2; c++) {
11742: UINT8 irr = pic[c].irr;
11743: if(c + 1 < 2) {
11744: // this is master
11745: if(pic[c + 1].irr & (~pic[c + 1].imr)) {
11746: // request from slave
11747: irr |= 1 << (pic[c + 1].icw3 & 7);
11748: }
11749: }
11750: irr &= (~pic[c].imr);
11751: if(!irr) {
11752: break;
11753: }
11754: if(!(pic[c].ocw3 & 0x20)) {
11755: irr |= pic[c].isr;
11756: }
11757: int level = pic[c].prio;
11758: UINT8 bit = 1 << level;
11759: while(!(irr & bit)) {
11760: level = (level + 1) & 7;
11761: bit = 1 << level;
11762: }
11763: if((c + 1 < 2) && (pic[c].icw3 & bit)) {
11764: // check slave
11765: continue;
11766: }
11767: if(pic[c].isr & bit) {
11768: break;
11769: }
11770: // interrupt request
11771: pic_req_chip = c;
11772: pic_req_level = level;
11773: pic_req_bit = bit;
1.1.1.3 root 11774: i386_set_irq_line(INPUT_LINE_IRQ, HOLD_LINE);
1.1 root 11775: return;
11776: }
1.1.1.3 root 11777: i386_set_irq_line(INPUT_LINE_IRQ, CLEAR_LINE);
1.1.1.2 root 11778: }
1.1 root 11779:
1.1.1.25 root 11780: // pio
11781:
11782: void pio_init()
11783: {
1.1.1.26! root 11784: memset(pio, 0, sizeof(pio));
1.1.1.25 root 11785: for(int c = 0; c < 2; c++) {
11786: pio[c].stat = 0xde;
11787: pio[c].ctrl = 0x0c;
11788: }
11789: }
11790:
11791: void pio_write(int c, UINT32 addr, UINT8 data)
11792: {
11793: switch(addr & 3) {
11794: case 0:
11795: pio[c].data = data;
11796: break;
11797: case 2:
11798: pio[c].ctrl = data;
11799: break;
11800: }
11801: }
11802:
11803: UINT8 pio_read(int c, UINT32 addr)
11804: {
11805: switch(addr & 3) {
11806: case 0:
11807: return(pio[c].data);
11808: case 1:
11809: return(pio[c].stat);
11810: case 2:
11811: return(pio[c].ctrl);
11812: }
11813: return(0xff);
11814: }
11815:
1.1 root 11816: // pit
11817:
1.1.1.22 root 11818: #define PIT_FREQ 1193182ULL
1.1 root 11819: #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)
11820:
11821: void pit_init()
11822: {
1.1.1.8 root 11823: memset(pit, 0, sizeof(pit));
1.1 root 11824: for(int ch = 0; ch < 3; ch++) {
11825: pit[ch].count = 0x10000;
11826: pit[ch].ctrl_reg = 0x34;
11827: pit[ch].mode = 3;
11828: }
11829:
11830: // from bochs bios
11831: pit_write(3, 0x34);
11832: pit_write(0, 0x00);
11833: pit_write(0, 0x00);
11834: }
11835:
11836: void pit_write(int ch, UINT8 val)
11837: {
1.1.1.8 root 11838: #ifndef PIT_ALWAYS_RUNNING
1.1 root 11839: if(!pit_active) {
11840: pit_active = 1;
11841: pit_init();
11842: }
1.1.1.8 root 11843: #endif
1.1 root 11844: switch(ch) {
11845: case 0:
11846: case 1:
11847: case 2:
11848: // write count register
11849: if(!pit[ch].low_write && !pit[ch].high_write) {
11850: if(pit[ch].ctrl_reg & 0x10) {
11851: pit[ch].low_write = 1;
11852: }
11853: if(pit[ch].ctrl_reg & 0x20) {
11854: pit[ch].high_write = 1;
11855: }
11856: }
11857: if(pit[ch].low_write) {
11858: pit[ch].count_reg = val;
11859: pit[ch].low_write = 0;
11860: } else if(pit[ch].high_write) {
11861: if((pit[ch].ctrl_reg & 0x30) == 0x20) {
11862: pit[ch].count_reg = val << 8;
11863: } else {
11864: pit[ch].count_reg |= val << 8;
11865: }
11866: pit[ch].high_write = 0;
11867: }
11868: // start count
1.1.1.8 root 11869: if(!pit[ch].low_write && !pit[ch].high_write) {
11870: if(pit[ch].mode == 0 || pit[ch].mode == 4 || pit[ch].prev_time == 0) {
11871: pit[ch].count = PIT_COUNT_VALUE(ch);
11872: pit[ch].prev_time = timeGetTime();
11873: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 11874: }
11875: }
11876: break;
11877: case 3: // ctrl reg
11878: if((val & 0xc0) == 0xc0) {
11879: // i8254 read-back command
11880: for(ch = 0; ch < 3; ch++) {
11881: if(!(val & 0x10) && !pit[ch].status_latched) {
11882: pit[ch].status = pit[ch].ctrl_reg & 0x3f;
11883: pit[ch].status_latched = 1;
11884: }
11885: if(!(val & 0x20) && !pit[ch].count_latched) {
11886: pit_latch_count(ch);
11887: }
11888: }
11889: break;
11890: }
11891: ch = (val >> 6) & 3;
11892: if(val & 0x30) {
11893: static int modes[8] = {0, 1, 2, 3, 4, 5, 2, 3};
11894: pit[ch].mode = modes[(val >> 1) & 7];
11895: pit[ch].count_latched = 0;
11896: pit[ch].low_read = pit[ch].high_read = 0;
11897: pit[ch].low_write = pit[ch].high_write = 0;
11898: pit[ch].ctrl_reg = val;
11899: // stop count
1.1.1.8 root 11900: pit[ch].prev_time = pit[ch].expired_time = 0;
1.1 root 11901: pit[ch].count_reg = 0;
11902: } else if(!pit[ch].count_latched) {
11903: pit_latch_count(ch);
11904: }
11905: break;
11906: }
11907: }
11908:
11909: UINT8 pit_read(int ch)
11910: {
1.1.1.8 root 11911: #ifndef PIT_ALWAYS_RUNNING
1.1 root 11912: if(!pit_active) {
11913: pit_active = 1;
11914: pit_init();
11915: }
1.1.1.8 root 11916: #endif
1.1 root 11917: switch(ch) {
11918: case 0:
11919: case 1:
11920: case 2:
11921: if(pit[ch].status_latched) {
11922: pit[ch].status_latched = 0;
11923: return(pit[ch].status);
11924: }
11925: // if not latched, through current count
11926: if(!pit[ch].count_latched) {
11927: if(!pit[ch].low_read && !pit[ch].high_read) {
11928: pit_latch_count(ch);
11929: }
11930: }
11931: // return latched count
11932: if(pit[ch].low_read) {
11933: pit[ch].low_read = 0;
11934: if(!pit[ch].high_read) {
11935: pit[ch].count_latched = 0;
11936: }
11937: return(pit[ch].latch & 0xff);
11938: } else if(pit[ch].high_read) {
11939: pit[ch].high_read = 0;
11940: pit[ch].count_latched = 0;
11941: return((pit[ch].latch >> 8) & 0xff);
11942: }
11943: }
11944: return(0xff);
11945: }
11946:
1.1.1.8 root 11947: int pit_run(int ch, UINT32 cur_time)
1.1 root 11948: {
1.1.1.8 root 11949: if(pit[ch].expired_time != 0 && cur_time >= pit[ch].expired_time) {
1.1 root 11950: pit[ch].count = PIT_COUNT_VALUE(ch);
1.1.1.8 root 11951: pit[ch].prev_time = pit[ch].expired_time;
11952: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
11953: if(cur_time >= pit[ch].expired_time) {
11954: pit[ch].prev_time = cur_time;
11955: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 11956: }
1.1.1.8 root 11957: return(1);
1.1 root 11958: }
1.1.1.8 root 11959: return(0);
1.1 root 11960: }
11961:
11962: void pit_latch_count(int ch)
11963: {
1.1.1.8 root 11964: if(pit[ch].expired_time != 0) {
1.1.1.26! root 11965: UINT32 cur_time = timeGetTime();
1.1.1.8 root 11966: pit_run(ch, cur_time);
11967: UINT32 tmp = (pit[ch].count * (pit[ch].expired_time - cur_time)) / (pit[ch].expired_time - pit[ch].prev_time);
1.1.1.26! root 11968: UINT16 latch = (tmp != 0) ? (UINT16)tmp : 1;
! 11969:
! 11970: if(pit[ch].prev_latch == latch && pit[ch].expired_time > cur_time) {
! 11971: // decrement counter in 1msec period
! 11972: if(pit[ch].next_latch == 0) {
! 11973: tmp = (pit[ch].count * (pit[ch].expired_time - cur_time - 1)) / (pit[ch].expired_time - pit[ch].prev_time);
! 11974: pit[ch].next_latch = (tmp != 0) ? (UINT16)tmp : 1;
! 11975: }
! 11976: if(pit[ch].latch > pit[ch].next_latch) {
! 11977: pit[ch].latch--;
! 11978: }
! 11979: } else {
! 11980: pit[ch].prev_latch = pit[ch].latch = latch;
! 11981: pit[ch].next_latch = 0;
! 11982: }
1.1.1.8 root 11983: } else {
11984: pit[ch].latch = (UINT16)pit[ch].count;
1.1.1.26! root 11985: pit[ch].prev_latch = pit[ch].next_latch = 0;
1.1 root 11986: }
11987: pit[ch].count_latched = 1;
11988: if((pit[ch].ctrl_reg & 0x30) == 0x10) {
11989: // lower byte
11990: pit[ch].low_read = 1;
11991: pit[ch].high_read = 0;
11992: } else if((pit[ch].ctrl_reg & 0x30) == 0x20) {
11993: // upper byte
11994: pit[ch].low_read = 0;
11995: pit[ch].high_read = 1;
11996: } else {
11997: // lower -> upper
1.1.1.14 root 11998: pit[ch].low_read = pit[ch].high_read = 1;
1.1 root 11999: }
12000: }
12001:
1.1.1.8 root 12002: int pit_get_expired_time(int ch)
1.1 root 12003: {
1.1.1.22 root 12004: pit[ch].accum += 1024ULL * 1000ULL * (UINT64)pit[ch].count / PIT_FREQ;
12005: UINT64 val = pit[ch].accum >> 10;
12006: pit[ch].accum -= val << 10;
12007: return((val != 0) ? val : 1);
1.1.1.8 root 12008: }
12009:
1.1.1.25 root 12010: // sio
12011:
12012: void sio_init()
12013: {
1.1.1.26! root 12014: memset(sio, 0, sizeof(sio));
! 12015: memset(sio_mt, 0, sizeof(sio_mt));
! 12016:
1.1.1.25 root 12017: for(int c = 0; c < 2; c++) {
12018: sio[c].send_buffer = new FIFO(SIO_BUFFER_SIZE);
12019: sio[c].recv_buffer = new FIFO(SIO_BUFFER_SIZE);
12020:
12021: sio[c].divisor.w = 12; // 115200Hz / 9600Baud
12022: sio[c].line_ctrl = 0x03; // 8bit, stop 1bit, non parity
1.1.1.26! root 12023: sio[c].modem_ctrl = 0x03; // rts=on, dtr=on
! 12024: sio[c].set_rts = sio[c].set_dtr = true;
1.1.1.25 root 12025: sio[c].line_stat_buf = 0x60; // send/recv buffers are empty
12026: sio[c].irq_identify = 0x01; // no pending irq
12027:
12028: InitializeCriticalSection(&sio_mt[c].csSendData);
12029: InitializeCriticalSection(&sio_mt[c].csRecvData);
12030: InitializeCriticalSection(&sio_mt[c].csLineCtrl);
12031: InitializeCriticalSection(&sio_mt[c].csLineStat);
12032: InitializeCriticalSection(&sio_mt[c].csModemCtrl);
12033: InitializeCriticalSection(&sio_mt[c].csModemStat);
12034:
1.1.1.26! root 12035: if(sio_port_number[c] != 0) {
1.1.1.25 root 12036: sio[c].channel = c;
12037: sio_mt[c].hThread = CreateThread(NULL, 0, sio_thread, &sio[c], 0, NULL);
12038: }
12039: }
12040: }
12041:
12042: void sio_finish()
12043: {
12044: for(int c = 0; c < 2; c++) {
12045: if(sio_mt[c].hThread != NULL) {
12046: WaitForSingleObject(sio_mt[c].hThread, INFINITE);
12047: CloseHandle(sio_mt[c].hThread);
12048: }
12049: DeleteCriticalSection(&sio_mt[c].csSendData);
12050: DeleteCriticalSection(&sio_mt[c].csRecvData);
12051: DeleteCriticalSection(&sio_mt[c].csLineCtrl);
12052: DeleteCriticalSection(&sio_mt[c].csLineStat);
12053: DeleteCriticalSection(&sio_mt[c].csModemCtrl);
12054: DeleteCriticalSection(&sio_mt[c].csModemStat);
12055:
12056: sio[c].send_buffer->release();
12057: delete sio[c].send_buffer;
12058: sio[c].recv_buffer->release();
12059: delete sio[c].recv_buffer;
12060: }
12061: }
12062:
12063: void sio_write(int c, UINT32 addr, UINT8 data)
12064: {
12065: switch(addr & 7) {
12066: case 0:
12067: if(sio[c].selector & 0x80) {
12068: if(sio[c].divisor.b.l != data) {
12069: EnterCriticalSection(&sio_mt[c].csLineCtrl);
12070: sio[c].divisor.b.l = data;
12071: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
12072: }
12073: } else {
12074: EnterCriticalSection(&sio_mt[c].csSendData);
12075: sio[c].send_buffer->write(data);
12076: // transmitter holding/shift registers are not empty
12077: sio[c].line_stat_buf &= ~0x60;
12078: LeaveCriticalSection(&sio_mt[c].csSendData);
12079:
12080: if(sio[c].irq_enable & 0x02) {
12081: sio_update_irq(c);
12082: }
12083: }
12084: break;
12085: case 1:
12086: if(sio[c].selector & 0x80) {
12087: if(sio[c].divisor.b.h != data) {
12088: EnterCriticalSection(&sio_mt[c].csLineCtrl);
12089: sio[c].divisor.b.h = data;
12090: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
12091: }
12092: } else {
12093: if(sio[c].irq_enable != data) {
12094: sio[c].irq_enable = data;
12095: sio_update_irq(c);
12096: }
12097: }
12098: break;
12099: case 3:
12100: {
12101: UINT8 line_ctrl = data & 0x3f;
12102: bool set_brk = ((data & 0x40) != 0);
12103:
12104: if(sio[c].line_ctrl != line_ctrl) {
12105: EnterCriticalSection(&sio_mt[c].csLineCtrl);
12106: sio[c].line_ctrl = line_ctrl;
12107: LeaveCriticalSection(&sio_mt[c].csLineCtrl);
12108: }
12109: if(sio[c].set_brk != set_brk) {
12110: EnterCriticalSection(&sio_mt[c].csModemCtrl);
12111: sio[c].set_brk = set_brk;
12112: LeaveCriticalSection(&sio_mt[c].csModemCtrl);
12113: }
12114: }
12115: sio[c].selector = data;
12116: break;
12117: case 4:
12118: {
12119: bool set_dtr = ((data & 0x01) != 0);
12120: bool set_rts = ((data & 0x02) != 0);
12121:
12122: if(sio[c].set_dtr != set_dtr || sio[c].set_rts != set_rts) {
1.1.1.26! root 12123: // EnterCriticalSection(&sio_mt[c].csModemCtrl);
1.1.1.25 root 12124: sio[c].set_dtr = set_dtr;
12125: sio[c].set_rts = set_rts;
1.1.1.26! root 12126: // LeaveCriticalSection(&sio_mt[c].csModemCtrl);
! 12127:
! 12128: bool state_changed = false;
! 12129:
! 12130: EnterCriticalSection(&sio_mt[c].csModemStat);
! 12131: if(set_dtr) {
! 12132: sio[c].modem_stat |= 0x20; // dsr on
! 12133: } else {
! 12134: sio[c].modem_stat &= ~0x20; // dsr off
! 12135: }
! 12136: if(set_rts) {
! 12137: sio[c].modem_stat |= 0x10; // cts on
! 12138: } else {
! 12139: sio[c].modem_stat &= ~0x10; // cts off
! 12140: }
! 12141: if((sio[c].prev_modem_stat & 0x20) != (sio[c].modem_stat & 0x20)) {
! 12142: if(!(sio[c].modem_stat & 0x02)) {
! 12143: if(sio[c].irq_enable & 0x08) {
! 12144: state_changed = true;
! 12145: }
! 12146: sio[c].modem_stat |= 0x02;
! 12147: }
! 12148: }
! 12149: if((sio[c].prev_modem_stat & 0x10) != (sio[c].modem_stat & 0x10)) {
! 12150: if(!(sio[c].modem_stat & 0x01)) {
! 12151: if(sio[c].irq_enable & 0x08) {
! 12152: state_changed = true;
! 12153: }
! 12154: sio[c].modem_stat |= 0x01;
! 12155: }
! 12156: }
! 12157: LeaveCriticalSection(&sio_mt[c].csModemStat);
! 12158:
! 12159: if(state_changed) {
! 12160: sio_update_irq(c);
! 12161: }
1.1.1.25 root 12162: }
12163: }
12164: sio[c].modem_ctrl = data;
12165: break;
12166: case 7:
12167: sio[c].scratch = data;
12168: break;
12169: }
12170: }
12171:
12172: UINT8 sio_read(int c, UINT32 addr)
12173: {
12174: switch(addr & 7) {
12175: case 0:
12176: if(sio[c].selector & 0x80) {
12177: return(sio[c].divisor.b.l);
12178: } else {
12179: EnterCriticalSection(&sio_mt[c].csRecvData);
12180: UINT8 data = sio[c].recv_buffer->read();
12181: // data is not ready
12182: sio[c].line_stat_buf &= ~0x01;
12183: LeaveCriticalSection(&sio_mt[c].csRecvData);
12184:
12185: if(sio[c].irq_enable & 0x01) {
12186: sio_update_irq(c);
12187: }
12188: return(data);
12189: }
12190: case 1:
12191: if(sio[c].selector & 0x80) {
12192: return(sio[c].divisor.b.h);
12193: } else {
12194: return(sio[c].irq_enable);
12195: }
12196: case 2:
12197: return(sio[c].irq_identify);
12198: case 3:
12199: return(sio[c].selector);
12200: case 4:
12201: return(sio[c].modem_ctrl);
12202: case 5:
12203: {
12204: EnterCriticalSection(&sio_mt[c].csLineStat);
12205: UINT8 val = sio[c].line_stat_err | sio[c].line_stat_buf;
12206: sio[c].line_stat_err = 0x00;
12207: LeaveCriticalSection(&sio_mt[c].csLineStat);
12208:
12209: bool state_changed = false;
12210:
12211: if((sio[c].line_stat_buf & 0x60) == 0x00) {
12212: EnterCriticalSection(&sio_mt[c].csSendData);
12213: if(!sio[c].send_buffer->full()) {
12214: // transmitter holding register will be empty first
12215: if(sio[c].irq_enable & 0x02) {
12216: state_changed = true;
12217: }
12218: sio[c].line_stat_buf |= 0x20;
12219: }
12220: LeaveCriticalSection(&sio_mt[c].csSendData);
12221: } else if((sio[c].line_stat_buf & 0x60) == 0x20) {
12222: // transmitter shift register will be empty later
12223: sio[c].line_stat_buf |= 0x40;
12224: }
12225: if(!(sio[c].line_stat_buf & 0x01)) {
12226: EnterCriticalSection(&sio_mt[c].csRecvData);
12227: if(!sio[c].recv_buffer->empty()) {
12228: // data is ready
12229: if(sio[c].irq_enable & 0x01) {
12230: state_changed = true;
12231: }
12232: sio[c].line_stat_buf |= 0x01;
12233: }
12234: LeaveCriticalSection(&sio_mt[c].csRecvData);
12235: }
12236: if(state_changed) {
12237: sio_update_irq(c);
12238: }
12239: return(val);
12240: }
12241: case 6:
12242: {
12243: EnterCriticalSection(&sio_mt[c].csModemStat);
12244: UINT8 val = sio[c].modem_stat;
12245: sio[c].modem_stat &= 0xf0;
12246: sio[c].prev_modem_stat = sio[c].modem_stat;
12247: LeaveCriticalSection(&sio_mt[c].csModemStat);
12248:
12249: if(sio[c].modem_ctrl & 0x10) {
12250: // loop-back
12251: val &= 0x0f;
12252: val |= (sio[c].modem_ctrl & 0x0c) << 4;
12253: val |= (sio[c].modem_ctrl & 0x01) << 5;
12254: val |= (sio[c].modem_ctrl & 0x02) << 3;
12255: }
12256: return(val);
12257: }
12258: case 7:
12259: return(sio[c].scratch);
12260: }
12261: return(0xff);
12262: }
12263:
12264: void sio_update(int c)
12265: {
12266: if((sio[c].line_stat_buf & 0x60) == 0x00) {
12267: EnterCriticalSection(&sio_mt[c].csSendData);
12268: if(!sio[c].send_buffer->full()) {
12269: // transmitter holding/shift registers will be empty
12270: sio[c].line_stat_buf |= 0x60;
12271: }
12272: LeaveCriticalSection(&sio_mt[c].csSendData);
12273: } else if((sio[c].line_stat_buf & 0x60) == 0x20) {
12274: // transmitter shift register will be empty
12275: sio[c].line_stat_buf |= 0x40;
12276: }
12277: if(!(sio[c].line_stat_buf & 0x01)) {
12278: EnterCriticalSection(&sio_mt[c].csRecvData);
12279: if(!sio[c].recv_buffer->empty()) {
12280: // data is ready
12281: sio[c].line_stat_buf |= 0x01;
12282: }
12283: LeaveCriticalSection(&sio_mt[c].csRecvData);
12284: }
12285: sio_update_irq(c);
12286: }
12287:
12288: void sio_update_irq(int c)
12289: {
12290: int level = -1;
12291:
12292: if(sio[c].irq_enable & 0x08) {
12293: EnterCriticalSection(&sio_mt[c].csModemStat);
12294: if((sio[c].modem_stat & 0x0f) != 0) {
12295: level = 0;
12296: }
12297: EnterCriticalSection(&sio_mt[c].csModemStat);
12298: }
12299: if(sio[c].irq_enable & 0x02) {
12300: if(sio[c].line_stat_buf & 0x20) {
12301: level = 1;
12302: }
12303: }
12304: if(sio[c].irq_enable & 0x01) {
12305: if(sio[c].line_stat_buf & 0x01) {
12306: level = 2;
12307: }
12308: }
12309: if(sio[c].irq_enable & 0x04) {
12310: EnterCriticalSection(&sio_mt[c].csLineStat);
12311: if(sio[c].line_stat_err != 0) {
12312: level = 3;
12313: }
12314: LeaveCriticalSection(&sio_mt[c].csLineStat);
12315: }
12316: if(level != -1) {
12317: sio[c].irq_identify = level << 1;
12318: pic_req(0, (c == 0) ? 4 : 3, 1);
12319: } else {
12320: sio[c].irq_identify = 1;
12321: pic_req(0, (c == 0) ? 4 : 3, 0);
12322: }
12323: }
12324:
12325: DWORD WINAPI sio_thread(void *lpx)
12326: {
12327: volatile sio_t *p = (sio_t *)lpx;
12328: sio_mt_t *q = &sio_mt[p->channel];
12329:
12330: char name[] = "COM1";
1.1.1.26! root 12331: name[3] = '0' + sio_port_number[p->channel];
! 12332: HANDLE hComm = NULL;
! 12333: COMMPROP commProp;
! 12334: DCB dcb;
! 12335: DWORD dwSettableBaud = 0xffb; // 75, 110, 150, 300, 600, 1200, 1800, 2400, 4800, 7200, and 9600bps
! 12336: BYTE bytBuffer[SIO_BUFFER_SIZE];
! 12337:
! 12338: if((hComm = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE) {
! 12339: if(GetCommProperties(hComm, &commProp)) {
! 12340: dwSettableBaud = commProp.dwSettableBaud;
! 12341: }
1.1.1.25 root 12342: EscapeCommFunction(hComm, CLRBREAK);
1.1.1.26! root 12343: // EscapeCommFunction(hComm, SETRTS);
! 12344: // EscapeCommFunction(hComm, SETDTR);
1.1.1.25 root 12345:
12346: while(!m_halted) {
12347: // setup comm port
12348: bool comm_state_changed = false;
12349:
12350: EnterCriticalSection(&q->csLineCtrl);
12351: if((p->prev_divisor != p->divisor.w || p->prev_line_ctrl != p->line_ctrl) && p->divisor.w != 0) {
12352: p->prev_divisor = p->divisor.w;
12353: p->prev_line_ctrl = p->line_ctrl;
12354: comm_state_changed = true;
12355: }
12356: LeaveCriticalSection(&q->csLineCtrl);
12357:
12358: if(comm_state_changed) {
1.1.1.26! root 12359: if(GetCommState(hComm, &dcb)) {
! 12360: // dcb.BaudRate = min(9600, 115200 / p->prev_divisor);
! 12361: DWORD baud = 115200 / p->prev_divisor;
! 12362: dcb.BaudRate = 9600; // default
! 12363:
! 12364: if((dwSettableBaud & BAUD_075 ) && baud >= 75 ) dcb.BaudRate = 75;
! 12365: if((dwSettableBaud & BAUD_110 ) && baud >= 110 ) dcb.BaudRate = 110;
! 12366: // 134.5bps is not supported ???
! 12367: // if((dwSettableBaud & BAUD_134_5) && baud >= 134.5) dcb.BaudRate = 134.5;
! 12368: if((dwSettableBaud & BAUD_150 ) && baud >= 150 ) dcb.BaudRate = 150;
! 12369: if((dwSettableBaud & BAUD_300 ) && baud >= 300 ) dcb.BaudRate = 300;
! 12370: if((dwSettableBaud & BAUD_600 ) && baud >= 600 ) dcb.BaudRate = 600;
! 12371: if((dwSettableBaud & BAUD_1200 ) && baud >= 1200 ) dcb.BaudRate = 1200;
! 12372: if((dwSettableBaud & BAUD_1800 ) && baud >= 1800 ) dcb.BaudRate = 1800;
! 12373: if((dwSettableBaud & BAUD_2400 ) && baud >= 2400 ) dcb.BaudRate = 2400;
! 12374: if((dwSettableBaud & BAUD_4800 ) && baud >= 4800 ) dcb.BaudRate = 4800;
! 12375: if((dwSettableBaud & BAUD_7200 ) && baud >= 7200 ) dcb.BaudRate = 7200;
! 12376: if((dwSettableBaud & BAUD_9600 ) && baud >= 9600 ) dcb.BaudRate = 9600;
! 12377: // if((dwSettableBaud & BAUD_14400) && baud >= 14400) dcb.BaudRate = 14400;
! 12378: // if((dwSettableBaud & BAUD_19200) && baud >= 19200) dcb.BaudRate = 19200;
! 12379: // if((dwSettableBaud & BAUD_38400) && baud >= 38400) dcb.BaudRate = 38400;
! 12380:
! 12381: switch(p->prev_line_ctrl & 0x03) {
! 12382: case 0x00: dcb.ByteSize = 5; break;
! 12383: case 0x01: dcb.ByteSize = 6; break;
! 12384: case 0x02: dcb.ByteSize = 7; break;
! 12385: case 0x03: dcb.ByteSize = 8; break;
! 12386: }
! 12387: switch(p->prev_line_ctrl & 0x04) {
! 12388: case 0x00: dcb.StopBits = ONESTOPBIT; break;
! 12389: case 0x04: dcb.StopBits = (dcb.ByteSize == 5) ? ONE5STOPBITS : TWOSTOPBITS; break;
! 12390: }
! 12391: switch(p->prev_line_ctrl & 0x38) {
! 12392: case 0x08: dcb.Parity = ODDPARITY; break;
! 12393: case 0x18: dcb.Parity = EVENPARITY; break;
! 12394: case 0x28: dcb.Parity = MARKPARITY; break;
! 12395: case 0x38: dcb.Parity = SPACEPARITY; break;
! 12396: default: dcb.Parity = NOPARITY; break;
! 12397: }
! 12398: dcb.fBinary = TRUE;
! 12399: dcb.fParity = (dcb.Parity != NOPARITY);
! 12400: dcb.fOutxCtsFlow = dcb.fOutxDsrFlow = TRUE;
! 12401: dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
! 12402: dcb.fDsrSensitivity = FALSE;//TRUE;
! 12403: dcb.fTXContinueOnXoff = TRUE;
! 12404: dcb.fOutX = dcb.fInX = FALSE;
! 12405: dcb.fErrorChar = FALSE;
! 12406: dcb.fNull = FALSE;
! 12407: dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
! 12408: dcb.fAbortOnError = FALSE;
! 12409:
! 12410: SetCommState(hComm, &dcb);
1.1.1.25 root 12411: }
12412:
12413: // check again to apply all comm state changes
12414: Sleep(10);
12415: continue;
12416: }
12417:
12418: // set comm pins
12419: bool change_brk = false;
1.1.1.26! root 12420: // bool change_rts = false;
! 12421: // bool change_dtr = false;
1.1.1.25 root 12422:
12423: EnterCriticalSection(&q->csModemCtrl);
12424: if(p->prev_set_brk != p->set_brk) {
12425: p->prev_set_brk = p->set_brk;
12426: change_brk = true;
12427: }
1.1.1.26! root 12428: // if(p->prev_set_rts != p->set_rts) {
! 12429: // p->prev_set_rts = p->set_rts;
! 12430: // change_rts = true;
! 12431: // }
! 12432: // if(p->prev_set_dtr != p->set_dtr) {
! 12433: // p->prev_set_dtr = p->set_dtr;
! 12434: // change_dtr = true;
! 12435: // }
1.1.1.25 root 12436: LeaveCriticalSection(&q->csModemCtrl);
12437:
12438: if(change_brk) {
1.1.1.26! root 12439: static UINT32 clear_time = 0;
! 12440: if(p->prev_set_brk) {
! 12441: EscapeCommFunction(hComm, SETBREAK);
! 12442: clear_time = timeGetTime() + 200;
! 12443: } else {
! 12444: // keep break for at least 200msec
! 12445: UINT32 cur_time = timeGetTime();
! 12446: if(clear_time > cur_time) {
! 12447: Sleep(clear_time - cur_time);
! 12448: }
! 12449: EscapeCommFunction(hComm, CLRBREAK);
! 12450: }
1.1.1.25 root 12451: }
1.1.1.26! root 12452: // if(change_rts) {
! 12453: // if(p->prev_set_rts) {
! 12454: // EscapeCommFunction(hComm, SETRTS);
! 12455: // } else {
! 12456: // EscapeCommFunction(hComm, CLRRTS);
! 12457: // }
! 12458: // }
! 12459: // if(change_dtr) {
! 12460: // if(p->prev_set_dtr) {
! 12461: // EscapeCommFunction(hComm, SETDTR);
! 12462: // } else {
! 12463: // EscapeCommFunction(hComm, CLRDTR);
! 12464: // }
! 12465: // }
1.1.1.25 root 12466:
12467: // get comm pins
12468: DWORD dwModemStat = 0;
12469:
12470: if(GetCommModemStatus(hComm, &dwModemStat)) {
12471: EnterCriticalSection(&q->csModemStat);
12472: if(dwModemStat & MS_RLSD_ON) {
12473: p->modem_stat |= 0x80;
12474: } else {
12475: p->modem_stat &= ~0x80;
12476: }
12477: if(dwModemStat & MS_RING_ON) {
12478: p->modem_stat |= 0x40;
12479: } else {
12480: p->modem_stat &= ~0x40;
12481: }
1.1.1.26! root 12482: // if(dwModemStat & MS_DSR_ON) {
! 12483: // p->modem_stat |= 0x20;
! 12484: // } else {
! 12485: // p->modem_stat &= ~0x20;
! 12486: // }
! 12487: // if(dwModemStat & MS_CTS_ON) {
! 12488: // p->modem_stat |= 0x10;
! 12489: // } else {
! 12490: // p->modem_stat &= ~0x10;
! 12491: // }
1.1.1.25 root 12492: if((p->prev_modem_stat & 0x80) != (p->modem_stat & 0x80)) {
12493: p->modem_stat |= 0x08;
12494: }
12495: if((p->prev_modem_stat & 0x40) && !(p->modem_stat & 0x40)) {
12496: p->modem_stat |= 0x04;
12497: }
1.1.1.26! root 12498: // if((p->prev_modem_stat & 0x20) != (p->modem_stat & 0x20)) {
! 12499: // p->modem_stat |= 0x02;
! 12500: // }
! 12501: // if((p->prev_modem_stat & 0x10) != (p->modem_stat & 0x10)) {
! 12502: // p->modem_stat |= 0x01;
! 12503: // }
1.1.1.25 root 12504: LeaveCriticalSection(&q->csModemStat);
12505: }
12506:
12507: // send data
12508: DWORD dwSend = 0;
12509:
12510: EnterCriticalSection(&q->csSendData);
12511: while(!p->send_buffer->empty()) {
12512: bytBuffer[dwSend++] = p->send_buffer->read();
12513: }
12514: LeaveCriticalSection(&q->csSendData);
12515:
12516: if(dwSend != 0) {
12517: DWORD dwWritten = 0;
12518: WriteFile(hComm, bytBuffer, dwSend, &dwWritten, NULL);
12519: }
12520:
12521: // get line status and recv data
12522: DWORD dwLineStat = 0;
12523: COMSTAT comStat;
12524:
12525: if(ClearCommError(hComm, &dwLineStat, &comStat)) {
12526: EnterCriticalSection(&q->csLineStat);
12527: if(dwLineStat & CE_BREAK) {
12528: p->line_stat_err |= 0x10;
12529: }
12530: if(dwLineStat & CE_FRAME) {
12531: p->line_stat_err |= 0x08;
12532: }
12533: if(dwLineStat & CE_RXPARITY) {
12534: p->line_stat_err |= 0x04;
12535: }
12536: if(dwLineStat & CE_OVERRUN) {
12537: p->line_stat_err |= 0x02;
12538: }
12539: LeaveCriticalSection(&q->csLineStat);
12540:
12541: if(comStat.cbInQue != 0) {
12542: EnterCriticalSection(&q->csRecvData);
12543: DWORD dwRecv = min(comStat.cbInQue, p->recv_buffer->remain());
12544: LeaveCriticalSection(&q->csRecvData);
12545:
12546: if(dwRecv != 0) {
12547: DWORD dwRead = 0;
12548: if(ReadFile(hComm, bytBuffer, dwRecv, &dwRead, NULL) && dwRead != 0) {
12549: EnterCriticalSection(&q->csRecvData);
12550: for(int i = 0; i < dwRead; i++) {
12551: p->recv_buffer->write(bytBuffer[i]);
12552: }
12553: LeaveCriticalSection(&q->csRecvData);
12554: }
12555: }
12556: }
12557: }
12558: Sleep(10);
12559: }
12560: CloseHandle(hComm);
12561: }
12562: return 0;
12563: }
12564:
1.1.1.8 root 12565: // cmos
12566:
12567: void cmos_init()
12568: {
12569: memset(cmos, 0, sizeof(cmos));
12570: cmos_addr = 0;
1.1 root 12571:
1.1.1.8 root 12572: // from DOSBox
12573: cmos_write(0x0a, 0x26);
12574: cmos_write(0x0b, 0x02);
12575: cmos_write(0x0d, 0x80);
1.1 root 12576: }
12577:
1.1.1.8 root 12578: void cmos_write(int addr, UINT8 val)
1.1 root 12579: {
1.1.1.8 root 12580: cmos[addr & 0x7f] = val;
12581: }
12582:
12583: #define CMOS_GET_TIME() { \
12584: UINT32 cur_sec = timeGetTime() / 1000 ; \
12585: if(prev_sec != cur_sec) { \
12586: GetLocalTime(&time); \
12587: prev_sec = cur_sec; \
12588: } \
1.1 root 12589: }
1.1.1.8 root 12590: #define CMOS_BCD(v) ((cmos[0x0b] & 4) ? (v) : to_bcd(v))
1.1 root 12591:
1.1.1.8 root 12592: UINT8 cmos_read(int addr)
1.1 root 12593: {
1.1.1.8 root 12594: static SYSTEMTIME time;
12595: static UINT32 prev_sec = 0;
1.1 root 12596:
1.1.1.8 root 12597: switch(addr & 0x7f) {
12598: case 0x00: CMOS_GET_TIME(); return(CMOS_BCD(time.wSecond));
12599: case 0x02: CMOS_GET_TIME(); return(CMOS_BCD(time.wMinute));
12600: case 0x04: CMOS_GET_TIME(); return(CMOS_BCD(time.wHour));
12601: case 0x06: CMOS_GET_TIME(); return(time.wDayOfWeek + 1);
12602: case 0x07: CMOS_GET_TIME(); return(CMOS_BCD(time.wDay));
12603: case 0x08: CMOS_GET_TIME(); return(CMOS_BCD(time.wMonth));
12604: case 0x09: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear));
12605: // case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 2 ? 0x80 : 0)); // 2msec
12606: case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 20 ? 0x80 : 0)); // precision of timeGetTime() may not be 1msec
12607: case 0x15: return((MEMORY_END >> 10) & 0xff);
12608: case 0x16: return((MEMORY_END >> 18) & 0xff);
12609: case 0x17: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
12610: case 0x18: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
12611: case 0x30: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
12612: case 0x31: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
12613: case 0x32: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear / 100));
1.1 root 12614: }
1.1.1.8 root 12615: return(cmos[addr & 0x7f]);
1.1 root 12616: }
12617:
1.1.1.7 root 12618: // kbd (a20)
12619:
12620: void kbd_init()
12621: {
1.1.1.8 root 12622: kbd_data = kbd_command = 0;
1.1.1.7 root 12623: kbd_status = 0x18;
12624: }
12625:
12626: UINT8 kbd_read_data()
12627: {
1.1.1.8 root 12628: kbd_status &= ~1;
1.1.1.7 root 12629: return(kbd_data);
12630: }
12631:
12632: void kbd_write_data(UINT8 val)
12633: {
12634: switch(kbd_command) {
12635: case 0xd1:
12636: i386_set_a20_line((val >> 1) & 1);
12637: break;
12638: }
12639: kbd_command = 0;
1.1.1.8 root 12640: kbd_status &= ~8;
1.1.1.7 root 12641: }
12642:
12643: UINT8 kbd_read_status()
12644: {
12645: return(kbd_status);
12646: }
12647:
12648: void kbd_write_command(UINT8 val)
12649: {
12650: switch(val) {
12651: case 0xd0:
12652: kbd_data = ((m_a20_mask >> 19) & 2) | 1;
1.1.1.8 root 12653: kbd_status |= 1;
1.1.1.7 root 12654: break;
12655: case 0xdd:
12656: i386_set_a20_line(0);
12657: break;
12658: case 0xdf:
12659: i386_set_a20_line(1);
12660: break;
1.1.1.26! root 12661: case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
! 12662: case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
1.1.1.7 root 12663: if(!(val & 1)) {
1.1.1.8 root 12664: if((cmos[0x0f] & 0x7f) == 5) {
1.1.1.7 root 12665: // reset pic
12666: pic_init();
12667: pic[0].irr = pic[1].irr = 0x00;
12668: pic[0].imr = pic[1].imr = 0xff;
12669: }
12670: CPU_RESET_CALL(CPU_MODEL);
12671: i386_jmp_far(0x40, 0x67);
12672: }
12673: i386_set_a20_line((val >> 1) & 1);
12674: break;
12675: }
12676: kbd_command = val;
1.1.1.8 root 12677: kbd_status |= 8;
1.1.1.7 root 12678: }
12679:
1.1.1.9 root 12680: // vga
12681:
12682: UINT8 vga_read_status()
12683: {
12684: // 60hz
12685: static const int period[3] = {16, 17, 17};
12686: static int index = 0;
12687: UINT32 time = timeGetTime() % period[index];
12688:
12689: index = (index + 1) % 3;
1.1.1.14 root 12690: return((time < 4 ? 0x08 : 0) | (time == 0 ? 0 : 0x01));
1.1.1.9 root 12691: }
12692:
1.1 root 12693: // i/o bus
12694:
1.1.1.25 root 12695: #ifdef ENABLE_DEBUG_IOPORT
12696: UINT8 read_io_byte_debug(offs_t addr);
12697:
12698: UINT8 read_io_byte(offs_t addr)
12699: {
12700: UINT8 val = read_io_byte_debug(addr);
12701: if(fdebug != NULL) {
12702: fprintf(fdebug, "inb %04X, %02X\n", addr, val);
12703: }
12704: return(val);
12705: }
12706:
12707: UINT8 read_io_byte_debug(offs_t addr)
12708: #else
1.1 root 12709: UINT8 read_io_byte(offs_t addr)
1.1.1.25 root 12710: #endif
1.1 root 12711: {
12712: switch(addr) {
1.1.1.25 root 12713: case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
12714: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
12715: return(dma_read(0, addr));
12716: case 0x20: case 0x21:
1.1 root 12717: return(pic_read(0, addr));
1.1.1.25 root 12718: case 0x40: case 0x41: case 0x42: case 0x43:
1.1 root 12719: return(pit_read(addr & 0x03));
1.1.1.7 root 12720: case 0x60:
12721: return(kbd_read_data());
1.1.1.9 root 12722: case 0x61:
12723: return(system_port);
1.1.1.7 root 12724: case 0x64:
12725: return(kbd_read_status());
1.1 root 12726: case 0x71:
1.1.1.8 root 12727: return(cmos_read(cmos_addr));
1.1.1.25 root 12728: case 0x81:
12729: return(dma_page_read(0, 2));
12730: case 0x82:
12731: return(dma_page_read(0, 3));
12732: case 0x83:
12733: return(dma_page_read(0, 1));
12734: case 0x87:
12735: return(dma_page_read(0, 0));
12736: case 0x89:
12737: return(dma_page_read(1, 2));
12738: case 0x8a:
12739: return(dma_page_read(1, 3));
12740: case 0x8b:
12741: return(dma_page_read(1, 1));
12742: case 0x8f:
12743: return(dma_page_read(1, 0));
1.1 root 12744: case 0x92:
1.1.1.3 root 12745: return((m_a20_mask >> 19) & 2);
1.1.1.25 root 12746: case 0xa0: case 0xa1:
1.1 root 12747: return(pic_read(1, addr));
1.1.1.25 root 12748: case 0xc0: case 0xc2: case 0xc4: case 0xc6: case 0xc8: case 0xca: case 0xcc: case 0xce:
12749: case 0xd0: case 0xd2: case 0xd4: case 0xd6: case 0xd8: case 0xda: case 0xdc: case 0xde:
1.1.1.26! root 12750: return(dma_read(1, (addr - 0xc0) >> 1));
! 12751: // case 0x278: case 0x279: case 0x27a:
! 12752: // return(pio_read(1, addr));
1.1.1.25 root 12753: case 0x2f8: case 0x2f9: case 0x2fa: case 0x2fb: case 0x2fc: case 0x2fd: case 0x2fe: case 0x2ff:
12754: return(sio_read(1, addr));
12755: case 0x378: case 0x379: case 0x37a:
12756: return(pio_read(0, addr));
12757: case 0x3ba: case 0x3da:
1.1.1.9 root 12758: return(vga_read_status());
1.1.1.25 root 12759: case 0x3f8: case 0x3f9: case 0x3fa: case 0x3fb: case 0x3fc: case 0x3fd: case 0x3fe: case 0x3ff:
12760: return(sio_read(0, addr));
1.1 root 12761: default:
12762: // error("inb %4x\n", addr);
12763: break;
12764: }
12765: return(0xff);
12766: }
12767:
12768: UINT16 read_io_word(offs_t addr)
12769: {
12770: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8));
12771: }
12772:
12773: UINT32 read_io_dword(offs_t addr)
12774: {
12775: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8) | (read_io_byte(addr + 2) << 16) | (read_io_byte(addr + 3) << 24));
12776: }
12777:
12778: void write_io_byte(offs_t addr, UINT8 val)
12779: {
1.1.1.25 root 12780: #ifdef ENABLE_DEBUG_IOPORT
12781: if(fdebug != NULL) {
12782: fprintf(fdebug, "outb %04X, %02X\n", addr, val);
12783: }
12784: #endif
1.1 root 12785: switch(addr) {
1.1.1.25 root 12786: case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
12787: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
12788: dma_write(0, addr, val);
12789: break;
12790: case 0x20: case 0x21:
1.1 root 12791: pic_write(0, addr, val);
12792: break;
1.1.1.25 root 12793: case 0x40: case 0x41: case 0x42: case 0x43:
1.1 root 12794: pit_write(addr & 0x03, val);
12795: break;
1.1.1.7 root 12796: case 0x60:
12797: kbd_write_data(val);
12798: break;
1.1.1.9 root 12799: case 0x61:
12800: if((system_port & 3) != 3 && (val & 3) == 3) {
12801: // beep on
12802: // MessageBeep(-1);
12803: } else if((system_port & 3) == 3 && (val & 3) != 3) {
12804: // beep off
12805: }
12806: system_port = val;
12807: break;
1.1 root 12808: case 0x64:
1.1.1.7 root 12809: kbd_write_command(val);
1.1 root 12810: break;
12811: case 0x70:
12812: cmos_addr = val;
12813: break;
12814: case 0x71:
1.1.1.8 root 12815: cmos_write(cmos_addr, val);
1.1 root 12816: break;
1.1.1.25 root 12817: case 0x81:
12818: dma_page_write(0, 2, val);
12819: case 0x82:
12820: dma_page_write(0, 3, val);
12821: case 0x83:
12822: dma_page_write(0, 1, val);
12823: case 0x87:
12824: dma_page_write(0, 0, val);
12825: case 0x89:
12826: dma_page_write(1, 2, val);
12827: case 0x8a:
12828: dma_page_write(1, 3, val);
12829: case 0x8b:
12830: dma_page_write(1, 1, val);
12831: case 0x8f:
12832: dma_page_write(1, 0, val);
1.1 root 12833: case 0x92:
1.1.1.7 root 12834: i386_set_a20_line((val >> 1) & 1);
1.1 root 12835: break;
1.1.1.25 root 12836: case 0xa0: case 0xa1:
1.1 root 12837: pic_write(1, addr, val);
12838: break;
1.1.1.25 root 12839: case 0xc0: case 0xc2: case 0xc4: case 0xc6: case 0xc8: case 0xca: case 0xcc: case 0xce:
12840: case 0xd0: case 0xd2: case 0xd4: case 0xd6: case 0xd8: case 0xda: case 0xdc: case 0xde:
1.1.1.26! root 12841: dma_write(1, (addr - 0xc0) >> 1, val);
1.1.1.25 root 12842: break;
1.1.1.26! root 12843: // case 0x278: case 0x279: case 0x27a:
! 12844: // pio_write(1, addr, val);
! 12845: // break;
1.1.1.25 root 12846: case 0x2f8: case 0x2f9: case 0x2fa: case 0x2fb: case 0x2fc: case 0x2fd: case 0x2fe: case 0x2ff:
12847: sio_write(1, addr, val);
12848: break;
12849: case 0x378: case 0x379: case 0x37a:
12850: pio_write(0, addr, val);
12851: break;
12852: case 0x3f8: case 0x3f9: case 0x3fa: case 0x3fb: case 0x3fc: case 0x3fd: case 0x3fe: case 0x3ff:
12853: sio_write(0, addr, val);
12854: break;
1.1 root 12855: default:
12856: // error("outb %4x,%2x\n", addr, val);
12857: break;
12858: }
12859: }
12860:
12861: void write_io_word(offs_t addr, UINT16 val)
12862: {
12863: write_io_byte(addr + 0, (val >> 0) & 0xff);
12864: write_io_byte(addr + 1, (val >> 8) & 0xff);
12865: }
12866:
12867: void write_io_dword(offs_t addr, UINT32 val)
12868: {
12869: write_io_byte(addr + 0, (val >> 0) & 0xff);
12870: write_io_byte(addr + 1, (val >> 8) & 0xff);
12871: write_io_byte(addr + 2, (val >> 16) & 0xff);
12872: write_io_byte(addr + 3, (val >> 24) & 0xff);
12873: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.