|
|
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 my_strchr(str, chr) (char *)_mbschr((unsigned char *)(str), (unsigned int)(chr))
11: #define my_strtok(tok, del) (char *)_mbstok((unsigned char *)(tok), (const unsigned char *)(del))
12: #define my_strupr(str) (char *)_mbsupr((unsigned char *)(str))
13:
14: #define fatalerror(...) { \
15: fprintf(stderr, __VA_ARGS__); \
16: exit(1); \
17: }
18: #define error(...) fprintf(stderr, "error: " __VA_ARGS__)
19:
1.1.1.12 root 20: #if defined(__MINGW32__)
21: extern "C" int _CRT_glob = 0;
22: #endif
23:
24: /*
25: kludge for "more-standardized" C++
26: */
27: #if !defined(_MSC_VER)
28: inline int kludge_min(int a, int b) { return (a<b ? a:b); }
29: inline int kludge_max(int a, int b) { return (a>b ? a:b); }
30: #define min(a,b) kludge_min(a,b)
31: #define max(a,b) kludge_max(a,b)
1.1.1.14 root 32: #elif _MSC_VER >= 1400
33: void ignore_invalid_parameters(const wchar_t *, const wchar_t *, const wchar_t *, unsigned int, uintptr_t)
34: {
35: }
36: #endif
37:
38: #define USE_THREAD
39:
40: #ifdef USE_THREAD
41: static CRITICAL_SECTION vram_crit_sect;
42: #else
43: #define EnterCriticalSection(x)
44: #define LeaveCriticalSection(x)
45: #define vram_flush()
1.1.1.12 root 46: #endif
47:
1.1.1.14 root 48: #define VIDEO_REGEN *(UINT16 *)(mem + 0x44c)
49: #define SCR_BUF(y,x) scr_buf[(y) * scr_buf_size.X + (x)]
50:
51: void change_console_size(int width, int height);
52: void clear_scr_buffer(WORD attr);
53:
54: static UINT32 vram_length_char = 0, vram_length_attr = 0;
55: static UINT32 vram_last_length_char = 0, vram_last_length_attr = 0;
56: static COORD vram_coord_char, vram_coord_attr;
57:
58: bool ignore_illegal_insn = false;
59: bool limit_max_memory = false;
60: bool no_windows = false;
61: //bool ctrl_break = false;
62: bool stay_busy = false;
63: UINT32 iops = 0;
64:
65: BOOL is_vista_or_later;
66:
67: inline UINT32 get_ticks_since_midnight()
68: {
69: SYSTEMTIME time;
70:
71: GetLocalTime(&time);
72: unsigned __int64 msec = ((time.wHour * 60 + time.wMinute) * 60 + time.wSecond) * 1000 + time.wMilliseconds;
73: unsigned __int64 tick = msec * 0x1800b0 / 24 / 60 / 60 / 1000;
74: return (UINT32)tick;
75: }
76:
77: inline void maybe_idle()
78: {
79: // if it appears to be in a tight loop, assume waiting for input
80: // allow for one updated video character, for a spinning cursor
81: if(!stay_busy && iops < 1000 && vram_length_char <= 1 && vram_length_attr <= 1) {
82: Sleep(10);
83: }
84: iops = 0;
85: }
1.1.1.12 root 86:
1.1 root 87: /* ----------------------------------------------------------------------------
1.1.1.3 root 88: MAME i86/i386
1.1 root 89: ---------------------------------------------------------------------------- */
90:
91: //#define SUPPORT_DISASSEMBLER
92:
1.1.1.7 root 93: #if defined(HAS_I86)
94: #define CPU_MODEL i8086
1.1.1.9 root 95: #elif defined(HAS_I186)
96: #define CPU_MODEL i80186
1.1.1.7 root 97: #elif defined(HAS_I286)
98: #define CPU_MODEL i80286
99: #elif defined(HAS_I386)
1.1.1.3 root 100: #define CPU_MODEL i386
1.1.1.9 root 101: #else
102: #if defined(HAS_I386SX)
103: #define CPU_MODEL i386SX
104: #else
1.1.1.11 root 105: #if defined(HAS_I486)
106: #define CPU_MODEL i486
107: #else
108: #if defined(HAS_PENTIUM)
109: #define CPU_MODEL pentium
110: #elif defined(HAS_MEDIAGX)
111: #define CPU_MODEL mediagx
112: #elif defined(HAS_PENTIUM_PRO)
113: #define CPU_MODEL pentium_pro
114: #elif defined(HAS_PENTIUM_MMX)
115: #define CPU_MODEL pentium_mmx
116: #elif defined(HAS_PENTIUM2)
117: #define CPU_MODEL pentium2
118: #elif defined(HAS_PENTIUM3)
119: #define CPU_MODEL pentium3
120: #elif defined(HAS_PENTIUM4)
121: #define CPU_MODEL pentium4
122: #endif
123: #define SUPPORT_RDTSC
1.1.1.9 root 124: #endif
1.1.1.11 root 125: #define SUPPORT_FPU
1.1.1.9 root 126: #endif
1.1.1.7 root 127: #define HAS_I386
1.1.1.3 root 128: #endif
1.1 root 129:
1.1.1.10 root 130: #ifndef __BIG_ENDIAN__
1.1 root 131: #define LSB_FIRST
1.1.1.10 root 132: #endif
1.1 root 133:
134: #ifndef INLINE
135: #define INLINE inline
136: #endif
137: #define U64(v) UINT64(v)
138:
139: //#define logerror(...) fprintf(stderr, __VA_ARGS__)
140: #define logerror(...)
141: //#define popmessage(...) fprintf(stderr, __VA_ARGS__)
142: #define popmessage(...)
143:
144: /*****************************************************************************/
1.1.1.10 root 145: /* src/emu/devcpu.h */
146:
147: // CPU interface functions
148: #define CPU_INIT_NAME(name) cpu_init_##name
149: #define CPU_INIT(name) void CPU_INIT_NAME(name)()
150: #define CPU_INIT_CALL(name) CPU_INIT_NAME(name)()
151:
152: #define CPU_RESET_NAME(name) cpu_reset_##name
153: #define CPU_RESET(name) void CPU_RESET_NAME(name)()
154: #define CPU_RESET_CALL(name) CPU_RESET_NAME(name)()
155:
156: #define CPU_EXECUTE_NAME(name) cpu_execute_##name
157: #define CPU_EXECUTE(name) void CPU_EXECUTE_NAME(name)()
158: #define CPU_EXECUTE_CALL(name) CPU_EXECUTE_NAME(name)()
159:
160: #define CPU_TRANSLATE_NAME(name) cpu_translate_##name
161: #define CPU_TRANSLATE(name) int CPU_TRANSLATE_NAME(name)(address_spacenum space, int intention, offs_t *address)
162: #define CPU_TRANSLATE_CALL(name) CPU_TRANSLATE_NAME(name)(space, intention, address)
163:
164: #define CPU_DISASSEMBLE_NAME(name) cpu_disassemble_##name
165: #define CPU_DISASSEMBLE(name) int CPU_DISASSEMBLE_NAME(name)(char *buffer, offs_t eip, const UINT8 *oprom)
166: #define CPU_DISASSEMBLE_CALL(name) CPU_DISASSEMBLE_NAME(name)(buffer, eip, oprom)
167:
1.1.1.14 root 168: #define CPU_MODEL_STR(name) #name
169: #define CPU_MODEL_NAME(name) CPU_MODEL_STR(name)
170:
1.1.1.10 root 171: /*****************************************************************************/
172: /* src/emu/didisasm.h */
173:
174: // Disassembler constants
175: const UINT32 DASMFLAG_SUPPORTED = 0x80000000; // are disassembly flags supported?
176: const UINT32 DASMFLAG_STEP_OUT = 0x40000000; // this instruction should be the end of a step out sequence
177: const UINT32 DASMFLAG_STEP_OVER = 0x20000000; // this instruction should be stepped over by setting a breakpoint afterwards
178: const UINT32 DASMFLAG_OVERINSTMASK = 0x18000000; // number of extra instructions to skip when stepping over
179: const UINT32 DASMFLAG_OVERINSTSHIFT = 27; // bits to shift after masking to get the value
180: const UINT32 DASMFLAG_LENGTHMASK = 0x0000ffff; // the low 16-bits contain the actual length
181:
182: /*****************************************************************************/
1.1 root 183: /* src/emu/diexec.h */
184:
185: // I/O line states
186: enum line_state
187: {
188: CLEAR_LINE = 0, // clear (a fired or held) line
189: ASSERT_LINE, // assert an interrupt immediately
190: HOLD_LINE, // hold interrupt line until acknowledged
191: PULSE_LINE // pulse interrupt line instantaneously (only for NMI, RESET)
192: };
193:
194: // I/O line definitions
195: enum
196: {
197: INPUT_LINE_IRQ = 0,
198: INPUT_LINE_NMI
199: };
200:
201: /*****************************************************************************/
1.1.1.10 root 202: /* src/emu/dimemory.h */
1.1 root 203:
1.1.1.10 root 204: // Translation intentions
205: const int TRANSLATE_TYPE_MASK = 0x03; // read write or fetch
206: const int TRANSLATE_USER_MASK = 0x04; // user mode or fully privileged
207: const int TRANSLATE_DEBUG_MASK = 0x08; // debug mode (no side effects)
208:
209: const int TRANSLATE_READ = 0; // translate for read
210: const int TRANSLATE_WRITE = 1; // translate for write
211: const int TRANSLATE_FETCH = 2; // translate for instruction fetch
212: const int TRANSLATE_READ_USER = (TRANSLATE_READ | TRANSLATE_USER_MASK);
213: const int TRANSLATE_WRITE_USER = (TRANSLATE_WRITE | TRANSLATE_USER_MASK);
214: const int TRANSLATE_FETCH_USER = (TRANSLATE_FETCH | TRANSLATE_USER_MASK);
215: const int TRANSLATE_READ_DEBUG = (TRANSLATE_READ | TRANSLATE_DEBUG_MASK);
216: const int TRANSLATE_WRITE_DEBUG = (TRANSLATE_WRITE | TRANSLATE_DEBUG_MASK);
217: const int TRANSLATE_FETCH_DEBUG = (TRANSLATE_FETCH | TRANSLATE_DEBUG_MASK);
1.1 root 218:
1.1.1.10 root 219: /*****************************************************************************/
220: /* src/emu/emucore.h */
1.1 root 221:
1.1.1.10 root 222: // constants for expression endianness
223: enum endianness_t
224: {
225: ENDIANNESS_LITTLE,
226: ENDIANNESS_BIG
227: };
1.1 root 228:
1.1.1.10 root 229: // declare native endianness to be one or the other
230: #ifdef LSB_FIRST
231: const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_LITTLE;
232: #else
233: const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_BIG;
234: #endif
235:
236: // endian-based value: first value is if 'endian' is little-endian, second is if 'endian' is big-endian
237: #define ENDIAN_VALUE_LE_BE(endian,leval,beval) (((endian) == ENDIANNESS_LITTLE) ? (leval) : (beval))
238:
239: // endian-based value: first value is if native endianness is little-endian, second is if native is big-endian
240: #define NATIVE_ENDIAN_VALUE_LE_BE(leval,beval) ENDIAN_VALUE_LE_BE(ENDIANNESS_NATIVE, leval, beval)
241:
242: // endian-based value: first value is if 'endian' matches native, second is if 'endian' doesn't match native
243: #define ENDIAN_VALUE_NE_NNE(endian,leval,beval) (((endian) == ENDIANNESS_NATIVE) ? (neval) : (nneval))
1.1 root 244:
245: /*****************************************************************************/
246: /* src/emu/memory.h */
247:
1.1.1.10 root 248: // address spaces
249: enum address_spacenum
250: {
251: AS_0, // first address space
252: AS_1, // second address space
253: AS_2, // third address space
254: AS_3, // fourth address space
255: ADDRESS_SPACES, // maximum number of address spaces
256:
257: // alternate address space names for common use
258: AS_PROGRAM = AS_0, // program address space
259: AS_DATA = AS_1, // data address space
260: AS_IO = AS_2 // I/O address space
261: };
262:
1.1 root 263: // offsets and addresses are 32-bit (for now...)
264: typedef UINT32 offs_t;
265:
266: // read accessors
267: UINT8 read_byte(offs_t byteaddress)
268: {
1.1.1.4 root 269: #if defined(HAS_I386)
1.1 root 270: if(byteaddress < MAX_MEM) {
271: return mem[byteaddress];
1.1.1.3 root 272: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
273: // return read_byte(byteaddress & 0xfffff);
1.1 root 274: }
275: return 0;
1.1.1.4 root 276: #else
277: return mem[byteaddress];
278: #endif
1.1 root 279: }
280:
281: UINT16 read_word(offs_t byteaddress)
282: {
1.1.1.14 root 283: if(byteaddress == 0x41c) {
284: // pointer to first free slot in keyboard buffer
285: // XXX: the buffer itself doesn't actually exist in DOS memory
286: if(key_buf_char->count() == 0) {
287: maybe_idle();
288: }
289: return (UINT16)key_buf_char->count();
290: }
1.1.1.4 root 291: #if defined(HAS_I386)
1.1 root 292: if(byteaddress < MAX_MEM - 1) {
293: return *(UINT16 *)(mem + byteaddress);
1.1.1.3 root 294: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
295: // return read_word(byteaddress & 0xfffff);
1.1 root 296: }
297: return 0;
1.1.1.4 root 298: #else
299: return *(UINT16 *)(mem + byteaddress);
300: #endif
1.1 root 301: }
302:
303: UINT32 read_dword(offs_t byteaddress)
304: {
1.1.1.14 root 305: if(byteaddress == 0x46c) {
1.1.1.15! root 306: UINT32 ticks = get_ticks_since_midnight();
! 307: *(UINT32 *)(mem + 0x46c) = ticks;
! 308: return ticks;
1.1.1.14 root 309: }
1.1.1.4 root 310: #if defined(HAS_I386)
1.1 root 311: if(byteaddress < MAX_MEM - 3) {
312: return *(UINT32 *)(mem + byteaddress);
1.1.1.3 root 313: // } else if((byteaddress & 0xfffffff0) == 0xfffffff0) {
314: // return read_dword(byteaddress & 0xfffff);
1.1 root 315: }
316: return 0;
1.1.1.4 root 317: #else
318: return *(UINT32 *)(mem + byteaddress);
319: #endif
1.1 root 320: }
321:
322: // write accessors
1.1.1.14 root 323: #ifdef USE_THREAD
324: void vram_flush_char()
325: {
326: if(vram_length_char != 0) {
327: DWORD num;
328: WriteConsoleOutputCharacter(hStdout, scr_char, vram_length_char, vram_coord_char, &num);
329: vram_length_char = vram_last_length_char = 0;
330: }
331: }
332:
333: void vram_flush_attr()
334: {
335: if(vram_length_attr != 0) {
336: DWORD num;
337: WriteConsoleOutputAttribute(hStdout, scr_attr, vram_length_attr, vram_coord_attr, &num);
338: vram_length_attr = vram_last_length_attr = 0;
339: }
340: }
341:
342: void vram_flush()
343: {
344: if(vram_length_char != 0 || vram_length_attr != 0) {
345: EnterCriticalSection(&vram_crit_sect);
346: vram_flush_char();
347: vram_flush_attr();
348: LeaveCriticalSection(&vram_crit_sect);
349: }
350: }
351: #endif
352:
353: void write_text_vram_char(offs_t offset, UINT8 data)
1.1.1.8 root 354: {
1.1.1.14 root 355: #ifdef USE_THREAD
356: static offs_t first_offset_char, last_offset_char;
357:
358: if(vram_length_char != 0) {
359: if(offset <= last_offset_char && offset >= first_offset_char) {
360: scr_char[(offset - first_offset_char) >> 1] = data;
361: return;
362: }
363: if(offset != last_offset_char + 2) {
364: vram_flush_char();
365: }
366: }
367: if(vram_length_char == 0) {
368: first_offset_char = offset;
369: vram_coord_char.X = (offset >> 1) % scr_width;
370: vram_coord_char.Y = (offset >> 1) / scr_width + scr_top;
371: }
372: scr_char[vram_length_char++] = data;
373: last_offset_char = offset;
374: #else
1.1.1.8 root 375: COORD co;
376: DWORD num;
377:
1.1.1.14 root 378: co.X = (offset >> 1) % scr_width;
379: co.Y = (offset >> 1) / scr_width;
380: scr_char[0] = data;
381: WriteConsoleOutputCharacter(hStdout, scr_char, 1, co, &num);
382: #endif
383: }
384:
385: void write_text_vram_attr(offs_t offset, UINT8 data)
386: {
387: #ifdef USE_THREAD
388: static offs_t first_offset_attr, last_offset_attr;
389:
390: if(vram_length_attr != 0) {
391: if(offset <= last_offset_attr && offset >= first_offset_attr) {
392: scr_attr[(offset - first_offset_attr) >> 1] = data;
393: return;
394: }
395: if(offset != last_offset_attr + 2) {
396: vram_flush_attr();
397: }
398: }
399: if(vram_length_attr == 0) {
400: first_offset_attr = offset;
401: vram_coord_attr.X = (offset >> 1) % scr_width;
402: vram_coord_attr.Y = (offset >> 1) / scr_width + scr_top;
403: }
404: scr_attr[vram_length_attr++] = data;
405: last_offset_attr = offset;
406: #else
407: COORD co;
408: DWORD num;
1.1.1.8 root 409:
1.1.1.14 root 410: co.X = (offset >> 1) % scr_width;
411: co.Y = (offset >> 1) / scr_width;
412: scr_attr[0] = data;
413: WriteConsoleOutputAttribute(hStdout, scr_attr, 1, co, &num);
414: #endif
415: }
416:
417: void write_text_vram_byte(offs_t offset, UINT8 data)
418: {
419: EnterCriticalSection(&vram_crit_sect);
1.1.1.8 root 420: if(offset & 1) {
1.1.1.14 root 421: write_text_vram_attr(offset, data);
1.1.1.8 root 422: } else {
1.1.1.14 root 423: write_text_vram_char(offset, data);
1.1.1.8 root 424: }
1.1.1.14 root 425: LeaveCriticalSection(&vram_crit_sect);
1.1.1.8 root 426: }
427:
428: void write_text_vram_word(offs_t offset, UINT16 data)
429: {
1.1.1.14 root 430: EnterCriticalSection(&vram_crit_sect);
1.1.1.8 root 431: if(offset & 1) {
1.1.1.14 root 432: write_text_vram_attr(offset , (data ) & 0xff);
433: write_text_vram_char(offset + 1, (data >> 8) & 0xff);
1.1.1.8 root 434: } else {
1.1.1.14 root 435: write_text_vram_char(offset , (data ) & 0xff);
436: write_text_vram_attr(offset + 1, (data >> 8) & 0xff);
1.1.1.8 root 437: }
1.1.1.14 root 438: LeaveCriticalSection(&vram_crit_sect);
1.1.1.8 root 439: }
440:
441: void write_text_vram_dword(offs_t offset, UINT32 data)
442: {
1.1.1.14 root 443: EnterCriticalSection(&vram_crit_sect);
1.1.1.8 root 444: if(offset & 1) {
1.1.1.14 root 445: write_text_vram_attr(offset , (data ) & 0xff);
446: write_text_vram_char(offset + 1, (data >> 8) & 0xff);
447: write_text_vram_attr(offset + 2, (data >> 16) & 0xff);
448: write_text_vram_char(offset + 3, (data >> 24) & 0xff);
449: } else {
450: write_text_vram_char(offset , (data ) & 0xff);
451: write_text_vram_attr(offset + 1, (data >> 8) & 0xff);
452: write_text_vram_char(offset + 2, (data >> 16) & 0xff);
453: write_text_vram_attr(offset + 3, (data >> 24) & 0xff);
1.1.1.8 root 454: }
1.1.1.14 root 455: LeaveCriticalSection(&vram_crit_sect);
1.1.1.8 root 456: }
457:
1.1 root 458: void write_byte(offs_t byteaddress, UINT8 data)
459: {
1.1.1.8 root 460: if(byteaddress < MEMORY_END) {
1.1.1.3 root 461: mem[byteaddress] = data;
1.1.1.8 root 462: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 463: if(!restore_console_on_exit) {
464: change_console_size(scr_width, scr_height);
1.1.1.12 root 465: }
1.1.1.8 root 466: write_text_vram_byte(byteaddress - text_vram_top_address, data);
467: mem[byteaddress] = data;
468: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
469: if(int_10h_feh_called && !int_10h_ffh_called) {
470: write_text_vram_byte(byteaddress - shadow_buffer_top_address, data);
1.1 root 471: }
472: mem[byteaddress] = data;
1.1.1.4 root 473: #if defined(HAS_I386)
1.1.1.3 root 474: } else if(byteaddress < MAX_MEM) {
1.1.1.4 root 475: #else
476: } else {
477: #endif
1.1.1.3 root 478: mem[byteaddress] = data;
1.1 root 479: }
480: }
481:
482: void write_word(offs_t byteaddress, UINT16 data)
483: {
1.1.1.8 root 484: if(byteaddress < MEMORY_END) {
1.1.1.14 root 485: if(byteaddress == 0x450 + mem[0x462] * 2) {
486: COORD co;
487: co.X = data & 0xff;
488: co.Y = (data >> 8) + scr_top;
489: SetConsoleCursorPosition(hStdout, co);
490: }
1.1.1.3 root 491: *(UINT16 *)(mem + byteaddress) = data;
1.1.1.8 root 492: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 493: if(!restore_console_on_exit) {
494: change_console_size(scr_width, scr_height);
1.1.1.12 root 495: }
1.1.1.8 root 496: write_text_vram_word(byteaddress - text_vram_top_address, data);
497: *(UINT16 *)(mem + byteaddress) = data;
498: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
499: if(int_10h_feh_called && !int_10h_ffh_called) {
500: write_text_vram_word(byteaddress - shadow_buffer_top_address, data);
1.1 root 501: }
502: *(UINT16 *)(mem + byteaddress) = data;
1.1.1.4 root 503: #if defined(HAS_I386)
1.1.1.3 root 504: } else if(byteaddress < MAX_MEM - 1) {
1.1.1.4 root 505: #else
506: } else {
507: #endif
1.1.1.3 root 508: *(UINT16 *)(mem + byteaddress) = data;
1.1 root 509: }
510: }
511:
512: void write_dword(offs_t byteaddress, UINT32 data)
513: {
1.1.1.8 root 514: if(byteaddress < MEMORY_END) {
1.1.1.3 root 515: *(UINT32 *)(mem + byteaddress) = data;
1.1.1.8 root 516: } else if(byteaddress >= text_vram_top_address && byteaddress < text_vram_end_address) {
1.1.1.14 root 517: if(!restore_console_on_exit) {
518: change_console_size(scr_width, scr_height);
1.1.1.12 root 519: }
1.1.1.8 root 520: write_text_vram_dword(byteaddress - text_vram_top_address, data);
521: *(UINT32 *)(mem + byteaddress) = data;
522: } else if(byteaddress >= shadow_buffer_top_address && byteaddress < shadow_buffer_end_address) {
523: if(int_10h_feh_called && !int_10h_ffh_called) {
524: write_text_vram_dword(byteaddress - shadow_buffer_top_address, data);
1.1 root 525: }
526: *(UINT32 *)(mem + byteaddress) = data;
1.1.1.4 root 527: #if defined(HAS_I386)
1.1.1.3 root 528: } else if(byteaddress < MAX_MEM - 3) {
1.1.1.4 root 529: #else
530: } else {
531: #endif
1.1.1.3 root 532: *(UINT32 *)(mem + byteaddress) = data;
1.1 root 533: }
534: }
535:
536: #define read_decrypted_byte read_byte
537: #define read_decrypted_word read_word
538: #define read_decrypted_dword read_dword
539:
1.1.1.3 root 540: #define read_raw_byte read_byte
541: #define write_raw_byte write_byte
542:
543: #define read_word_unaligned read_word
544: #define write_word_unaligned write_word
545:
546: #define read_io_word_unaligned read_io_word
547: #define write_io_word_unaligned write_io_word
548:
1.1 root 549: UINT8 read_io_byte(offs_t byteaddress);
550: UINT16 read_io_word(offs_t byteaddress);
551: UINT32 read_io_dword(offs_t byteaddress);
552:
553: void write_io_byte(offs_t byteaddress, UINT8 data);
554: void write_io_word(offs_t byteaddress, UINT16 data);
555: void write_io_dword(offs_t byteaddress, UINT32 data);
556:
557: /*****************************************************************************/
558: /* src/osd/osdcomm.h */
559:
560: /* Highly useful macro for compile-time knowledge of an array size */
561: #define ARRAY_LENGTH(x) (sizeof(x) / sizeof(x[0]))
562:
1.1.1.3 root 563: #if defined(HAS_I386)
1.1.1.10 root 564: static CPU_TRANSLATE(i386);
565: #include "mame/lib/softfloat/softfloat.c"
566: #include "mame/emu/cpu/i386/i386.c"
1.1.1.12 root 567: #include "mame/emu/cpu/vtlb.c"
1.1.1.3 root 568: #elif defined(HAS_I286)
1.1.1.10 root 569: #include "mame/emu/cpu/i86/i286.c"
1.1.1.3 root 570: #else
1.1.1.10 root 571: #include "mame/emu/cpu/i86/i86.c"
1.1.1.3 root 572: #endif
1.1 root 573: #ifdef SUPPORT_DISASSEMBLER
1.1.1.10 root 574: #include "mame/emu/cpu/i386/i386dasm.c"
1.1.1.3 root 575: bool dasm = false;
1.1 root 576: #endif
577:
1.1.1.3 root 578: #if defined(HAS_I386)
579: #define SREG(x) m_sreg[x].selector
580: #define SREG_BASE(x) m_sreg[x].base
581:
582: int cpu_type, cpu_step;
583: #else
584: #define REG8(x) m_regs.b[x]
585: #define REG16(x) m_regs.w[x]
586: #define SREG(x) m_sregs[x]
587: #define SREG_BASE(x) m_base[x]
588: #define m_CF m_CarryVal
589: #define m_a20_mask AMASK
590: #define i386_load_segment_descriptor(x) m_base[x] = SegBase(x)
591: #if defined(HAS_I286)
592: #define i386_set_a20_line(x) i80286_set_a20_line(x)
593: #else
594: #define i386_set_a20_line(x)
595: #endif
596: #define i386_set_irq_line(x, y) set_irq_line(x, y)
597: #endif
1.1 root 598:
599: void i386_jmp_far(UINT16 selector, UINT32 address)
600: {
1.1.1.3 root 601: #if defined(HAS_I386)
1.1 root 602: if(PROTECTED_MODE && !V8086_MODE) {
1.1.1.3 root 603: i386_protected_mode_jump(selector, address, 1, m_operand_size);
1.1 root 604: } else {
1.1.1.3 root 605: SREG(CS) = selector;
606: m_performed_intersegment_jump = 1;
607: i386_load_segment_descriptor(CS);
608: m_eip = address;
609: CHANGE_PC(m_eip);
1.1 root 610: }
1.1.1.3 root 611: #elif defined(HAS_I286)
612: i80286_code_descriptor(selector, address, 1);
613: #else
614: SREG(CS) = selector;
615: i386_load_segment_descriptor(CS);
616: m_pc = (SREG_BASE(CS) + address) & m_a20_mask;
617: #endif
1.1 root 618: }
619:
620: /* ----------------------------------------------------------------------------
621: main
622: ---------------------------------------------------------------------------- */
623:
1.1.1.10 root 624: bool is_started_from_command_prompt()
625: {
1.1.1.14 root 626: DWORD pl;
627: return(GetConsoleProcessList(&pl, 1) > 1);
628: }
629:
630: BOOL is_greater_windows_version(DWORD dwMajorVersion, DWORD dwMinorVersion, WORD wServicePackMajor, WORD wServicePackMinor)
631: {
632: //https://msdn.microsoft.com/en-us/library/windows/desktop/ms725491(v=vs.85).aspx
633: OSVERSIONINFOEX osvi;
634: DWORDLONG dwlConditionMask = 0;
635: int op = VER_GREATER_EQUAL;
636:
637: // Initialize the OSVERSIONINFOEX structure.
638: ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
639: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
640: osvi.dwMajorVersion = dwMajorVersion;
641: osvi.dwMinorVersion = dwMinorVersion;
642: osvi.wServicePackMajor = wServicePackMajor;
643: osvi.wServicePackMinor = wServicePackMinor;
644:
645: // Initialize the condition mask.
646: VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, op );
647: VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, op );
648: VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMAJOR, op );
649: VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMINOR, op );
650:
651: // Perform the test.
652: return VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, dwlConditionMask);
653: }
654:
655: BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
656: {
657: if(dwCtrlType == CTRL_BREAK_EVENT || dwCtrlType == CTRL_C_EVENT) {
658: m_halted = 1;
659: return TRUE;
660: }
661: return FALSE;
662: }
663:
664: #ifdef USE_THREAD
665: DWORD WINAPI vram_thread(LPVOID)
666: {
667: while(!m_halted) {
668: EnterCriticalSection(&vram_crit_sect);
669: if(vram_length_char != 0 && vram_length_char == vram_last_length_char) {
670: vram_flush_char();
671: }
672: if(vram_length_attr != 0 && vram_length_attr == vram_last_length_attr) {
673: vram_flush_attr();
674: }
675: vram_last_length_char = vram_length_char;
676: vram_last_length_attr = vram_length_attr;
677: LeaveCriticalSection(&vram_crit_sect);
678: // this is about half the maximum keyboard repeat rate - any
679: // lower tends to be jerky, any higher misses updates
680: Sleep(15);
1.1.1.10 root 681: }
1.1.1.14 root 682: return 0;
1.1.1.10 root 683: }
1.1.1.14 root 684: #endif
1.1.1.10 root 685:
1.1.1.9 root 686: #define IS_NUMERIC(c) ((c) >= '0' && (c) <= '9')
687:
1.1 root 688: int main(int argc, char *argv[], char *envp[])
689: {
1.1.1.9 root 690: int arg_offset = 0;
691: int standard_env = 0;
1.1.1.14 root 692: int buf_width = 0, buf_height = 0;
1.1.1.15! root 693: BOOL bSuccess, bChangeScreenSize = FALSE;
1.1 root 694:
1.1.1.9 root 695: for(int i = 1; i < argc; i++) {
696: if(_strnicmp(argv[i], "-e", 2) == 0) {
697: standard_env = 1;
698: arg_offset++;
1.1.1.14 root 699: } else if(_strnicmp(argv[i], "-i", 2) == 0) {
700: ignore_illegal_insn = true;
701: arg_offset++;
702: } else if(_strnicmp(argv[i], "-m", 2) == 0) {
703: limit_max_memory = true;
704: arg_offset++;
705: } else if(_strnicmp(argv[i], "-d", 2) == 0) {
706: no_windows = true;
707: arg_offset++;
708: } else if(_strnicmp(argv[i], "-b", 2) == 0) {
709: stay_busy = true;
710: arg_offset++;
711: } else if(_strnicmp(argv[i], "-n", 2) == 0) {
712: buf_width = 80;
713: buf_height = 25;
714: sscanf(argv[1] + 2, "%hd,%hd", &buf_height, &buf_width);
715: arg_offset++;
1.1.1.9 root 716: } else if(_strnicmp(argv[i], "-v", 2) == 0) {
717: if(strlen(argv[i]) >= 6 && IS_NUMERIC(argv[i][2]) && argv[i][3] == '.' && IS_NUMERIC(argv[i][4]) && IS_NUMERIC(argv[i][5])) {
718: major_version = argv[i][2] - '0';
719: minor_version = (argv[i][4] - '0') * 10 + (argv[i][5] - '0');
720: }
721: arg_offset++;
722: } else {
723: break;
724: }
725: }
726:
727: if(argc < 2 + arg_offset) {
1.1 root 728: #ifdef _WIN64
1.1.1.14 root 729: fprintf(stderr, "MS-DOS Player (" CPU_MODEL_NAME(CPU_MODEL) ") for Win32-x64 console\n\n");
1.1 root 730: #else
1.1.1.14 root 731: fprintf(stderr, "MS-DOS Player (" CPU_MODEL_NAME(CPU_MODEL) ") for Win32 console\n\n");
1.1 root 732: #endif
1.1.1.14 root 733: fprintf(stderr, "Usage: MSDOS [-b] [-d] [-e] [-i] [-m] [-n[L[,C]]] [-vX.XX] (command file) [options]\n"
734: "\n"
735: "\t-b\tstay busy during keyboard polling\n"
736: "\t-d\tpretend running under straight DOS, not Windows\n"
737: "\t-e\tuse a reduced environment block\n"
738: "\t-i\tignore invalid instructions\n"
739: "\t-m\trestrict free memory to 0x7FFF paragraphs\n"
740: "\t-n\tcreate a new buffer (25 lines, 80 columns by default)\n"
741: "\t-v\tset the DOS version\n");
1.1.1.10 root 742:
743: if(!is_started_from_command_prompt()) {
744: fprintf(stderr, "\nStart this program from a command prompt!\n\nHit any key to quit...");
745: while(!_kbhit()) {
746: Sleep(10);
747: }
748: }
1.1 root 749: return(EXIT_FAILURE);
750: }
751:
1.1.1.14 root 752: is_vista_or_later = is_greater_windows_version(6, 0, 0, 0);
753:
1.1 root 754: CONSOLE_SCREEN_BUFFER_INFO csbi;
1.1.1.14 root 755: CONSOLE_CURSOR_INFO ci;
1.1 root 756: hStdin = GetStdHandle(STD_INPUT_HANDLE);
757: hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
1.1.1.12 root 758: bSuccess = GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 759: GetConsoleCursorInfo(hStdout, &ci);
1.1 root 760:
1.1.1.14 root 761: for(int y = 0; y < SCR_BUF_WIDTH; y++) {
762: for(int x = 0; x < SCR_BUF_HEIGHT; x++) {
763: SCR_BUF(y,x).Char.AsciiChar = ' ';
764: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
1.1 root 765: }
766: }
1.1.1.12 root 767: if(bSuccess) {
768: scr_width = csbi.dwSize.X;
1.1.1.14 root 769: scr_height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
770:
771: // v-text shadow buffer size is 0x7ff0
772: if((scr_width > SCR_BUF_WIDTH) || (scr_height > SCR_BUF_HEIGHT) || (scr_width * scr_height * 2 > 0x7ff0) ||
773: (buf_width != 0 && buf_width != scr_width) || (buf_height != 0 && buf_height != scr_height)) {
774: scr_width = min(buf_width != 0 ? buf_width : scr_width, SCR_BUF_WIDTH);
775: scr_height = min(buf_height != 0 ? buf_height : scr_height, SCR_BUF_HEIGHT);
776: if(scr_width * scr_height * 2 > 0x7ff0) {
777: scr_width = 80;
778: scr_height = 25;
779: }
1.1.1.15! root 780: bChangeScreenSize = TRUE;
1.1.1.14 root 781: }
1.1.1.12 root 782: } else {
783: // for a proof (not a console)
784: scr_width = 80;
785: scr_height = 25;
786: }
1.1.1.14 root 787: scr_buf_size.X = scr_width;
788: scr_buf_size.Y = scr_height;
789: scr_buf_pos.X = scr_buf_pos.Y = 0;
790: scr_top = csbi.srWindow.Top;
1.1 root 791: cursor_moved = false;
792:
793: key_buf_char = new FIFO();
794: key_buf_scan = new FIFO();
795:
796: hardware_init();
797:
1.1.1.9 root 798: if(msdos_init(argc - (arg_offset + 1), argv + (arg_offset + 1), envp, standard_env)) {
1.1 root 799: retval = EXIT_FAILURE;
800: } else {
1.1.1.15! root 801: if(bChangeScreenSize) {
! 802: change_console_size(scr_width, scr_height);
! 803: }
1.1.1.14 root 804: #if defined(_MSC_VER) && _MSC_VER >= 1400
805: _set_invalid_parameter_handler((_invalid_parameter_handler)ignore_invalid_parameters);
806: #endif
807: SetConsoleCtrlHandler(ctrl_handler, TRUE);
808:
1.1.1.8 root 809: TIMECAPS caps;
810: timeGetDevCaps(&caps, sizeof(TIMECAPS));
811: timeBeginPeriod(caps.wPeriodMin);
1.1.1.14 root 812:
813: #ifdef USE_THREAD
814: InitializeCriticalSection(&vram_crit_sect);
815: CloseHandle(CreateThread(NULL, 4096, vram_thread, NULL, 0, NULL));
816: #endif
1.1 root 817: hardware_run();
1.1.1.14 root 818: #ifdef USE_THREAD
819: vram_flush();
820: DeleteCriticalSection(&vram_crit_sect);
821: #endif
822:
1.1.1.12 root 823: if(bSuccess) {
824: if(restore_console_on_exit) {
1.1.1.14 root 825: // window can't be bigger than buffer,
826: // buffer can't be smaller than window,
827: // so make a tiny window,
828: // set the required buffer,
829: // then set the required window
830: SMALL_RECT rect;
831: SET_RECT(rect, 0, csbi.srWindow.Top, 0, csbi.srWindow.Top);
832: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1.1.1.12 root 833: SetConsoleScreenBufferSize(hStdout, csbi.dwSize);
1.1.1.14 root 834: SET_RECT(rect, 0, 0, csbi.srWindow.Right - csbi.srWindow.Left, csbi.srWindow.Bottom - csbi.srWindow.Top);
1.1.1.12 root 835: SetConsoleWindowInfo(hStdout, TRUE, &rect);
836: }
1.1.1.14 root 837: // hStdout (and all handles) will close in msdos_finish()...
838: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
839: SetConsoleCursorInfo(hStdout, &ci);
1.1.1.12 root 840: }
1.1 root 841: msdos_finish();
1.1.1.14 root 842:
1.1.1.8 root 843: timeEndPeriod(caps.wPeriodMin);
1.1.1.14 root 844: SetConsoleCtrlHandler(ctrl_handler, FALSE);
1.1 root 845: }
846:
1.1.1.10 root 847: hardware_finish();
848:
1.1 root 849: delete key_buf_char;
850: delete key_buf_scan;
851:
1.1.1.12 root 852: // SetConsoleTextAttribute(hStdout, csbi.wAttributes);
1.1 root 853:
854: return(retval);
855: }
856:
1.1.1.14 root 857: void change_console_size(int width, int height)
1.1.1.12 root 858: {
859: CONSOLE_SCREEN_BUFFER_INFO csbi;
860: SMALL_RECT rect;
861: COORD co;
862:
863: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 864: if(csbi.srWindow.Top != 0 || csbi.dwCursorPosition.Y > height - 1) {
865: if(csbi.srWindow.Right - csbi.srWindow.Left + 1 == width && csbi.srWindow.Bottom - csbi.srWindow.Top + 1 == height) {
866: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &csbi.srWindow);
867: SET_RECT(rect, 0, 0, width - 1, height - 1);
868: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
869: } else if(csbi.dwCursorPosition.Y > height - 1) {
870: SET_RECT(rect, 0, csbi.dwCursorPosition.Y - (height - 1), width - 1, csbi.dwCursorPosition.Y);
871: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
872: SET_RECT(rect, 0, 0, width - 1, height - 1);
873: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1.1.12 root 874: }
875: }
1.1.1.14 root 876: if(csbi.dwCursorPosition.Y > height - 1) {
1.1.1.12 root 877: co.X = csbi.dwCursorPosition.X;
1.1.1.14 root 878: co.Y = min(height - 1, csbi.dwCursorPosition.Y - csbi.srWindow.Top);
1.1.1.12 root 879: SetConsoleCursorPosition(hStdout, co);
880: cursor_moved = true;
881: }
1.1.1.14 root 882:
883: // window can't be bigger than buffer,
884: // buffer can't be smaller than window,
885: // so make a tiny window,
886: // set the required buffer,
887: // then set the required window
888: SET_RECT(rect, 0, csbi.srWindow.Top, 0, csbi.srWindow.Top);
1.1.1.12 root 889: SetConsoleWindowInfo(hStdout, TRUE, &rect);
1.1.1.14 root 890: co.X = width;
891: co.Y = height;
1.1.1.12 root 892: SetConsoleScreenBufferSize(hStdout, co);
1.1.1.14 root 893: SET_RECT(rect, 0, 0, width - 1, height - 1);
894: SetConsoleWindowInfo(hStdout, TRUE, &rect);
895:
896: scr_width = scr_buf_size.X = width;
897: scr_height = scr_buf_size.Y = height;
898: scr_top = 0;
899:
900: clear_scr_buffer(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
901:
902: int regen = min(scr_width * scr_height * 2, 0x8000);
1.1.1.15! root 903: text_vram_end_address = text_vram_top_address + regen;
! 904: shadow_buffer_end_address = shadow_buffer_top_address + regen;
! 905:
1.1.1.14 root 906: if(regen > 0x4000) {
907: regen = 0x8000;
908: vram_pages = 1;
909: } else if(regen > 0x2000) {
910: regen = 0x4000;
911: vram_pages = 2;
912: } else if(regen > 0x1000) {
913: regen = 0x2000;
914: vram_pages = 4;
915: } else {
916: regen = 0x1000;
917: vram_pages = 8;
918: }
1.1.1.15! root 919: *(UINT16 *)(mem + 0x44a) = scr_width;
! 920: *(UINT16 *)(mem + 0x44c) = regen;
! 921: *(UINT8 *)(mem + 0x484) = scr_height - 1;
! 922:
! 923: restore_console_on_exit = true;
1.1.1.14 root 924: }
925:
926: void clear_scr_buffer(WORD attr)
927: {
928: for(int y = 0; y < scr_height; y++) {
929: for(int x = 0; x < scr_width; x++) {
930: SCR_BUF(y,x).Char.AsciiChar = ' ';
931: SCR_BUF(y,x).Attributes = attr;
932: }
933: }
1.1.1.12 root 934: }
935:
1.1 root 936: /* ----------------------------------------------------------------------------
937: MS-DOS virtual machine
938: ---------------------------------------------------------------------------- */
939:
1.1.1.14 root 940: bool update_key_buffer_tmp()
1.1 root 941: {
1.1.1.8 root 942: DWORD dwNumberOfEvents = 0;
1.1 root 943: DWORD dwRead;
944: INPUT_RECORD ir[16];
945:
1.1.1.8 root 946: if(GetNumberOfConsoleInputEvents(hStdin, &dwNumberOfEvents) && dwNumberOfEvents != 0) {
947: if(ReadConsoleInputA(hStdin, ir, 16, &dwRead)) {
948: for(int i = 0; i < dwRead; i++) {
949: if((ir[i].EventType & KEY_EVENT) && ir[i].Event.KeyEvent.bKeyDown) {
1.1.1.14 root 950: UINT8 chr = ir[i].Event.KeyEvent.uChar.AsciiChar;
951: UINT8 scn = ir[i].Event.KeyEvent.wVirtualScanCode & 0xff;
952: if(chr == 0) {
953: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
954: if(scn >= 0x3b && scn <= 0x44) {
955: scn += 0x68 - 0x3b; // F1 to F10
956: } else if(scn == 0x57 || scn == 0x58) {
957: scn += 0x8b - 0x57; // F11 & F12
958: } else if(scn >= 0x47 && scn <= 0x53) {
959: scn += 0x97 - 0x47; // edit/arrow clusters
960: } else if(scn == 0x35) {
961: scn = 0xa4; // keypad /
962: }
963: } else if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
964: if(scn == 0x07) {
965: chr = 0x1e; // Ctrl+^
966: } else if(scn == 0x0c) {
967: chr = 0x1f; // Ctrl+_
968: } else if(scn >= 0x35 && scn <= 0x58) {
969: static const UINT8 ctrl_map[] = {
970: 0x95, // keypad /
971: 0,
972: 0x96, // keypad *
973: 0, 0, 0,
974: 0x5e, // F1
975: 0x5f, // F2
976: 0x60, // F3
977: 0x61, // F4
978: 0x62, // F5
979: 0x63, // F6
980: 0x64, // F7
981: 0x65, // F8
982: 0x66, // F9
983: 0x67, // F10
984: 0,
985: 0,
986: 0x77, // Home
987: 0x8d, // Up
988: 0x84, // PgUp
989: 0x8e, // keypad -
990: 0x73, // Left
991: 0x8f, // keypad center
992: 0x74, // Right
993: 0x90, // keyapd +
994: 0x75, // End
995: 0x91, // Down
996: 0x76, // PgDn
997: 0x92, // Insert
998: 0x93, // Delete
999: 0, 0, 0,
1000: 0x89, // F11
1001: 0x8a, // F12
1002: };
1003: scn = ctrl_map[scn - 0x35];
1004: }
1005: } else if(ir[i].Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
1006: if(scn >= 0x3b && scn <= 0x44) {
1007: scn += 0x54 - 0x3b; // F1 to F10
1008: } else if(scn == 0x57 || scn == 0x58) {
1009: scn += 0x87 - 0x57; // F11 & F12
1010: }
1011: } else if(scn == 0x57 || scn == 0x58) {
1012: scn += 0x85 - 0x57;
1013: }
1014: // ignore shift, ctrl, alt, win and menu keys
1015: if(scn != 0x1d && scn != 0x2a && scn != 0x36 && scn != 0x38 && (scn < 0x5b || scn > 0x5e)) {
1016: if(chr == 0) {
1017: key_buf_char->write(0x00);
1018: key_buf_scan->write(ir[i].Event.KeyEvent.dwControlKeyState & ENHANCED_KEY ? 0xe0 : 0x00);
1019: }
1020: key_buf_char->write(chr);
1021: key_buf_scan->write(scn);
1.1.1.8 root 1022: }
1023: } else {
1.1.1.14 root 1024: if(ir[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
1025: chr = 0;
1026: if(scn >= 0x02 && scn <= 0x0e) {
1027: scn += 0x78 - 0x02; // 1 to 0 - =
1028: }
1029: }
1030: key_buf_char->write(chr);
1031: key_buf_scan->write(scn);
1032: }
1033: }
1034: }
1035: for(int i = dwRead; --i >= 0;) {
1036: if((ir[i].EventType & KEY_EVENT)) {
1037: kbd_data = ir[i].Event.KeyEvent.wVirtualScanCode & 0x7f;
1038: if(!ir[i].Event.KeyEvent.bKeyDown) {
1039: kbd_data |= 0x80;
1.1 root 1040: }
1.1.1.14 root 1041: return true;
1.1 root 1042: }
1043: }
1044: }
1045: }
1.1.1.14 root 1046: return false;
1.1.1.8 root 1047: }
1048:
1.1.1.14 root 1049: bool update_key_buffer()
1.1.1.8 root 1050: {
1051: int prev_count = key_buf_char->count();
1.1.1.14 root 1052: bool input = update_key_buffer_tmp();
1.1.1.8 root 1053: key_input += key_buf_char->count() - prev_count;
1.1.1.14 root 1054: return(input || key_buf_char->count() != 0);
1.1 root 1055: }
1056:
1.1.1.8 root 1057: int check_key_input()
1058: {
1059: if(key_input == 0) {
1060: int prev_count = key_buf_char->count();
1.1.1.14 root 1061: bool input = update_key_buffer_tmp();
1.1.1.8 root 1062: key_input = key_buf_char->count() - prev_count;
1.1.1.14 root 1063: if(key_input == 0 && input) {
1064: key_input = 1;
1065: }
1.1.1.8 root 1066: }
1067: int val = key_input;
1068: key_input = 0;
1069: return(val);
1070: }
1071:
1.1 root 1072: // process info
1073:
1074: process_t *msdos_process_info_create(UINT16 psp_seg)
1075: {
1076: for(int i = 0; i < MAX_PROCESS; i++) {
1077: if(process[i].psp == 0 || process[i].psp == psp_seg) {
1078: memset(&process[i], 0, sizeof(process_t));
1079: process[i].psp = psp_seg;
1080: return(&process[i]);
1081: }
1082: }
1083: fatalerror("too many processes\n");
1084: return(NULL);
1085: }
1086:
1087: process_t *msdos_process_info_get(UINT16 psp_seg)
1088: {
1089: for(int i = 0; i < MAX_PROCESS; i++) {
1090: if(process[i].psp == psp_seg) {
1091: return(&process[i]);
1092: }
1093: }
1094: fatalerror("invalid psp address\n");
1095: return(NULL);
1096: }
1097:
1.1.1.13 root 1098: // dta info
1099:
1100: void msdos_dta_info_init()
1101: {
1.1.1.14 root 1102: for(int i = 0; i < MAX_DTAINFO; i++) {
1.1.1.13 root 1103: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
1104: }
1105: }
1106:
1107: dtainfo_t *msdos_dta_info_get(UINT16 psp_seg, UINT32 dta_laddr)
1108: {
1109: dtainfo_t *free_dta = NULL;
1.1.1.14 root 1110: for(int i = 0; i < MAX_DTAINFO; i++) {
1111: if(dtalist[i].find_handle == INVALID_HANDLE_VALUE) {
1112: if(free_dta == NULL) {
1.1.1.13 root 1113: free_dta = &dtalist[i];
1114: }
1.1.1.14 root 1115: } else if(dta_laddr < LFN_DTA_LADDR && dtalist[i].dta == dta_laddr) {
1.1.1.13 root 1116: return(&dtalist[i]);
1117: }
1118: }
1.1.1.14 root 1119: if(free_dta) {
1.1.1.13 root 1120: free_dta->psp = psp_seg;
1121: free_dta->dta = dta_laddr;
1122: return(free_dta);
1123: }
1124: fatalerror("too many dta\n");
1125: return(NULL);
1126: }
1127:
1128: void msdos_dta_info_free(UINT16 psp_seg)
1129: {
1.1.1.14 root 1130: for(int i = 0; i < MAX_DTAINFO; i++) {
1131: if(dtalist[i].psp == psp_seg && dtalist[i].find_handle != INVALID_HANDLE_VALUE) {
1.1.1.13 root 1132: FindClose(dtalist[i].find_handle);
1133: dtalist[i].find_handle = INVALID_HANDLE_VALUE;
1134: }
1135: }
1136: }
1137:
1.1 root 1138: void msdos_cds_update(int drv)
1139: {
1140: cds_t *cds = (cds_t *)(mem + CDS_TOP);
1141:
1142: memset(mem + CDS_TOP, 0, CDS_SIZE);
1143: sprintf(cds->path_name, "%c:\\", 'A' + drv);
1144: cds->drive_attrib = 0x4000; // physical drive
1145: cds->physical_drive_number = drv;
1146: }
1147:
1148: // dbcs
1149:
1150: void msdos_dbcs_table_update()
1151: {
1152: UINT8 dbcs_data[DBCS_SIZE];
1153: memset(dbcs_data, 0, sizeof(dbcs_data));
1154:
1155: CPINFO info;
1156: GetCPInfo(active_code_page, &info);
1157:
1158: if(info.MaxCharSize != 1) {
1159: for(int i = 0;; i += 2) {
1160: UINT8 lo = info.LeadByte[i + 0];
1161: UINT8 hi = info.LeadByte[i + 1];
1162: dbcs_data[2 + i + 0] = lo;
1163: dbcs_data[2 + i + 1] = hi;
1164: if(lo == 0 && hi == 0) {
1165: dbcs_data[0] = i + 2;
1166: break;
1167: }
1168: }
1169: } else {
1170: dbcs_data[0] = 2; // ???
1171: }
1172: memcpy(mem + DBCS_TOP, dbcs_data, sizeof(dbcs_data));
1173: }
1174:
1175: void msdos_dbcs_table_init()
1176: {
1177: system_code_page = active_code_page = _getmbcp();
1178: msdos_dbcs_table_update();
1179: }
1180:
1181: void msdos_dbcs_table_finish()
1182: {
1183: if(active_code_page != system_code_page) {
1184: _setmbcp(system_code_page);
1185: }
1186: }
1187:
1188: int msdos_lead_byte_check(UINT8 code)
1189: {
1190: UINT8 *dbcs_table = mem + DBCS_TABLE;
1191:
1192: for(int i = 0;; i += 2) {
1193: UINT8 lo = dbcs_table[i + 0];
1194: UINT8 hi = dbcs_table[i + 1];
1195: if(lo == 0 && hi == 0) {
1196: break;
1197: }
1198: if(lo <= code && code <= hi) {
1199: return(1);
1200: }
1201: }
1202: return(0);
1203: }
1204:
1205: // file control
1206:
1.1.1.14 root 1207: char *msdos_remove_double_quote(char *path)
1208: {
1209: static char tmp[MAX_PATH];
1210:
1211: memset(tmp, 0, sizeof(tmp));
1212: if(strlen(path) >= 2 && path[0] == '"' && path[strlen(path) - 1] == '"') {
1213: memcpy(tmp, path + 1, strlen(path) - 2);
1214: } else {
1215: strcpy(tmp, path);
1216: }
1217: return(tmp);
1218: }
1219:
1220: char *msdos_combine_path(char *dir, const char *file)
1221: {
1222: static char tmp[MAX_PATH];
1223: char *tmp_dir = msdos_remove_double_quote(dir);
1224:
1225: if(strlen(tmp_dir) == 0) {
1226: strcpy(tmp, file);
1227: } else if(tmp_dir[strlen(tmp_dir) - 1] == '\\') {
1228: sprintf(tmp, "%s%s", tmp_dir, file);
1229: } else {
1230: sprintf(tmp, "%s\\%s", tmp_dir, file);
1231: }
1232: return(tmp);
1233: }
1234:
1.1 root 1235: char *msdos_trimmed_path(char *path, int lfn)
1236: {
1237: static char tmp[MAX_PATH];
1238:
1239: if(lfn) {
1240: strcpy(tmp, path);
1241: } else {
1242: // remove space in the path
1243: char *src = path, *dst = tmp;
1244:
1245: while(*src != '\0') {
1246: if(msdos_lead_byte_check(*src)) {
1247: *dst++ = *src++;
1248: *dst++ = *src++;
1249: } else if(*src != ' ') {
1250: *dst++ = *src++;
1251: } else {
1252: src++; // skip space
1253: }
1254: }
1255: *dst = '\0';
1256: }
1.1.1.14 root 1257: if(_stricmp(tmp, "C:\\COMMAND.COM") == 0) {
1258: // redirect C:\COMMAND.COM to comspec_path
1259: strcpy(tmp, comspec_path);
1260: } else if(is_vista_or_later && _access(tmp, 0) != 0) {
1261: // redirect new files (without wildcards) in C:\ to %TEMP%, since C:\ is not usually writable
1262: static int root_drive_protected = -1;
1263: char temp[MAX_PATH], name[MAX_PATH], *name_temp = NULL;
1264: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
1265:
1266: if(GetFullPathName(tmp, MAX_PATH, temp, &name_temp) != 0 &&
1267: name_temp != NULL && strstr(name_temp, "?") == NULL && strstr(name_temp, "*") == NULL) {
1268: strcpy(name, name_temp);
1269: name_temp[0] = '\0';
1270:
1271: if((temp[0] == 'A' + dos_info->boot_drive - 1 || temp[0] == 'a' + dos_info->boot_drive - 1) &&
1272: (temp[1] == ':') && (temp[2] == '\\' || temp[2] == '/') && (temp[3] == '\0')) {
1273: if(root_drive_protected == -1) {
1274: FILE *fp = NULL;
1275:
1276: sprintf(temp, "%c:\\MS-DOS_Player.$$$", 'A' + dos_info->boot_drive - 1);
1277: root_drive_protected = 1;
1278: try {
1279: if((fp = fopen(temp, "w")) != NULL) {
1280: if(fprintf(fp, "TEST") == 4) {
1281: root_drive_protected = 0;
1282: }
1283: }
1284: } catch(...) {
1285: }
1286: if(fp != NULL) {
1287: fclose(fp);
1288: }
1289: if(_access(temp, 0) == 0) {
1290: remove(temp);
1291: }
1292: }
1293: if(root_drive_protected == 1) {
1294: if(GetEnvironmentVariable("TEMP", temp, MAX_PATH) != 0 ||
1295: GetEnvironmentVariable("TMP", temp, MAX_PATH) != 0) {
1296: strcpy(tmp, msdos_combine_path(temp, name));
1297: }
1298: }
1299: }
1300: }
1301: }
1.1 root 1302: return(tmp);
1303: }
1304:
1305: bool match(char *text, char *pattern)
1306: {
1307: //http://www.prefield.com/algorithm/string/wildcard.html
1.1.1.14 root 1308: switch(*pattern) {
1.1 root 1309: case '\0':
1310: return !*text;
1311: case '*':
1.1.1.14 root 1312: return match(text, pattern + 1) || (*text && match(text + 1, pattern));
1.1 root 1313: case '?':
1314: return *text && match(text + 1, pattern + 1);
1315: default:
1316: return (*text == *pattern) && match(text + 1, pattern + 1);
1317: }
1318: }
1319:
1320: bool msdos_match_volume_label(char *path, char *volume)
1321: {
1322: char *p;
1323:
1.1.1.14 root 1324: if(!*volume) {
1325: return false;
1326: } else if((p = my_strchr(path, ':')) != NULL) {
1.1 root 1327: return msdos_match_volume_label(p + 1, volume);
1328: } else if((p = my_strchr(path, '\\')) != NULL) {
1329: return msdos_match_volume_label(p + 1, volume);
1330: } else if((p = my_strchr(path, '.')) != NULL) {
1.1.1.14 root 1331: char tmp[MAX_PATH];
1332: sprintf(tmp, "%.*s%s", (int)(p - path), path, p + 1);
1333: return match(volume, tmp);
1.1 root 1334: } else {
1335: return match(volume, path);
1336: }
1337: }
1338:
1339: char *msdos_fcb_path(fcb_t *fcb)
1340: {
1341: static char tmp[MAX_PATH];
1342: char name[9], ext[4];
1343:
1344: memset(name, 0, sizeof(name));
1345: memcpy(name, fcb->file_name, 8);
1346: strcpy(name, msdos_trimmed_path(name, 0));
1347:
1348: memset(ext, 0, sizeof(ext));
1349: memcpy(ext, fcb->file_name + 8, 3);
1350: strcpy(ext, msdos_trimmed_path(ext, 0));
1351:
1352: if(name[0] == '\0' || strcmp(name, "????????") == 0) {
1353: strcpy(name, "*");
1354: }
1355: if(ext[0] == '\0') {
1356: strcpy(tmp, name);
1357: } else {
1358: if(strcmp(ext, "???") == 0) {
1359: strcpy(ext, "*");
1360: }
1361: sprintf(tmp, "%s.%s", name, ext);
1362: }
1363: return(tmp);
1364: }
1365:
1366: void msdos_set_fcb_path(fcb_t *fcb, char *path)
1367: {
1368: char *ext = my_strchr(path, '.');
1369:
1370: memset(fcb->file_name, 0x20, 8 + 3);
1371: if(ext != NULL && path[0] != '.') {
1372: *ext = '\0';
1373: memcpy(fcb->file_name + 8, ext + 1, strlen(ext + 1));
1374: }
1375: memcpy(fcb->file_name, path, strlen(path));
1376: }
1377:
1378: char *msdos_short_path(char *path)
1379: {
1380: static char tmp[MAX_PATH];
1381:
1382: GetShortPathName(path, tmp, MAX_PATH);
1383: my_strupr(tmp);
1384: return(tmp);
1385: }
1386:
1.1.1.13 root 1387: char *msdos_short_name(WIN32_FIND_DATA *fd)
1388: {
1389: static char tmp[MAX_PATH];
1390:
1.1.1.14 root 1391: if(fd->cAlternateFileName[0]) {
1.1.1.13 root 1392: strcpy(tmp, fd->cAlternateFileName);
1393: } else {
1394: strcpy(tmp, fd->cFileName);
1395: }
1396: my_strupr(tmp);
1397: return(tmp);
1398: }
1399:
1.1 root 1400: char *msdos_short_full_path(char *path)
1401: {
1402: static char tmp[MAX_PATH];
1403: char full[MAX_PATH], *name;
1404:
1.1.1.14 root 1405: // Full works with non-existent files, but Short does not
1.1 root 1406: GetFullPathName(path, MAX_PATH, full, &name);
1.1.1.14 root 1407: *tmp = '\0';
1408: if(GetShortPathName(full, tmp, MAX_PATH) == 0 && name > path) {
1409: name[-1] = '\0';
1410: DWORD len = GetShortPathName(full, tmp, MAX_PATH);
1411: if(len == 0) {
1412: strcpy(tmp, full);
1413: } else {
1414: tmp[len++] = '\\';
1415: strcpy(tmp + len, name);
1416: }
1417: }
1.1 root 1418: my_strupr(tmp);
1419: return(tmp);
1420: }
1421:
1422: char *msdos_short_full_dir(char *path)
1423: {
1424: static char tmp[MAX_PATH];
1425: char full[MAX_PATH], *name;
1426:
1427: GetFullPathName(path, MAX_PATH, full, &name);
1428: name[-1] = '\0';
1429: GetShortPathName(full, tmp, MAX_PATH);
1430: my_strupr(tmp);
1431: return(tmp);
1432: }
1433:
1434: char *msdos_local_file_path(char *path, int lfn)
1435: {
1436: char *trimmed = msdos_trimmed_path(path, lfn);
1.1.1.14 root 1437: #if 0
1438: // I have forgotten the reason of this routine... :-(
1.1 root 1439: if(_access(trimmed, 0) != 0) {
1440: process_t *process = msdos_process_info_get(current_psp);
1441: static char tmp[MAX_PATH];
1442:
1443: sprintf(tmp, "%s\\%s", process->module_dir, trimmed);
1444: if(_access(tmp, 0) == 0) {
1445: return(tmp);
1446: }
1447: }
1.1.1.14 root 1448: #endif
1.1 root 1449: return(trimmed);
1450: }
1451:
1.1.1.11 root 1452: bool msdos_is_con_path(char *path)
1453: {
1454: char full[MAX_PATH], *name;
1455:
1456: GetFullPathName(path, MAX_PATH, full, &name);
1457: return(_stricmp(full, "\\\\.\\CON") == 0);
1458: }
1459:
1.1.1.14 root 1460: bool msdos_is_nul_path(char *path)
1.1.1.8 root 1461: {
1.1.1.14 root 1462: char full[MAX_PATH], *name;
1.1.1.8 root 1463:
1.1.1.14 root 1464: GetFullPathName(path, MAX_PATH, full, &name);
1465: return(_stricmp(full, "\\\\.\\NUL") == 0);
1.1.1.8 root 1466: }
1467:
1.1.1.9 root 1468: char *msdos_search_command_com(char *command_path, char *env_path)
1469: {
1470: static char tmp[MAX_PATH];
1471: char path[MAX_PATH], *file_name;
1472:
1473: if(GetFullPathName(command_path, MAX_PATH, tmp, &file_name) != 0) {
1474: sprintf(file_name, "COMMAND.COM");
1475: if(_access(tmp, 0) == 0) {
1476: return(tmp);
1477: }
1478: }
1479: if(GetModuleFileName(NULL, path, MAX_PATH) != 0 && GetFullPathName(path, MAX_PATH, tmp, &file_name) != 0) {
1480: sprintf(file_name, "COMMAND.COM");
1481: if(_access(tmp, 0) == 0) {
1482: return(tmp);
1483: }
1484: }
1485: if(GetFullPathName("COMMAND.COM", MAX_PATH, tmp, &file_name) != 0) {
1486: if(_access(tmp, 0) == 0) {
1487: return(tmp);
1488: }
1489: }
1490: char *token = my_strtok(env_path, ";");
1491: while(token != NULL) {
1.1.1.14 root 1492: if(strlen(token) != 0 && token[0] != '%') {
1.1.1.9 root 1493: strcpy(tmp, msdos_combine_path(token, "COMMAND.COM"));
1494: if(_access(tmp, 0) == 0) {
1495: return(tmp);
1496: }
1497: }
1498: token = my_strtok(NULL, ";");
1499: }
1500: return(NULL);
1501: }
1502:
1.1.1.14 root 1503: int msdos_drive_number(const char *path)
1.1 root 1504: {
1505: char tmp[MAX_PATH], *name;
1506:
1507: GetFullPathName(path, MAX_PATH, tmp, &name);
1508: if(tmp[0] >= 'a' && tmp[0] <= 'z') {
1509: return(tmp[0] - 'a');
1510: } else {
1511: return(tmp[0] - 'A');
1512: }
1513: }
1514:
1515: char *msdos_volume_label(char *path)
1516: {
1517: static char tmp[MAX_PATH];
1518: char volume[] = "A:\\";
1519:
1520: if(path[1] == ':') {
1521: volume[0] = path[0];
1522: } else {
1523: volume[0] = 'A' + _getdrive() - 1;
1524: }
1525: if(!GetVolumeInformation(volume, tmp, MAX_PATH, NULL, NULL, NULL, NULL, 0)) {
1526: memset(tmp, 0, sizeof(tmp));
1527: }
1528: return(tmp);
1529: }
1530:
1531: char *msdos_short_volume_label(char *label)
1532: {
1533: static char tmp[(8 + 1 + 3) + 1];
1534: char *src = label;
1535: int remain = strlen(label);
1536: char *dst_n = tmp;
1537: char *dst_e = tmp + 9;
1538:
1539: strcpy(tmp, " . ");
1540: for(int i = 0; i < 8 && remain > 0; i++) {
1541: if(msdos_lead_byte_check(*src)) {
1542: if(++i == 8) {
1543: break;
1544: }
1545: *dst_n++ = *src++;
1546: remain--;
1547: }
1548: *dst_n++ = *src++;
1549: remain--;
1550: }
1551: if(remain > 0) {
1552: for(int i = 0; i < 3 && remain > 0; i++) {
1553: if(msdos_lead_byte_check(*src)) {
1554: if(++i == 3) {
1555: break;
1556: }
1557: *dst_e++ = *src++;
1558: remain--;
1559: }
1560: *dst_e++ = *src++;
1561: remain--;
1562: }
1563: *dst_e = '\0';
1564: } else {
1565: *dst_n = '\0';
1566: }
1567: my_strupr(tmp);
1568: return(tmp);
1569: }
1570:
1.1.1.13 root 1571: errno_t msdos_maperr(unsigned long oserrno)
1572: {
1573: _doserrno = oserrno;
1.1.1.14 root 1574: switch(oserrno) {
1.1.1.13 root 1575: case ERROR_FILE_NOT_FOUND: // 2
1576: case ERROR_PATH_NOT_FOUND: // 3
1577: case ERROR_INVALID_DRIVE: // 15
1578: case ERROR_NO_MORE_FILES: // 18
1579: case ERROR_BAD_NETPATH: // 53
1580: case ERROR_BAD_NET_NAME: // 67
1581: case ERROR_BAD_PATHNAME: // 161
1582: case ERROR_FILENAME_EXCED_RANGE: // 206
1583: return ENOENT;
1584: case ERROR_TOO_MANY_OPEN_FILES: // 4
1585: return EMFILE;
1586: case ERROR_ACCESS_DENIED: // 5
1587: case ERROR_CURRENT_DIRECTORY: // 16
1588: case ERROR_NETWORK_ACCESS_DENIED: // 65
1589: case ERROR_CANNOT_MAKE: // 82
1590: case ERROR_FAIL_I24: // 83
1591: case ERROR_DRIVE_LOCKED: // 108
1592: case ERROR_SEEK_ON_DEVICE: // 132
1593: case ERROR_NOT_LOCKED: // 158
1594: case ERROR_LOCK_FAILED: // 167
1595: return EACCES;
1596: case ERROR_INVALID_HANDLE: // 6
1597: case ERROR_INVALID_TARGET_HANDLE: // 114
1598: case ERROR_DIRECT_ACCESS_HANDLE: // 130
1599: return EBADF;
1600: case ERROR_ARENA_TRASHED: // 7
1601: case ERROR_NOT_ENOUGH_MEMORY: // 8
1602: case ERROR_INVALID_BLOCK: // 9
1603: case ERROR_NOT_ENOUGH_QUOTA: // 1816
1604: return ENOMEM;
1605: case ERROR_BAD_ENVIRONMENT: // 10
1606: return E2BIG;
1607: case ERROR_BAD_FORMAT: // 11
1608: return ENOEXEC;
1609: case ERROR_NOT_SAME_DEVICE: // 17
1610: return EXDEV;
1611: case ERROR_FILE_EXISTS: // 80
1612: case ERROR_ALREADY_EXISTS: // 183
1613: return EEXIST;
1614: case ERROR_NO_PROC_SLOTS: // 89
1615: case ERROR_MAX_THRDS_REACHED: // 164
1616: case ERROR_NESTING_NOT_ALLOWED: // 215
1617: return EAGAIN;
1618: case ERROR_BROKEN_PIPE: // 109
1619: return EPIPE;
1620: case ERROR_DISK_FULL: // 112
1621: return ENOSPC;
1622: case ERROR_WAIT_NO_CHILDREN: // 128
1623: case ERROR_CHILD_NOT_COMPLETE: // 129
1624: return ECHILD;
1625: case ERROR_DIR_NOT_EMPTY: // 145
1626: return ENOTEMPTY;
1627: }
1.1.1.14 root 1628: if(oserrno >= ERROR_WRITE_PROTECT /* 19 */ &&
1.1.1.13 root 1629: oserrno <= ERROR_SHARING_BUFFER_EXCEEDED /* 36 */) {
1630: return EACCES;
1631: }
1.1.1.14 root 1632: if(oserrno >= ERROR_INVALID_STARTING_CODESEG /* 188 */ &&
1.1.1.13 root 1633: oserrno <= ERROR_INFLOOP_IN_RELOC_CHAIN /* 202 */) {
1634: return ENOEXEC;
1635: }
1636: return EINVAL;
1637: }
1638:
1639: int msdos_open(const char *filename, int oflag)
1640: {
1.1.1.14 root 1641: if((oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) != _O_RDONLY) {
1.1.1.13 root 1642: return _open(filename, oflag);
1643: }
1.1.1.14 root 1644:
1645: SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, !(oflag & _O_NOINHERIT) };
1.1.1.13 root 1646: DWORD disposition;
1.1.1.14 root 1647: switch(oflag & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
1648: default:
1.1.1.13 root 1649: case _O_EXCL:
1650: disposition = OPEN_EXISTING;
1651: break;
1652: case _O_CREAT:
1653: disposition = OPEN_ALWAYS;
1654: break;
1655: case _O_CREAT | _O_EXCL:
1656: case _O_CREAT | _O_TRUNC | _O_EXCL:
1657: disposition = CREATE_NEW;
1658: break;
1659: case _O_TRUNC:
1660: case _O_TRUNC | _O_EXCL:
1661: disposition = TRUNCATE_EXISTING;
1662: break;
1663: case _O_CREAT | _O_TRUNC:
1664: disposition = CREATE_ALWAYS;
1665: break;
1666: }
1.1.1.14 root 1667:
1.1.1.13 root 1668: HANDLE h = CreateFile(filename, GENERIC_READ | FILE_WRITE_ATTRIBUTES,
1669: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
1670: FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.14 root 1671: if(h == INVALID_HANDLE_VALUE) {
1.1.1.13 root 1672: // FILE_WRITE_ATTRIBUTES may not be granted for standard users.
1673: // Retry without FILE_WRITE_ATTRIBUTES.
1674: h = CreateFile(filename, GENERIC_READ,
1675: FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, disposition,
1676: FILE_ATTRIBUTE_NORMAL, NULL);
1.1.1.14 root 1677: if(h == INVALID_HANDLE_VALUE) {
1.1.1.13 root 1678: errno = msdos_maperr(GetLastError());
1679: return -1;
1680: }
1681: }
1.1.1.14 root 1682:
1.1.1.13 root 1683: int fd = _open_osfhandle((intptr_t) h, oflag);
1.1.1.14 root 1684: if(fd == -1) {
1.1.1.13 root 1685: CloseHandle(h);
1686: }
1687: return fd;
1688: }
1689:
1.1.1.14 root 1690: void msdos_file_handler_open(int fd, const char *path, int atty, int mode, UINT16 info, UINT16 psp_seg)
1.1 root 1691: {
1692: static int id = 0;
1693: char full[MAX_PATH], *name;
1694:
1695: if(psp_seg && fd < 20) {
1696: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
1697: psp->file_table[fd] = fd;
1698: }
1699: if(GetFullPathName(path, MAX_PATH, full, &name) != 0) {
1700: strcpy(file_handler[fd].path, full);
1701: } else {
1702: strcpy(file_handler[fd].path, path);
1703: }
1.1.1.14 root 1704: // isatty makes no distinction between CON & NUL
1705: // GetFileSize fails on CON, succeeds on NUL
1706: if(atty && (info != 0x80d3 || GetFileSize((HANDLE)_get_osfhandle(fd), NULL) == 0)) {
1707: info = 0x8084;
1708: atty = 0;
1709: } else if(!atty && info == 0x80d3) {
1710: info = msdos_drive_number(".");
1711: }
1.1 root 1712: file_handler[fd].valid = 1;
1713: file_handler[fd].id = id++; // dummy id for int 21h ax=71a6h
1714: file_handler[fd].atty = atty;
1715: file_handler[fd].mode = mode;
1716: file_handler[fd].info = info;
1717: file_handler[fd].psp = psp_seg;
1718: }
1719:
1720: void msdos_file_handler_dup(int dst, int src, UINT16 psp_seg)
1721: {
1722: if(psp_seg && dst < 20) {
1723: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
1724: psp->file_table[dst] = dst;
1725: }
1726: strcpy(file_handler[dst].path, file_handler[src].path);
1727: file_handler[dst].valid = 1;
1728: file_handler[dst].id = file_handler[src].id;
1729: file_handler[dst].atty = file_handler[src].atty;
1730: file_handler[dst].mode = file_handler[src].mode;
1731: file_handler[dst].info = file_handler[src].info;
1732: file_handler[dst].psp = psp_seg;
1733: }
1734:
1735: void msdos_file_handler_close(int fd, UINT16 psp_seg)
1736: {
1737: if(psp_seg && fd < 20) {
1738: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
1739: psp->file_table[fd] = 0xff;
1740: }
1741: file_handler[fd].valid = 0;
1742: }
1743:
1.1.1.14 root 1744: inline int msdos_file_attribute_create(UINT16 new_attr)
1.1 root 1745: {
1.1.1.14 root 1746: return(new_attr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
1747: FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE |
1748: FILE_ATTRIBUTE_DIRECTORY));
1.1 root 1749: }
1750:
1751: // find file
1752:
1753: int msdos_find_file_check_attribute(int attribute, int allowed_mask, int required_mask)
1754: {
1755: if((allowed_mask & 0x08) && !(attribute & FILE_ATTRIBUTE_DIRECTORY)) {
1756: return(0); // search directory only !!!
1757: } else if(!(allowed_mask & 0x02) && (attribute & FILE_ATTRIBUTE_HIDDEN)) {
1758: return(0);
1759: } else if(!(allowed_mask & 0x04) && (attribute & FILE_ATTRIBUTE_SYSTEM)) {
1760: return(0);
1761: } else if(!(allowed_mask & 0x10) && (attribute & FILE_ATTRIBUTE_DIRECTORY)) {
1762: return(0);
1763: } else if((attribute & required_mask) != required_mask) {
1764: return(0);
1765: } else {
1766: return(1);
1767: }
1768: }
1769:
1.1.1.13 root 1770: int msdos_find_file_has_8dot3name(WIN32_FIND_DATA *fd)
1771: {
1.1.1.14 root 1772: if(fd->cAlternateFileName[0]) {
1.1.1.13 root 1773: return 1;
1774: }
1775: size_t len = strlen(fd->cFileName);
1.1.1.14 root 1776: if(len > 12) {
1.1.1.13 root 1777: return 0;
1778: }
1779: const char *ext = strrchr(fd->cFileName, '.');
1.1.1.14 root 1780: if((ext ? ext - fd->cFileName : len) > 8) {
1.1.1.13 root 1781: return 0;
1782: }
1783: return 1;
1784: }
1785:
1.1 root 1786: void msdos_find_file_conv_local_time(WIN32_FIND_DATA *fd)
1787: {
1788: FILETIME local;
1789:
1790: FileTimeToLocalFileTime(&fd->ftCreationTime, &local);
1791: fd->ftCreationTime.dwLowDateTime = local.dwLowDateTime;
1792: fd->ftCreationTime.dwHighDateTime = local.dwHighDateTime;
1793:
1794: FileTimeToLocalFileTime(&fd->ftLastAccessTime, &local);
1795: fd->ftLastAccessTime.dwLowDateTime = local.dwLowDateTime;
1796: fd->ftLastAccessTime.dwHighDateTime = local.dwHighDateTime;
1797:
1798: FileTimeToLocalFileTime(&fd->ftLastWriteTime, &local);
1799: fd->ftLastWriteTime.dwLowDateTime = local.dwLowDateTime;
1800: fd->ftLastWriteTime.dwHighDateTime = local.dwHighDateTime;
1801: }
1802:
1803: // i/o
1804:
1805: void msdos_putch(UINT8 data);
1806:
1807: void msdos_stdio_reopen()
1808: {
1809: if(!file_handler[0].valid) {
1810: _dup2(DUP_STDIN, 0);
1811: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
1812: }
1813: if(!file_handler[1].valid) {
1814: _dup2(DUP_STDOUT, 1);
1815: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
1816: }
1817: if(!file_handler[2].valid) {
1818: _dup2(DUP_STDERR, 2);
1819: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
1820: }
1821: }
1822:
1823: int msdos_kbhit()
1824: {
1825: msdos_stdio_reopen();
1826:
1827: if(!file_handler[0].atty) {
1828: // stdin is redirected to file
1829: return(eof(0) == 0);
1830: }
1831:
1832: // check keyboard status
1.1.1.5 root 1833: if(key_buf_char->count() != 0 || key_code != 0) {
1.1 root 1834: return(1);
1835: } else {
1836: return(_kbhit());
1837: }
1838: }
1839:
1840: int msdos_getch_ex(int echo)
1841: {
1842: static char prev = 0;
1843:
1844: msdos_stdio_reopen();
1845:
1846: if(!file_handler[0].atty) {
1847: // stdin is redirected to file
1848: retry:
1849: char data;
1850: if(_read(0, &data, 1) == 1) {
1851: char tmp = data;
1852: if(data == 0x0a) {
1853: if(prev == 0x0d) {
1854: goto retry; // CRLF -> skip LF
1855: } else {
1856: data = 0x0d; // LF only -> CR
1857: }
1858: }
1859: prev = tmp;
1860: return(data);
1861: }
1862: return(EOF);
1863: }
1864:
1865: // input from console
1.1.1.5 root 1866: int key_char, key_scan;
1867: if(key_code != 0) {
1868: key_char = (key_code >> 0) & 0xff;
1869: key_scan = (key_code >> 8) & 0xff;
1870: key_code >>= 16;
1871: } else {
1.1.1.14 root 1872: while(key_buf_char->count() == 0 && !m_halted) {
1873: if(!update_key_buffer()) {
1874: Sleep(10);
1875: }
1876: }
1877: if(m_halted) {
1878: // ctrl-c pressed - insert CR to terminate input loops
1879: key_char = 0x0d;
1880: key_scan = 0;
1881: } else {
1882: key_char = key_buf_char->read();
1883: key_scan = key_buf_scan->read();
1.1.1.5 root 1884: }
1.1 root 1885: }
1886: if(echo && key_char) {
1887: msdos_putch(key_char);
1888: }
1889: return key_char ? key_char : (key_scan != 0xe0) ? key_scan : 0;
1890: }
1891:
1892: inline int msdos_getch()
1893: {
1894: return(msdos_getch_ex(0));
1895: }
1896:
1897: inline int msdos_getche()
1898: {
1899: return(msdos_getch_ex(1));
1900: }
1901:
1902: int msdos_write(int fd, const void *buffer, unsigned int count)
1903: {
1904: static int is_cr = 0;
1905:
1906: if(fd == 1 && !file_handler[1].atty) {
1907: // CR+LF -> LF
1908: UINT8 *buf = (UINT8 *)buffer;
1909: for(unsigned int i = 0; i < count; i++) {
1910: UINT8 data = buf[i];
1911: if(is_cr) {
1912: if(data != 0x0a) {
1913: UINT8 tmp = 0x0d;
1914: _write(1, &tmp, 1);
1915: }
1916: _write(1, &data, 1);
1917: is_cr = 0;
1918: } else if(data == 0x0d) {
1919: is_cr = 1;
1920: } else {
1921: _write(1, &data, 1);
1922: }
1923: }
1924: return(count);
1925: }
1.1.1.14 root 1926: vram_flush();
1.1 root 1927: return(_write(fd, buffer, count));
1928: }
1929:
1930: void msdos_putch(UINT8 data)
1931: {
1932: static int p = 0;
1933: static int is_kanji = 0;
1934: static int is_esc = 0;
1935: static int stored_x;
1936: static int stored_y;
1937: static WORD stored_a;
1938: static char tmp[64];
1939:
1940: msdos_stdio_reopen();
1941:
1942: if(!file_handler[1].atty) {
1943: // stdout is redirected to file
1944: msdos_write(1, &data, 1);
1945: return;
1946: }
1947:
1948: // output to console
1949: tmp[p++] = data;
1950:
1.1.1.14 root 1951: vram_flush();
1952:
1.1 root 1953: if(is_kanji) {
1954: // kanji character
1955: is_kanji = 0;
1956: } else if(is_esc) {
1957: // escape sequense
1958: if((tmp[1] == ')' || tmp[1] == '(') && p == 3) {
1959: p = is_esc = 0;
1960: } else if(tmp[1] == '=' && p == 4) {
1961: COORD co;
1962: co.X = tmp[3] - 0x20;
1.1.1.14 root 1963: co.Y = tmp[2] - 0x20 + scr_top;
1.1 root 1964: SetConsoleCursorPosition(hStdout, co);
1965: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14 root 1966: mem[0x451 + mem[0x462] * 2] = co.Y - scr_top;
1.1 root 1967: cursor_moved = false;
1968: p = is_esc = 0;
1969: } else if((data >= 'a' && data <= 'z') || (data >= 'A' && data <= 'Z') || data == '*') {
1970: CONSOLE_SCREEN_BUFFER_INFO csbi;
1971: COORD co;
1972: GetConsoleScreenBufferInfo(hStdout, &csbi);
1973: co.X = csbi.dwCursorPosition.X;
1974: co.Y = csbi.dwCursorPosition.Y;
1975: WORD wAttributes = csbi.wAttributes;
1976:
1977: if(tmp[1] == 'D') {
1978: co.Y++;
1979: } else if(tmp[1] == 'E') {
1980: co.X = 0;
1981: co.Y++;
1982: } else if(tmp[1] == 'M') {
1983: co.Y--;
1984: } else if(tmp[1] == '*') {
1985: SMALL_RECT rect;
1.1.1.14 root 1986: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
1987: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1988: co.X = 0;
1989: co.Y = csbi.srWindow.Top;
1.1 root 1990: } else if(tmp[1] == '[') {
1991: int param[256], params = 0;
1992: memset(param, 0, sizeof(param));
1993: for(int i = 2; i < p; i++) {
1994: if(tmp[i] >= '0' && tmp[i] <= '9') {
1995: param[params] *= 10;
1996: param[params] += tmp[i] - '0';
1997: } else {
1998: params++;
1999: }
2000: }
2001: if(data == 'A') {
1.1.1.14 root 2002: co.Y -= (params == 0) ? 1 : param[0];
1.1 root 2003: } else if(data == 'B') {
1.1.1.14 root 2004: co.Y += (params == 0) ? 1 : param[0];
1.1 root 2005: } else if(data == 'C') {
1.1.1.14 root 2006: co.X += (params == 0) ? 1 : param[0];
1.1 root 2007: } else if(data == 'D') {
1.1.1.14 root 2008: co.X -= (params == 0) ? 1 : param[0];
1.1 root 2009: } else if(data == 'H' || data == 'f') {
1.1.1.14 root 2010: co.X = (param[1] == 0 ? 1 : param[1]) - 1;
2011: co.Y = (param[0] == 0 ? 1 : param[0]) - 1 + csbi.srWindow.Top;
1.1 root 2012: } else if(data == 'J') {
2013: SMALL_RECT rect;
1.1.1.14 root 2014: clear_scr_buffer(csbi.wAttributes);
1.1 root 2015: if(param[0] == 0) {
2016: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 2017: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2018: if(co.Y < csbi.srWindow.Bottom) {
2019: SET_RECT(rect, 0, co.Y + 1, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2020: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2021: }
2022: } else if(param[0] == 1) {
1.1.1.14 root 2023: if(co.Y > csbi.srWindow.Top) {
2024: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, co.Y - 1);
2025: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2026: }
2027: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14 root 2028: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2029: } else if(param[0] == 2) {
1.1.1.14 root 2030: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2031: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2032: co.X = co.Y = 0;
2033: }
2034: } else if(data == 'K') {
2035: SMALL_RECT rect;
1.1.1.14 root 2036: clear_scr_buffer(csbi.wAttributes);
1.1 root 2037: if(param[0] == 0) {
2038: SET_RECT(rect, co.X, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 2039: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2040: } else if(param[0] == 1) {
2041: SET_RECT(rect, 0, co.Y, co.X, co.Y);
1.1.1.14 root 2042: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2043: } else if(param[0] == 2) {
2044: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y);
1.1.1.14 root 2045: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2046: }
2047: } else if(data == 'L') {
2048: SMALL_RECT rect;
1.1.1.14 root 2049: if(params == 0) {
2050: param[0] = 1;
1.1 root 2051: }
1.1.1.14 root 2052: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2053: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2054: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2055: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2056: clear_scr_buffer(csbi.wAttributes);
1.1 root 2057: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, co.Y + param[0] - 1);
1.1.1.14 root 2058: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2059: co.X = 0;
2060: } else if(data == 'M') {
2061: SMALL_RECT rect;
1.1.1.14 root 2062: if(params == 0) {
2063: param[0] = 1;
2064: }
2065: if(co.Y + param[0] > csbi.srWindow.Bottom) {
2066: clear_scr_buffer(csbi.wAttributes);
2067: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2068: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 2069: } else {
1.1.1.14 root 2070: SET_RECT(rect, 0, co.Y + param[0], csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2071: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2072: SET_RECT(rect, 0, co.Y, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
2073: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
2074: clear_scr_buffer(csbi.wAttributes);
1.1 root 2075: }
2076: co.X = 0;
2077: } else if(data == 'h') {
2078: if(tmp[2] == '>' && tmp[3] == '5') {
2079: CONSOLE_CURSOR_INFO cur;
2080: GetConsoleCursorInfo(hStdout, &cur);
2081: if(cur.bVisible) {
2082: cur.bVisible = FALSE;
1.1.1.14 root 2083: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 2084: }
2085: }
2086: } else if(data == 'l') {
2087: if(tmp[2] == '>' && tmp[3] == '5') {
2088: CONSOLE_CURSOR_INFO cur;
2089: GetConsoleCursorInfo(hStdout, &cur);
2090: if(!cur.bVisible) {
2091: cur.bVisible = TRUE;
1.1.1.14 root 2092: // SetConsoleCursorInfo(hStdout, &cur);
1.1 root 2093: }
2094: }
2095: } else if(data == 'm') {
2096: wAttributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
2097: int reverse = 0, hidden = 0;
2098: for(int i = 0; i < params; i++) {
2099: if(param[i] == 1) {
2100: wAttributes |= FOREGROUND_INTENSITY;
2101: } else if(param[i] == 4) {
2102: wAttributes |= COMMON_LVB_UNDERSCORE;
2103: } else if(param[i] == 7) {
2104: reverse = 1;
2105: } else if(param[i] == 8 || param[i] == 16) {
2106: hidden = 1;
2107: } else if((param[i] >= 17 && param[i] <= 23) || (param[i] >= 30 && param[i] <= 37)) {
2108: wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
2109: if(param[i] >= 17 && param[i] <= 23) {
2110: param[i] -= 16;
2111: } else {
2112: param[i] -= 30;
2113: }
2114: if(param[i] & 1) {
2115: wAttributes |= FOREGROUND_RED;
2116: }
2117: if(param[i] & 2) {
2118: wAttributes |= FOREGROUND_GREEN;
2119: }
2120: if(param[i] & 4) {
2121: wAttributes |= FOREGROUND_BLUE;
2122: }
2123: } else if(param[i] >= 40 && param[i] <= 47) {
2124: wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
2125: if((param[i] - 40) & 1) {
2126: wAttributes |= BACKGROUND_RED;
2127: }
2128: if((param[i] - 40) & 2) {
2129: wAttributes |= BACKGROUND_GREEN;
2130: }
2131: if((param[i] - 40) & 4) {
2132: wAttributes |= BACKGROUND_BLUE;
2133: }
2134: }
2135: }
2136: if(reverse) {
2137: wAttributes &= ~0xff;
2138: wAttributes |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
2139: }
2140: if(hidden) {
2141: wAttributes &= ~0x0f;
2142: wAttributes |= (wAttributes >> 4) & 0x0f;
2143: }
2144: } else if(data == 'n') {
2145: if(param[0] == 6) {
2146: char tmp[16];
2147: sprintf(tmp, "\x1b[%d;%dR", co.Y + 1, co.X + 1);
2148: int len = strlen(tmp);
2149: for(int i = 0; i < len; i++) {
2150: key_buf_char->write(tmp[i]);
2151: key_buf_scan->write(0x00);
2152: }
2153: }
2154: } else if(data == 's') {
2155: stored_x = co.X;
2156: stored_y = co.Y;
2157: stored_a = wAttributes;
2158: } else if(data == 'u') {
2159: co.X = stored_x;
2160: co.Y = stored_y;
2161: wAttributes = stored_a;
2162: }
2163: }
2164: if(co.X < 0) {
2165: co.X = 0;
2166: } else if(co.X >= csbi.dwSize.X) {
2167: co.X = csbi.dwSize.X - 1;
2168: }
1.1.1.14 root 2169: if(co.Y < csbi.srWindow.Top) {
2170: co.Y = csbi.srWindow.Top;
2171: } else if(co.Y > csbi.srWindow.Bottom) {
2172: co.Y = csbi.srWindow.Bottom;
1.1 root 2173: }
2174: if(co.X != csbi.dwCursorPosition.X || co.Y != csbi.dwCursorPosition.Y) {
2175: SetConsoleCursorPosition(hStdout, co);
2176: mem[0x450 + mem[0x462] * 2] = co.X;
1.1.1.14 root 2177: mem[0x451 + mem[0x462] * 2] = co.Y - csbi.srWindow.Top;
1.1 root 2178: cursor_moved = false;
2179: }
2180: if(wAttributes != csbi.wAttributes) {
2181: SetConsoleTextAttribute(hStdout, wAttributes);
2182: }
2183: p = is_esc = 0;
2184: }
2185: return;
2186: } else {
2187: if(msdos_lead_byte_check(data)) {
2188: is_kanji = 1;
2189: return;
2190: } else if(data == 0x1b) {
2191: is_esc = 1;
2192: return;
2193: }
2194: }
1.1.1.14 root 2195: // tmp[p++] = '\0';
2196: // printf("%s", tmp);
2197: DWORD num;
2198: WriteConsole(hStdout, tmp, p, &num, NULL);
1.1 root 2199: p = 0;
1.1.1.14 root 2200:
1.1.1.15! root 2201: if(!restore_console_on_exit) {
! 2202: CONSOLE_SCREEN_BUFFER_INFO csbi;
! 2203: GetConsoleScreenBufferInfo(hStdout, &csbi);
! 2204: scr_top = csbi.srWindow.Top;
! 2205: }
1.1 root 2206: cursor_moved = true;
2207: }
2208:
2209: int msdos_aux_in()
2210: {
2211: #ifdef SUPPORT_AUX_PRN
2212: if(file_handler[3].valid && !eof(3)) {
2213: char data = 0;
2214: _read(3, &data, 1);
2215: return(data);
2216: } else {
2217: return(EOF);
2218: }
2219: #else
2220: return(0);
2221: #endif
2222: }
2223:
2224: void msdos_aux_out(char data)
2225: {
2226: #ifdef SUPPORT_AUX_PRN
2227: if(file_handler[3].valid) {
2228: msdos_write(3, &data, 1);
2229: }
2230: #endif
2231: }
2232:
2233: void msdos_prn_out(char data)
2234: {
2235: #ifdef SUPPORT_AUX_PRN
2236: if(file_handler[4].valid) {
2237: msdos_write(4, &data, 1);
2238: }
2239: #endif
2240: }
2241:
2242: // memory control
2243:
2244: mcb_t *msdos_mcb_create(int mcb_seg, UINT8 mz, UINT16 psp, UINT16 paragraphs)
2245: {
2246: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2247:
2248: mcb->mz = mz;
2249: mcb->psp = psp;
2250: mcb->paragraphs = paragraphs;
2251: return(mcb);
2252: }
2253:
2254: void msdos_mcb_check(mcb_t *mcb)
2255: {
2256: if(!(mcb->mz == 'M' || mcb->mz == 'Z')) {
2257: fatalerror("broken mcb\n");
2258: }
2259: }
2260:
2261: int msdos_mem_split(int seg, int paragraphs)
2262: {
2263: int mcb_seg = seg - 1;
2264: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2265: msdos_mcb_check(mcb);
2266:
2267: if(mcb->paragraphs > paragraphs) {
2268: int new_seg = mcb_seg + 1 + paragraphs;
2269: int new_paragraphs = mcb->paragraphs - paragraphs - 1;
2270:
2271: msdos_mcb_create(new_seg, mcb->mz, 0, new_paragraphs);
2272: mcb->mz = 'M';
2273: mcb->paragraphs = paragraphs;
2274: return(0);
2275: }
2276: return(-1);
2277: }
2278:
2279: void msdos_mem_merge(int seg)
2280: {
2281: int mcb_seg = seg - 1;
2282: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2283: msdos_mcb_check(mcb);
2284:
2285: while(1) {
2286: if(mcb->mz == 'Z') {
2287: break;
2288: }
2289: int next_seg = mcb_seg + 1 + mcb->paragraphs;
2290: mcb_t *next_mcb = (mcb_t *)(mem + (next_seg << 4));
2291: msdos_mcb_check(next_mcb);
2292:
2293: if(next_mcb->psp != 0) {
2294: break;
2295: }
2296: mcb->mz = next_mcb->mz;
2297: mcb->paragraphs += 1 + next_mcb->paragraphs;
2298: }
2299: }
2300:
1.1.1.8 root 2301: int msdos_mem_alloc(int mcb_seg, int paragraphs, int new_process)
1.1 root 2302: {
2303: while(1) {
2304: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2305:
1.1.1.14 root 2306: if(mcb->psp == 0) {
2307: msdos_mem_merge(mcb_seg + 1);
2308: } else {
2309: msdos_mcb_check(mcb);
2310: }
1.1.1.8 root 2311: if(!(new_process && mcb->mz != 'Z')) {
1.1 root 2312: if(mcb->psp == 0 && mcb->paragraphs >= paragraphs) {
2313: msdos_mem_split(mcb_seg + 1, paragraphs);
2314: mcb->psp = current_psp;
2315: return(mcb_seg + 1);
2316: }
2317: }
2318: if(mcb->mz == 'Z') {
2319: break;
2320: }
2321: mcb_seg += 1 + mcb->paragraphs;
2322: }
2323: return(-1);
2324: }
2325:
2326: int msdos_mem_realloc(int seg, int paragraphs, int *max_paragraphs)
2327: {
2328: int mcb_seg = seg - 1;
2329: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2330: msdos_mcb_check(mcb);
2331: int current_paragraphs = mcb->paragraphs;
2332:
2333: msdos_mem_merge(seg);
2334: if(paragraphs > mcb->paragraphs) {
1.1.1.14 root 2335: if(max_paragraphs) {
2336: *max_paragraphs = mcb->paragraphs;
2337: }
1.1 root 2338: msdos_mem_split(seg, current_paragraphs);
2339: return(-1);
2340: }
2341: msdos_mem_split(seg, paragraphs);
2342: return(0);
2343: }
2344:
2345: void msdos_mem_free(int seg)
2346: {
2347: int mcb_seg = seg - 1;
2348: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2349: msdos_mcb_check(mcb);
2350:
2351: mcb->psp = 0;
2352: msdos_mem_merge(seg);
2353: }
2354:
1.1.1.8 root 2355: int msdos_mem_get_free(int mcb_seg, int new_process)
1.1 root 2356: {
2357: int max_paragraphs = 0;
2358:
2359: while(1) {
2360: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2361: msdos_mcb_check(mcb);
2362:
1.1.1.8 root 2363: if(!(new_process && mcb->mz != 'Z')) {
1.1 root 2364: if(mcb->psp == 0 && mcb->paragraphs > max_paragraphs) {
2365: max_paragraphs = mcb->paragraphs;
2366: }
2367: }
2368: if(mcb->mz == 'Z') {
2369: break;
2370: }
2371: mcb_seg += 1 + mcb->paragraphs;
2372: }
1.1.1.14 root 2373: return(max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs);
1.1 root 2374: }
2375:
1.1.1.8 root 2376: int msdos_mem_get_last_mcb(int mcb_seg, UINT16 psp)
2377: {
2378: int last_seg = -1;
2379:
2380: while(1) {
2381: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
2382: msdos_mcb_check(mcb);
2383:
1.1.1.14 root 2384: if(mcb->psp == psp) {
1.1.1.8 root 2385: last_seg = mcb_seg;
2386: }
1.1.1.14 root 2387: if(mcb->mz == 'Z') {
2388: break;
2389: }
1.1.1.8 root 2390: mcb_seg += 1 + mcb->paragraphs;
2391: }
2392: return(last_seg);
2393: }
2394:
1.1 root 2395: // environment
2396:
2397: void msdos_env_set_argv(int env_seg, char *argv)
2398: {
2399: char *dst = (char *)(mem + (env_seg << 4));
2400:
2401: while(1) {
2402: if(dst[0] == 0) {
2403: break;
2404: }
2405: dst += strlen(dst) + 1;
2406: }
2407: *dst++ = 0; // end of environment
2408: *dst++ = 1; // top of argv[0]
2409: *dst++ = 0;
2410: memcpy(dst, argv, strlen(argv));
2411: dst += strlen(argv);
2412: *dst++ = 0;
2413: *dst++ = 0;
2414: }
2415:
2416: char *msdos_env_get_argv(int env_seg)
2417: {
2418: static char env[ENV_SIZE];
2419: char *src = env;
2420:
2421: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
2422: while(1) {
2423: if(src[0] == 0) {
2424: if(src[1] == 1) {
2425: return(src + 3);
2426: }
2427: break;
2428: }
2429: src += strlen(src) + 1;
2430: }
2431: return(NULL);
2432: }
2433:
2434: char *msdos_env_get(int env_seg, const char *name)
2435: {
2436: static char env[ENV_SIZE];
2437: char *src = env;
2438:
2439: memcpy(src, mem + (env_seg << 4), ENV_SIZE);
2440: while(1) {
2441: if(src[0] == 0) {
2442: break;
2443: }
2444: int len = strlen(src);
2445: char *n = my_strtok(src, "=");
2446: char *v = src + strlen(n) + 1;
2447:
2448: if(_stricmp(name, n) == 0) {
2449: return(v);
2450: }
2451: src += len + 1;
2452: }
2453: return(NULL);
2454: }
2455:
2456: void msdos_env_set(int env_seg, char *name, char *value)
2457: {
2458: char env[ENV_SIZE];
2459: char *src = env;
2460: char *dst = (char *)(mem + (env_seg << 4));
2461: char *argv = msdos_env_get_argv(env_seg);
2462: int done = 0;
2463:
2464: memcpy(src, dst, ENV_SIZE);
2465: memset(dst, 0, ENV_SIZE);
2466: while(1) {
2467: if(src[0] == 0) {
2468: break;
2469: }
2470: int len = strlen(src);
2471: char *n = my_strtok(src, "=");
2472: char *v = src + strlen(n) + 1;
2473: char tmp[1024];
2474:
2475: if(_stricmp(name, n) == 0) {
2476: sprintf(tmp, "%s=%s", n, value);
2477: done = 1;
2478: } else {
2479: sprintf(tmp, "%s=%s", n, v);
2480: }
2481: memcpy(dst, tmp, strlen(tmp));
2482: dst += strlen(tmp) + 1;
2483: src += len + 1;
2484: }
2485: if(!done) {
2486: char tmp[1024];
2487:
2488: sprintf(tmp, "%s=%s", name, value);
2489: memcpy(dst, tmp, strlen(tmp));
2490: dst += strlen(tmp) + 1;
2491: }
2492: if(argv) {
2493: *dst++ = 0; // end of environment
2494: *dst++ = 1; // top of argv[0]
2495: *dst++ = 0;
2496: memcpy(dst, argv, strlen(argv));
2497: dst += strlen(argv);
2498: *dst++ = 0;
2499: *dst++ = 0;
2500: }
2501: }
2502:
2503: // process
2504:
1.1.1.8 root 2505: psp_t *msdos_psp_create(int psp_seg, UINT16 mcb_seg, UINT16 parent_psp, UINT16 env_seg)
1.1 root 2506: {
2507: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
2508:
2509: memset(psp, 0, PSP_SIZE);
2510: psp->exit[0] = 0xcd;
2511: psp->exit[1] = 0x20;
1.1.1.8 root 2512: psp->first_mcb = mcb_seg;
1.1 root 2513: psp->far_call = 0xea;
2514: psp->cpm_entry.w.l = 0xfff1; // int 21h, retf
2515: psp->cpm_entry.w.h = 0xf000;
2516: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
2517: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
2518: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
2519: psp->parent_psp = parent_psp;
2520: for(int i = 0; i < 20; i++) {
2521: if(file_handler[i].valid) {
2522: psp->file_table[i] = i;
2523: } else {
2524: psp->file_table[i] = 0xff;
2525: }
2526: }
2527: psp->env_seg = env_seg;
2528: psp->stack.w.l = REG16(SP);
1.1.1.3 root 2529: psp->stack.w.h = SREG(SS);
1.1.1.14 root 2530: psp->file_table_size = 20;
2531: psp->file_table_ptr.w.l = 0x18;
2532: psp->file_table_ptr.w.h = psp_seg;
1.1 root 2533: psp->service[0] = 0xcd;
2534: psp->service[1] = 0x21;
2535: psp->service[2] = 0xcb;
2536: return(psp);
2537: }
2538:
2539: int msdos_process_exec(char *cmd, param_block_t *param, UINT8 al)
2540: {
2541: // load command file
2542: int fd = -1;
2543: int dos_command = 0;
1.1.1.4 root 2544: char command[MAX_PATH], path[MAX_PATH], opt[MAX_PATH], *name, name_tmp[MAX_PATH];
1.1 root 2545:
2546: int opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
2547: int opt_len = mem[opt_ofs];
2548: memset(opt, 0, sizeof(opt));
2549: memcpy(opt, mem + opt_ofs + 1, opt_len);
2550:
1.1.1.14 root 2551: if(strlen(cmd) >= 5 && _stricmp(&cmd[strlen(cmd) - 4], ".BAT") == 0) {
2552: // this is a batch file, run command.com
2553: char tmp[MAX_PATH];
2554: if(opt_len != 0) {
2555: sprintf(tmp, "/C %s %s", cmd, opt);
2556: } else {
2557: sprintf(tmp, "/C %s", cmd);
2558: }
2559: strcpy(opt, tmp);
2560: opt_len = strlen(opt);
2561: mem[opt_ofs] = opt_len;
2562: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
2563: strcpy(command, comspec_path);
2564: strcpy(name_tmp, "COMMAND.COM");
2565: } else {
2566: if(_stricmp(cmd, "C:\\COMMAND.COM") == 0) {
2567: // redirect C:\COMMAND.COM to comspec_path
2568: strcpy(command, comspec_path);
2569: } else {
2570: strcpy(command, cmd);
2571: }
2572: GetFullPathName(command, MAX_PATH, path, &name);
2573: memset(name_tmp, 0, sizeof(name_tmp));
2574: strcpy(name_tmp, name);
2575:
2576: // check command.com
2577: if(_stricmp(name, "COMMAND.COM") == 0 || _stricmp(name, "COMMAND") == 0) {
2578: if(opt_len == 0) {
2579: // process_t *current_process = msdos_process_info_get(current_psp);
2580: process_t *current_process = NULL;
2581: for(int i = 0; i < MAX_PROCESS; i++) {
2582: if(process[i].psp == current_psp) {
2583: current_process = &process[i];
2584: break;
2585: }
2586: }
2587: if(current_process != NULL) {
2588: param->cmd_line.dw = current_process->dta.dw;
2589: opt_ofs = (param->cmd_line.w.h << 4) + param->cmd_line.w.l;
2590: opt_len = mem[opt_ofs];
2591: memset(opt, 0, sizeof(opt));
2592: memcpy(opt, mem + opt_ofs + 1, opt_len);
2593: }
2594: }
2595: for(int i = 0; i < opt_len; i++) {
2596: if(opt[i] == ' ') {
2597: continue;
2598: }
2599: if(opt[i] == '/' && (opt[i + 1] == 'c' || opt[i + 1] == 'C') && opt[i + 2] == ' ') {
2600: for(int j = i + 3; j < opt_len; j++) {
2601: if(opt[j] == ' ') {
2602: continue;
2603: }
2604: char *token = my_strtok(opt + j, " ");
2605:
2606: if(strlen(token) >= 5 && _stricmp(&token[strlen(token) - 4], ".BAT") == 0) {
2607: // this is a batch file, okay to run command.com
2608: } else {
2609: // run program directly without command.com
2610: strcpy(command, token);
2611: char tmp[MAX_PATH];
2612: strcpy(tmp, token + strlen(token) + 1);
2613: strcpy(opt, tmp);
2614: opt_len = strlen(opt);
2615: mem[opt_ofs] = opt_len;
2616: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
2617: dos_command = 1;
2618: }
2619: break;
1.1 root 2620: }
2621: }
1.1.1.14 root 2622: break;
1.1 root 2623: }
2624: }
2625: }
2626:
2627: // load command file
2628: strcpy(path, command);
2629: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
2630: sprintf(path, "%s.COM", command);
2631: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
2632: sprintf(path, "%s.EXE", command);
2633: if((fd = _open(path, _O_RDONLY | _O_BINARY)) == -1) {
1.1.1.14 root 2634: sprintf(path, "%s.BAT", command);
2635: if(_access(path, 0) == 0) {
2636: // this is a batch file, run command.com
2637: char tmp[MAX_PATH];
2638: if(opt_len != 0) {
2639: sprintf(tmp, "/C %s %s", path, opt);
2640: } else {
2641: sprintf(tmp, "/C %s", path);
2642: }
2643: strcpy(opt, tmp);
2644: opt_len = strlen(opt);
2645: mem[opt_ofs] = opt_len;
2646: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
2647: strcpy(path, comspec_path);
2648: strcpy(name_tmp, "COMMAND.COM");
2649: fd = _open(path, _O_RDONLY | _O_BINARY);
2650: } else {
2651: // search path in parent environments
2652: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
2653: char *env = msdos_env_get(parent_psp->env_seg, "PATH");
2654: if(env != NULL) {
2655: char env_path[4096];
2656: strcpy(env_path, env);
2657: char *token = my_strtok(env_path, ";");
2658:
2659: while(token != NULL) {
2660: if(strlen(token) != 0) {
2661: sprintf(path, "%s", msdos_combine_path(token, command));
2662: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
2663: break;
2664: }
2665: sprintf(path, "%s.COM", msdos_combine_path(token, command));
2666: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
2667: break;
2668: }
2669: sprintf(path, "%s.EXE", msdos_combine_path(token, command));
2670: if((fd = _open(path, _O_RDONLY | _O_BINARY)) != -1) {
2671: break;
2672: }
2673: sprintf(path, "%s.BAT", msdos_combine_path(token, command));
2674: if(_access(path, 0) == 0) {
2675: // this is a batch file, run command.com
2676: char tmp[MAX_PATH];
2677: if(opt_len != 0) {
2678: sprintf(tmp, "/C %s %s", path, opt);
2679: } else {
2680: sprintf(tmp, "/C %s", path);
2681: }
2682: strcpy(opt, tmp);
2683: opt_len = strlen(opt);
2684: mem[opt_ofs] = opt_len;
2685: sprintf((char *)(mem + opt_ofs + 1), "%s\x0d", opt);
2686: strcpy(path, comspec_path);
2687: strcpy(name_tmp, "COMMAND.COM");
2688: fd = _open(path, _O_RDONLY | _O_BINARY);
2689: break;
2690: }
1.1.1.8 root 2691: }
1.1.1.14 root 2692: token = my_strtok(NULL, ";");
1.1 root 2693: }
2694: }
2695: }
2696: }
2697: }
2698: }
2699: if(fd == -1) {
2700: if(dos_command) {
2701: // may be dos command
2702: char tmp[MAX_PATH];
2703: sprintf(tmp, "%s %s", command, opt);
2704: system(tmp);
2705: return(0);
2706: } else {
2707: return(-1);
2708: }
2709: }
2710: _read(fd, file_buffer, sizeof(file_buffer));
2711: _close(fd);
2712:
2713: // copy environment
2714: int env_seg, psp_seg;
2715:
1.1.1.8 root 2716: if((env_seg = msdos_mem_alloc(first_mcb, ENV_SIZE >> 4, 1)) == -1) {
1.1 root 2717: return(-1);
2718: }
2719: if(param->env_seg == 0) {
2720: psp_t *parent_psp = (psp_t *)(mem + (current_psp << 4));
2721: memcpy(mem + (env_seg << 4), mem + (parent_psp->env_seg << 4), ENV_SIZE);
2722: } else {
2723: memcpy(mem + (env_seg << 4), mem + (param->env_seg << 4), ENV_SIZE);
2724: }
2725: msdos_env_set_argv(env_seg, msdos_short_full_path(path));
2726:
2727: // check exe header
2728: exe_header_t *header = (exe_header_t *)file_buffer;
1.1.1.8 root 2729: int paragraphs, free_paragraphs = msdos_mem_get_free(first_mcb, 1);
1.1 root 2730: UINT16 cs, ss, ip, sp;
2731:
2732: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
2733: // memory allocation
2734: int header_size = header->header_size * 16;
2735: int load_size = header->pages * 512 - header_size;
2736: if(header_size + load_size < 512) {
2737: load_size = 512 - header_size;
2738: }
2739: paragraphs = (PSP_SIZE + load_size) >> 4;
2740: if(paragraphs + header->min_alloc > free_paragraphs) {
2741: msdos_mem_free(env_seg);
2742: return(-1);
2743: }
2744: paragraphs += header->max_alloc ? header->max_alloc : header->min_alloc;
2745: if(paragraphs > free_paragraphs) {
2746: paragraphs = free_paragraphs;
2747: }
1.1.1.8 root 2748: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1 root 2749: msdos_mem_free(env_seg);
2750: return(-1);
2751: }
2752: // relocation
2753: int start_seg = psp_seg + (PSP_SIZE >> 4);
2754: for(int i = 0; i < header->relocations; i++) {
2755: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
2756: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
2757: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
2758: }
2759: memcpy(mem + (start_seg << 4), file_buffer + header_size, load_size);
2760: // segments
2761: cs = header->init_cs + start_seg;
2762: ss = header->init_ss + start_seg;
2763: ip = header->init_ip;
2764: sp = header->init_sp - 2; // for symdeb
2765: } else {
2766: // memory allocation
2767: paragraphs = free_paragraphs;
1.1.1.8 root 2768: if((psp_seg = msdos_mem_alloc(first_mcb, paragraphs, 1)) == -1) {
1.1 root 2769: msdos_mem_free(env_seg);
2770: return(-1);
2771: }
2772: int start_seg = psp_seg + (PSP_SIZE >> 4);
2773: memcpy(mem + (start_seg << 4), file_buffer, 0x10000 - PSP_SIZE);
2774: // segments
2775: cs = ss = psp_seg;
2776: ip = 0x100;
2777: sp = 0xfffe;
2778: }
2779:
2780: // create psp
1.1.1.3 root 2781: #if defined(HAS_I386)
2782: *(UINT16 *)(mem + 4 * 0x22 + 0) = m_eip;
2783: #else
2784: *(UINT16 *)(mem + 4 * 0x22 + 0) = m_pc - SREG_BASE(CS);
2785: #endif
2786: *(UINT16 *)(mem + 4 * 0x22 + 2) = SREG(CS);
1.1 root 2787: psp_t *psp = msdos_psp_create(psp_seg, psp_seg + paragraphs, current_psp, env_seg);
2788: memcpy(psp->fcb1, mem + (param->fcb1.w.h << 4) + param->fcb1.w.l, sizeof(psp->fcb1));
2789: memcpy(psp->fcb2, mem + (param->fcb2.w.h << 4) + param->fcb2.w.l, sizeof(psp->fcb2));
2790: memcpy(psp->buffer, mem + (param->cmd_line.w.h << 4) + param->cmd_line.w.l, sizeof(psp->buffer));
2791:
2792: mcb_t *mcb_env = (mcb_t *)(mem + ((env_seg - 1) << 4));
2793: mcb_t *mcb_psp = (mcb_t *)(mem + ((psp_seg - 1) << 4));
2794: mcb_psp->psp = mcb_env->psp = psp_seg;
2795:
1.1.1.4 root 2796: for(int i = 0; i < 8; i++) {
2797: if(name_tmp[i] == '.') {
2798: mcb_psp->prog_name[i] = '\0';
2799: break;
2800: } else if(i < 7 && msdos_lead_byte_check(name_tmp[i])) {
2801: mcb_psp->prog_name[i] = name_tmp[i];
2802: i++;
2803: mcb_psp->prog_name[i] = name_tmp[i];
2804: } else if(name_tmp[i] >= 'a' && name_tmp[i] <= 'z') {
2805: mcb_psp->prog_name[i] = name_tmp[i] - 'a' + 'A';
2806: } else {
2807: mcb_psp->prog_name[i] = name_tmp[i];
2808: }
2809: }
2810:
1.1 root 2811: // process info
2812: process_t *process = msdos_process_info_create(psp_seg);
2813: strcpy(process->module_dir, msdos_short_full_dir(path));
2814: process->dta.w.l = 0x80;
2815: process->dta.w.h = psp_seg;
2816: process->switchar = '/';
2817: process->max_files = 20;
2818: process->parent_int_10h_feh_called = int_10h_feh_called;
2819: process->parent_int_10h_ffh_called = int_10h_ffh_called;
1.1.1.14 root 2820: process->parent_ds = SREG(DS);
1.1 root 2821:
2822: current_psp = psp_seg;
2823:
2824: if(al == 0x00) {
2825: int_10h_feh_called = int_10h_ffh_called = false;
2826:
2827: // registers and segments
2828: REG16(AX) = REG16(BX) = 0x00;
2829: REG16(CX) = 0xff;
2830: REG16(DX) = psp_seg;
2831: REG16(SI) = ip;
2832: REG16(DI) = sp;
2833: REG16(SP) = sp;
1.1.1.3 root 2834: SREG(DS) = SREG(ES) = psp_seg;
2835: SREG(SS) = ss;
2836: i386_load_segment_descriptor(DS);
2837: i386_load_segment_descriptor(ES);
2838: i386_load_segment_descriptor(SS);
1.1 root 2839:
2840: *(UINT16 *)(mem + (ss << 4) + sp) = 0;
2841: i386_jmp_far(cs, ip);
2842: } else if(al == 0x01) {
2843: // copy ss:sp and cs:ip to param block
2844: param->sp = sp;
2845: param->ss = ss;
2846: param->ip = ip;
2847: param->cs = cs;
2848: }
2849: return(0);
2850: }
2851:
2852: void msdos_process_terminate(int psp_seg, int ret, int mem_free)
2853: {
2854: psp_t *psp = (psp_t *)(mem + (psp_seg << 4));
2855:
2856: *(UINT32 *)(mem + 4 * 0x22) = psp->int_22h.dw;
2857: *(UINT32 *)(mem + 4 * 0x23) = psp->int_23h.dw;
2858: *(UINT32 *)(mem + 4 * 0x24) = psp->int_24h.dw;
2859:
1.1.1.3 root 2860: SREG(SS) = psp->stack.w.h;
2861: i386_load_segment_descriptor(SS);
1.1 root 2862: REG16(SP) = psp->stack.w.l;
2863: i386_jmp_far(psp->int_22h.w.h, psp->int_22h.w.l);
2864:
2865: process_t *process = msdos_process_info_get(psp_seg);
2866: int_10h_feh_called = process->parent_int_10h_feh_called;
2867: int_10h_ffh_called = process->parent_int_10h_ffh_called;
1.1.1.14 root 2868: SREG(DS) = process->parent_ds;
2869: i386_load_segment_descriptor(DS);
1.1 root 2870:
2871: if(mem_free) {
1.1.1.8 root 2872: int mcb_seg;
2873: while((mcb_seg = msdos_mem_get_last_mcb(first_mcb, psp_seg)) != -1) {
2874: msdos_mem_free(mcb_seg + 1);
2875: }
2876: while((mcb_seg = msdos_mem_get_last_mcb(UMB_TOP >> 4, psp_seg)) != -1) {
2877: msdos_mem_free(mcb_seg + 1);
2878: }
1.1 root 2879:
2880: for(int i = 0; i < MAX_FILES; i++) {
2881: if(file_handler[i].valid && file_handler[i].psp == psp_seg) {
2882: _close(i);
2883: msdos_file_handler_close(i, psp_seg);
2884: }
2885: }
1.1.1.13 root 2886: msdos_dta_info_free(psp_seg);
1.1 root 2887: }
1.1.1.14 root 2888: msdos_stdio_reopen();
1.1 root 2889:
2890: memset(process, 0, sizeof(process_t));
2891:
2892: current_psp = psp->parent_psp;
2893: retval = ret;
2894: }
2895:
2896: // drive
2897:
2898: int msdos_drive_param_block_update(int drive_num, UINT16 *seg, UINT16 *ofs, int force_update)
2899: {
2900: *seg = DPB_TOP >> 4;
2901: *ofs = sizeof(dpb_t) * drive_num;
2902: dpb_t *dpb = (dpb_t *)(mem + (*seg << 4) + *ofs);
2903:
2904: if(!force_update && dpb->free_clusters != 0) {
2905: return(dpb->bytes_per_sector ? 1 : 0);
2906: }
2907: memset(dpb, 0, sizeof(dpb_t));
2908:
2909: int res = 0;
2910: char dev[64];
2911: sprintf(dev, "\\\\.\\%c:", 'A' + drive_num);
2912:
2913: HANDLE hFile = CreateFile(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
2914: if(hFile != INVALID_HANDLE_VALUE) {
2915: DISK_GEOMETRY geo;
2916: DWORD dwSize;
2917: if(DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geo, sizeof(geo), &dwSize, NULL)) {
2918: dpb->bytes_per_sector = (UINT16)geo.BytesPerSector;
2919: dpb->highest_sector_num = (UINT8)(geo.SectorsPerTrack - 1);
2920: dpb->highest_cluster_num = (UINT16)(geo.TracksPerCylinder * geo.Cylinders.QuadPart + 1);
1.1.1.14 root 2921: dpb->maximum_cluster_num = (UINT32)(geo.TracksPerCylinder * geo.Cylinders.QuadPart + 1);
1.1 root 2922: switch(geo.MediaType) {
2923: case F5_320_512: // floppy, double-sided, 8 sectors per track (320K)
2924: dpb->media_type = 0xff;
2925: break;
2926: case F5_160_512: // floppy, single-sided, 8 sectors per track (160K)
2927: dpb->media_type = 0xfe;
2928: break;
2929: case F5_360_512: // floppy, double-sided, 9 sectors per track (360K)
2930: dpb->media_type = 0xfd;
2931: break;
2932: case F5_180_512: // floppy, single-sided, 9 sectors per track (180K)
2933: dpb->media_type = 0xfc;
2934: break;
2935: case F5_1Pt2_512: // floppy, double-sided, 15 sectors per track (1.2M)
2936: case F3_720_512: // floppy, double-sided, 9 sectors per track (720K,3.5")
2937: dpb->media_type = 0xf9;
2938: break;
2939: case FixedMedia: // hard disk
2940: case RemovableMedia:
2941: dpb->media_type = 0xf8;
2942: break;
2943: default:
2944: dpb->media_type = 0xf0;
2945: break;
2946: }
2947: res = 1;
2948: }
2949: dpb->drive_num = drive_num;
2950: dpb->unit_num = drive_num;
2951: dpb->next_dpb_ofs = *ofs + sizeof(dpb_t);
2952: dpb->next_dpb_seg = *seg;
1.1.1.14 root 2953: dpb->info_sector = 0xffff;
2954: dpb->backup_boot_sector = 0xffff;
1.1 root 2955: dpb->free_clusters = 0xffff;
1.1.1.14 root 2956: dpb->free_search_cluster = 0xffffffff;
1.1 root 2957: CloseHandle(hFile);
2958: }
2959: return(res);
2960: }
2961:
2962: // pc bios
2963:
1.1.1.14 root 2964: inline void pcbios_irq0()
2965: {
2966: //++*(UINT32 *)(mem + 0x46c);
2967: *(UINT32 *)(mem + 0x46c) = get_ticks_since_midnight();
2968: }
2969:
1.1.1.8 root 2970: int get_text_vram_address(int page)
1.1 root 2971: {
2972: if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 2973: return TEXT_VRAM_TOP;
1.1 root 2974: } else {
1.1.1.14 root 2975: return TEXT_VRAM_TOP + VIDEO_REGEN * (page % vram_pages);
1.1 root 2976: }
2977: }
2978:
1.1.1.8 root 2979: int get_shadow_buffer_address(int page)
1.1 root 2980: {
1.1.1.14 root 2981: if(!int_10h_feh_called) {
2982: return get_text_vram_address(page);
2983: } else if(/*mem[0x449] == 0x03 || */mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 2984: return SHADOW_BUF_TOP;
2985: } else {
1.1.1.14 root 2986: return SHADOW_BUF_TOP + VIDEO_REGEN * (page % vram_pages);
1.1.1.8 root 2987: }
2988: }
2989:
2990: inline int get_shadow_buffer_address(int page, int x, int y)
2991: {
1.1.1.14 root 2992: return get_shadow_buffer_address(page) + (x + y * scr_width) * 2;
1.1 root 2993: }
2994:
1.1.1.14 root 2995: inline void pcbios_int_10h_00h(int height)
1.1 root 2996: {
1.1.1.14 root 2997: // clear the existing screen, not just the new one
2998: int clr_height = max(height, scr_height);
2999:
3000: if(scr_width != 80 || scr_height != height) {
3001: change_console_size(80, height);
3002: mem[0x44a] = 80;
3003: mem[0x484] = height - 1;
3004: }
1.1 root 3005: mem[0x449] = REG8(AL) & 0x7f;
1.1.1.14 root 3006: mem[0x462] = 0;
3007: *(UINT16 *)(mem + 0x44e) = 0;
3008:
3009: text_vram_top_address = get_text_vram_address(0);
3010: text_vram_end_address = text_vram_top_address + scr_width * height * 2;
3011: shadow_buffer_top_address = get_shadow_buffer_address(0);
3012: shadow_buffer_end_address = shadow_buffer_top_address + scr_width * height * 2;
1.1 root 3013:
3014: if(REG8(AL) & 0x80) {
3015: mem[0x487] |= 0x80;
3016: } else {
1.1.1.14 root 3017: mem[0x487] &= ~0x80;
3018: for(int ofs = shadow_buffer_top_address; ofs < shadow_buffer_end_address;) {
3019: mem[ofs++] = 0x20;
3020: mem[ofs++] = 0x07;
3021: }
3022:
3023: EnterCriticalSection(&vram_crit_sect);
3024: for(int y = 0; y < clr_height; y++) {
3025: for(int x = 0; x < scr_width; x++) {
3026: SCR_BUF(y,x).Char.AsciiChar = ' ';
3027: SCR_BUF(y,x).Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
1.1 root 3028: }
3029: }
3030: SMALL_RECT rect;
1.1.1.14 root 3031: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + clr_height - 1);
3032: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
3033: vram_length_char = vram_last_length_char = 0;
3034: vram_length_attr = vram_last_length_attr = 0;
3035: LeaveCriticalSection(&vram_crit_sect);
1.1 root 3036: }
1.1.1.14 root 3037: COORD co;
3038: co.X = 0;
3039: co.Y = scr_top;
3040: SetConsoleCursorPosition(hStdout, co);
3041: cursor_moved = true;
3042: SetConsoleTextAttribute(hStdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
1.1 root 3043: }
3044:
3045: inline void pcbios_int_10h_01h()
3046: {
1.1.1.13 root 3047: mem[0x460] = REG8(CL);
3048: mem[0x461] = REG8(CH);
1.1.1.14 root 3049:
3050: CONSOLE_CURSOR_INFO ci;
3051: GetConsoleCursorInfo(hStdout, &ci);
3052: // ci.bVisible = !(REG8(CH) & 0x60) && REG8(CH) <= REG8(CL);
3053: // if(ci.bVisible) {
3054: int lines = max(8, REG8(CL) + 1);
3055: ci.dwSize = (REG8(CL) - REG8(CH) + 1) * 100 / lines;
3056: // }
3057: SetConsoleCursorInfo(hStdout, &ci);
1.1 root 3058: }
3059:
3060: inline void pcbios_int_10h_02h()
3061: {
1.1.1.14 root 3062: // continuously setting the cursor effectively stops it blinking
3063: if(mem[0x462] == REG8(BH) && (REG8(DL) != mem[0x450 + REG8(BH) * 2] || REG8(DH) != mem[0x451 + REG8(BH) * 2])) {
1.1 root 3064: COORD co;
3065: co.X = REG8(DL);
1.1.1.14 root 3066: co.Y = REG8(DH) + scr_top;
3067:
3068: // some programs hide the cursor by moving it off screen
3069: static bool hidden = false;
3070: CONSOLE_CURSOR_INFO ci;
3071: GetConsoleCursorInfo(hStdout, &ci);
3072:
3073: if(REG8(DH) >= scr_height || !SetConsoleCursorPosition(hStdout, co)) {
3074: if(ci.bVisible) {
3075: ci.bVisible = FALSE;
3076: // SetConsoleCursorInfo(hStdout, &ci);
3077: hidden = true;
3078: }
3079: } else if(hidden) {
3080: if(!ci.bVisible) {
3081: ci.bVisible = TRUE;
3082: // SetConsoleCursorInfo(hStdout, &ci);
3083: }
3084: hidden = false;
3085: }
1.1 root 3086: }
1.1.1.14 root 3087: mem[0x450 + (REG8(BH) % vram_pages) * 2] = REG8(DL);
3088: mem[0x451 + (REG8(BH) % vram_pages) * 2] = REG8(DH);
1.1 root 3089: }
3090:
3091: inline void pcbios_int_10h_03h()
3092: {
1.1.1.14 root 3093: REG8(DL) = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3094: REG8(DH) = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 3095: REG8(CL) = mem[0x460];
3096: REG8(CH) = mem[0x461];
3097: }
3098:
3099: inline void pcbios_int_10h_05h()
3100: {
1.1.1.14 root 3101: if(REG8(AL) >= vram_pages) {
3102: return;
3103: }
3104: if(mem[0x462] != REG8(AL)) {
3105: vram_flush();
3106:
1.1 root 3107: SMALL_RECT rect;
1.1.1.14 root 3108: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
3109: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3110:
1.1.1.14 root 3111: for(int y = 0, ofs = get_shadow_buffer_address(mem[0x462]); y < scr_height; y++) {
3112: for(int x = 0; x < scr_width; x++) {
3113: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
3114: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 3115: }
3116: }
1.1.1.14 root 3117: for(int y = 0, ofs = get_shadow_buffer_address(REG8(AL)); y < scr_height; y++) {
3118: for(int x = 0; x < scr_width; x++) {
3119: SCR_BUF(y,x).Char.AsciiChar = mem[ofs++];
3120: SCR_BUF(y,x).Attributes = mem[ofs++];
1.1 root 3121: }
3122: }
1.1.1.14 root 3123: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3124:
3125: COORD co;
1.1.1.14 root 3126: co.X = mem[0x450 + REG8(AL) * 2];
3127: co.Y = mem[0x451 + REG8(AL) * 2] + scr_top;
3128: if(co.Y < scr_top + scr_height) {
3129: SetConsoleCursorPosition(hStdout, co);
3130: }
1.1 root 3131: }
1.1.1.14 root 3132: mem[0x462] = REG8(AL);
3133: *(UINT16 *)(mem + 0x44e) = REG8(AL) * VIDEO_REGEN;
3134: int regen = min(scr_width * scr_height * 2, 0x8000);
1.1.1.8 root 3135: text_vram_top_address = get_text_vram_address(mem[0x462]);
1.1.1.14 root 3136: text_vram_end_address = text_vram_top_address + regen;
1.1.1.8 root 3137: shadow_buffer_top_address = get_shadow_buffer_address(mem[0x462]);
1.1.1.14 root 3138: shadow_buffer_end_address = shadow_buffer_top_address + regen;
1.1 root 3139: }
3140:
3141: inline void pcbios_int_10h_06h()
3142: {
1.1.1.14 root 3143: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
3144: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
3145: return;
3146: }
3147: vram_flush();
3148:
1.1 root 3149: SMALL_RECT rect;
1.1.1.14 root 3150: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
3151: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
3152:
3153: int right = min(REG8(DL), scr_width - 1);
3154: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 3155:
3156: if(REG8(AL) == 0) {
1.1.1.14 root 3157: for(int y = REG8(CH); y <= bottom; y++) {
3158: for(int x = REG8(CL), ofs = get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
3159: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
3160: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3161: }
3162: }
3163: } else {
1.1.1.14 root 3164: for(int y = REG8(CH), y2 = min(REG8(CH) + REG8(AL), bottom + 1); y <= bottom; y++, y2++) {
3165: for(int x = REG8(CL), ofs = get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
3166: if(y2 <= bottom) {
3167: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 3168: } else {
1.1.1.14 root 3169: SCR_BUF(y,x).Char.AsciiChar = ' ';
3170: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3171: }
1.1.1.14 root 3172: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
3173: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 3174: }
3175: }
3176: }
1.1.1.14 root 3177: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3178: }
3179:
3180: inline void pcbios_int_10h_07h()
3181: {
1.1.1.14 root 3182: if(REG8(CH) >= scr_height || REG8(CH) > REG8(DH) ||
3183: REG8(CL) >= scr_width || REG8(CL) > REG8(DL)) {
3184: return;
3185: }
3186: vram_flush();
3187:
1.1 root 3188: SMALL_RECT rect;
1.1.1.14 root 3189: SET_RECT(rect, 0, scr_top, scr_width - 1, scr_top + scr_height - 1);
3190: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
3191:
3192: int right = min(REG8(DL), scr_width - 1);
3193: int bottom = min(REG8(DH), scr_height - 1);
1.1 root 3194:
3195: if(REG8(AL) == 0) {
1.1.1.14 root 3196: for(int y = REG8(CH); y <= bottom; y++) {
3197: for(int x = REG8(CL), ofs = get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
3198: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar = ' ';
3199: mem[ofs++] = SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3200: }
3201: }
3202: } else {
1.1.1.14 root 3203: for(int y = bottom, y2 = max(REG8(CH) - 1, bottom - REG8(AL)); y >= REG8(CH); y--, y2--) {
3204: for(int x = REG8(CL), ofs = get_shadow_buffer_address(mem[0x462], REG8(CL), y); x <= right; x++) {
3205: if(y2 >= REG8(CH)) {
3206: SCR_BUF(y,x) = SCR_BUF(y2,x);
1.1 root 3207: } else {
1.1.1.14 root 3208: SCR_BUF(y,x).Char.AsciiChar = ' ';
3209: SCR_BUF(y,x).Attributes = REG8(BH);
1.1 root 3210: }
1.1.1.14 root 3211: mem[ofs++] = SCR_BUF(y,x).Char.AsciiChar;
3212: mem[ofs++] = SCR_BUF(y,x).Attributes;
1.1 root 3213: }
3214: }
3215: }
1.1.1.14 root 3216: WriteConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
1.1 root 3217: }
3218:
3219: inline void pcbios_int_10h_08h()
3220: {
3221: COORD co;
3222: DWORD num;
3223:
1.1.1.14 root 3224: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3225: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
1.1 root 3226:
3227: if(mem[0x462] == REG8(BH)) {
1.1.1.14 root 3228: co.Y += scr_top;
3229: vram_flush();
1.1 root 3230: ReadConsoleOutputCharacter(hStdout, scr_char, 1, co, &num);
3231: ReadConsoleOutputAttribute(hStdout, scr_attr, 1, co, &num);
3232: REG8(AL) = scr_char[0];
3233: REG8(AH) = scr_attr[0];
3234: } else {
1.1.1.8 root 3235: REG16(AX) = *(UINT16 *)(mem + get_shadow_buffer_address(REG8(BH), co.X, co.Y));
1.1 root 3236: }
3237: }
3238:
3239: inline void pcbios_int_10h_09h()
3240: {
3241: COORD co;
3242:
1.1.1.14 root 3243: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3244: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
3245:
3246: int dest = get_shadow_buffer_address(REG8(BH), co.X, co.Y);
3247: int end = min(dest + REG16(CX) * 2, get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 3248:
3249: if(mem[0x462] == REG8(BH)) {
1.1.1.14 root 3250: EnterCriticalSection(&vram_crit_sect);
3251: int vram = get_shadow_buffer_address(REG8(BH));
3252: while(dest < end) {
3253: write_text_vram_char(dest - vram, REG8(AL));
3254: mem[dest++] = REG8(AL);
3255: write_text_vram_attr(dest - vram, REG8(BL));
3256: mem[dest++] = REG8(BL);
1.1 root 3257: }
1.1.1.14 root 3258: LeaveCriticalSection(&vram_crit_sect);
1.1 root 3259: } else {
1.1.1.14 root 3260: while(dest < end) {
1.1 root 3261: mem[dest++] = REG8(AL);
3262: mem[dest++] = REG8(BL);
3263: }
3264: }
3265: }
3266:
3267: inline void pcbios_int_10h_0ah()
3268: {
3269: COORD co;
3270:
1.1.1.14 root 3271: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3272: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
3273:
3274: int dest = get_shadow_buffer_address(REG8(BH), co.X, co.Y);
3275: int end = min(dest + REG16(CX) * 2, get_shadow_buffer_address(REG8(BH), 0, scr_height));
1.1 root 3276:
3277: if(mem[0x462] == REG8(BH)) {
1.1.1.14 root 3278: EnterCriticalSection(&vram_crit_sect);
3279: int vram = get_shadow_buffer_address(REG8(BH));
3280: while(dest < end) {
3281: write_text_vram_char(dest - vram, REG8(AL));
3282: mem[dest++] = REG8(AL);
3283: dest++;
1.1 root 3284: }
1.1.1.14 root 3285: LeaveCriticalSection(&vram_crit_sect);
1.1 root 3286: } else {
1.1.1.14 root 3287: while(dest < end) {
1.1 root 3288: mem[dest++] = REG8(AL);
3289: dest++;
3290: }
3291: }
3292: }
3293:
3294: inline void pcbios_int_10h_0eh()
3295: {
1.1.1.14 root 3296: DWORD num;
3297: COORD co;
3298:
3299: co.X = mem[0x450 + (REG8(BH) % vram_pages) * 2];
3300: co.Y = mem[0x451 + (REG8(BH) % vram_pages) * 2];
3301:
3302: if(REG8(AL) == 7) {
3303: //MessageBeep(-1);
3304: } else if(REG8(AL) == 8 || REG8(AL) == 10 || REG8(AL) == 13) {
3305: if(REG8(AL) == 10) {
3306: vram_flush();
3307: }
3308: WriteConsole(hStdout, ®8(AL), 1, &num, NULL);
3309: cursor_moved = true;
3310: } else {
3311: int dest = get_shadow_buffer_address(REG8(BH), co.X, co.Y);
3312: if(mem[0x462] == REG8(BH)) {
3313: EnterCriticalSection(&vram_crit_sect);
3314: int vram = get_shadow_buffer_address(REG8(BH));
3315: write_text_vram_char(dest - vram, REG8(AL));
3316: LeaveCriticalSection(&vram_crit_sect);
3317:
3318: if(++co.X == scr_width) {
3319: co.X = 0;
3320: if(++co.Y == scr_height) {
3321: vram_flush();
3322: WriteConsole(hStdout, "\n", 1, &num, NULL);
3323: cursor_moved = true;
3324: }
3325: }
3326: if(!cursor_moved) {
3327: co.Y += scr_top;
3328: SetConsoleCursorPosition(hStdout, co);
3329: cursor_moved = true;
3330: }
3331: }
3332: mem[dest] = REG8(AL);
3333: }
1.1 root 3334: }
3335:
3336: inline void pcbios_int_10h_0fh()
3337: {
3338: REG8(AL) = mem[0x449];
3339: REG8(AH) = mem[0x44a];
3340: REG8(BH) = mem[0x462];
3341: }
3342:
1.1.1.14 root 3343: inline void pcbios_int_10h_11h()
3344: {
3345: switch(REG8(AL)) {
3346: case 0x11:
3347: pcbios_int_10h_00h(28);
3348: break;
3349: case 0x12:
3350: pcbios_int_10h_00h(50);
3351: break;
3352: case 0x14:
3353: pcbios_int_10h_00h(25);
3354: break;
3355: case 0x30:
3356: SREG(ES) = 0;
3357: i386_load_segment_descriptor(ES);
3358: REG16(BP) = 0;
3359: REG16(CX) = mem[0x485];
3360: REG8(DL) = mem[0x484];
3361: break;
3362: }
3363: }
3364:
3365: inline void pcbios_int_10h_12h()
3366: {
3367: if(REG8(BL) == 0x10) {
3368: REG16(BX) = 0x0003;
3369: REG16(CX) = 0x0009;
3370: }
3371: }
3372:
1.1 root 3373: inline void pcbios_int_10h_13h()
3374: {
1.1.1.3 root 3375: int ofs = SREG_BASE(ES) + REG16(BP);
1.1 root 3376: COORD co;
3377: DWORD num;
3378:
3379: co.X = REG8(DL);
1.1.1.14 root 3380: co.Y = REG8(DH) + scr_top;
3381:
3382: vram_flush();
1.1 root 3383:
3384: switch(REG8(AL)) {
3385: case 0x00:
3386: case 0x01:
3387: if(mem[0x462] == REG8(BH)) {
3388: CONSOLE_SCREEN_BUFFER_INFO csbi;
3389: GetConsoleScreenBufferInfo(hStdout, &csbi);
3390: SetConsoleCursorPosition(hStdout, co);
3391:
3392: if(csbi.wAttributes != REG8(BL)) {
3393: SetConsoleTextAttribute(hStdout, REG8(BL));
3394: }
1.1.1.14 root 3395: WriteConsole(hStdout, &mem[ofs], REG16(CX), &num, NULL);
3396:
1.1 root 3397: if(csbi.wAttributes != REG8(BL)) {
3398: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
3399: }
3400: if(REG8(AL) == 0x00) {
1.1.1.15! root 3401: if(!restore_console_on_exit) {
! 3402: GetConsoleScreenBufferInfo(hStdout, &csbi);
! 3403: scr_top = csbi.srWindow.Top;
! 3404: }
1.1.1.14 root 3405: co.X = mem[0x450 + REG8(BH) * 2];
3406: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 3407: SetConsoleCursorPosition(hStdout, co);
3408: } else {
3409: cursor_moved = true;
3410: }
3411: } else {
1.1.1.3 root 3412: m_CF = 1;
1.1 root 3413: }
3414: break;
3415: case 0x02:
3416: case 0x03:
3417: if(mem[0x462] == REG8(BH)) {
3418: CONSOLE_SCREEN_BUFFER_INFO csbi;
3419: GetConsoleScreenBufferInfo(hStdout, &csbi);
3420: SetConsoleCursorPosition(hStdout, co);
3421:
3422: WORD wAttributes = csbi.wAttributes;
3423: for(int i = 0; i < REG16(CX); i++, ofs += 2) {
3424: if(wAttributes != mem[ofs + 1]) {
3425: SetConsoleTextAttribute(hStdout, mem[ofs + 1]);
3426: wAttributes = mem[ofs + 1];
3427: }
1.1.1.14 root 3428: WriteConsole(hStdout, &mem[ofs], 1, &num, NULL);
1.1 root 3429: }
3430: if(csbi.wAttributes != wAttributes) {
3431: SetConsoleTextAttribute(hStdout, csbi.wAttributes);
3432: }
3433: if(REG8(AL) == 0x02) {
1.1.1.14 root 3434: co.X = mem[0x450 + REG8(BH) * 2];
3435: co.Y = mem[0x451 + REG8(BH) * 2] + scr_top;
1.1 root 3436: SetConsoleCursorPosition(hStdout, co);
3437: } else {
3438: cursor_moved = true;
3439: }
3440: } else {
1.1.1.3 root 3441: m_CF = 1;
1.1 root 3442: }
3443: break;
3444: case 0x10:
3445: case 0x11:
3446: if(mem[0x462] == REG8(BH)) {
3447: ReadConsoleOutputCharacter(hStdout, scr_char, REG16(CX), co, &num);
3448: ReadConsoleOutputAttribute(hStdout, scr_attr, REG16(CX), co, &num);
3449: for(int i = 0; i < num; i++) {
3450: mem[ofs++] = scr_char[i];
3451: mem[ofs++] = scr_attr[i];
3452: if(REG8(AL) == 0x11) {
3453: mem[ofs++] = 0;
3454: mem[ofs++] = 0;
3455: }
3456: }
3457: } else {
1.1.1.14 root 3458: for(int i = 0, src = get_shadow_buffer_address(REG8(BH), co.X, co.Y - scr_top); i < REG16(CX); i++) {
1.1 root 3459: mem[ofs++] = mem[src++];
3460: mem[ofs++] = mem[src++];
3461: if(REG8(AL) == 0x11) {
3462: mem[ofs++] = 0;
3463: mem[ofs++] = 0;
3464: }
1.1.1.14 root 3465: if(++co.X == scr_width) {
3466: if(++co.Y == scr_height) {
1.1 root 3467: break;
3468: }
3469: co.X = 0;
3470: }
3471: }
3472: }
3473: break;
3474: case 0x20:
3475: case 0x21:
3476: if(mem[0x462] == REG8(BH)) {
1.1.1.14 root 3477: int len = min(REG16(CX), scr_width * scr_height);
3478: for(int i = 0; i < len; i++) {
1.1 root 3479: scr_char[i] = mem[ofs++];
3480: scr_attr[i] = mem[ofs++];
3481: if(REG8(AL) == 0x21) {
3482: ofs += 2;
3483: }
3484: }
1.1.1.14 root 3485: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
3486: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 3487: } else {
1.1.1.14 root 3488: for(int i = 0, dest = get_shadow_buffer_address(REG8(BH), co.X, co.Y - scr_top); i < REG16(CX); i++) {
1.1 root 3489: mem[dest++] = mem[ofs++];
3490: mem[dest++] = mem[ofs++];
3491: if(REG8(AL) == 0x21) {
3492: ofs += 2;
3493: }
1.1.1.14 root 3494: if(++co.X == scr_width) {
3495: if(++co.Y == scr_height) {
1.1 root 3496: break;
3497: }
3498: co.X = 0;
3499: }
3500: }
3501: }
3502: break;
3503: default:
1.1.1.3 root 3504: m_CF = 1;
1.1 root 3505: break;
3506: }
3507: }
3508:
1.1.1.14 root 3509: inline void pcbios_int_10h_1ah()
3510: {
3511: switch(REG8(AL)) {
3512: case 0x00:
3513: REG8(AL) = 0x1a;
3514: REG8(BL) = 0x08;
3515: REG8(BH) = 0x00;
3516: break;
3517: default:
3518: m_CF = 1;
3519: break;
3520: }
3521: }
3522:
1.1 root 3523: inline void pcbios_int_10h_1dh()
3524: {
3525: switch(REG8(AL)) {
3526: case 0x01:
3527: break;
3528: case 0x02:
3529: REG16(BX) = 0;
3530: break;
3531: default:
1.1.1.3 root 3532: m_CF = 1;
1.1 root 3533: break;
3534: }
3535: }
3536:
3537: inline void pcbios_int_10h_82h()
3538: {
3539: static UINT8 mode = 0;
3540:
3541: switch(REG8(AL)) {
3542: case 0:
3543: if(REG8(BL) != 0xff) {
3544: mode = REG8(BL);
3545: }
3546: REG8(AL) = mode;
3547: break;
3548: default:
1.1.1.3 root 3549: m_CF = 1;
1.1 root 3550: break;
3551: }
3552: }
3553:
3554: inline void pcbios_int_10h_feh()
3555: {
3556: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
1.1.1.8 root 3557: SREG(ES) = (SHADOW_BUF_TOP >> 4);
1.1.1.3 root 3558: i386_load_segment_descriptor(ES);
1.1.1.8 root 3559: REG16(DI) = (SHADOW_BUF_TOP & 0x0f);
1.1 root 3560: }
3561: int_10h_feh_called = true;
3562: }
3563:
3564: inline void pcbios_int_10h_ffh()
3565: {
3566: if(mem[0x449] == 0x03 || mem[0x449] == 0x70 || mem[0x449] == 0x71 || mem[0x449] == 0x73) {
3567: COORD co;
3568: DWORD num;
3569:
1.1.1.14 root 3570: vram_flush();
3571:
3572: co.X = (REG16(DI) >> 1) % scr_width;
3573: co.Y = (REG16(DI) >> 1) / scr_width;
3574: int ofs = get_shadow_buffer_address(0, co.X, co.Y);
3575: int end = min(ofs + REG16(CX) * 2, get_shadow_buffer_address(0, 0, scr_height));
3576: int len;
3577: for(len = 0; ofs < end; len++) {
3578: scr_char[len] = mem[ofs++];
3579: scr_attr[len] = mem[ofs++];
3580: }
3581: co.Y += scr_top;
3582: WriteConsoleOutputCharacter(hStdout, scr_char, len, co, &num);
3583: WriteConsoleOutputAttribute(hStdout, scr_attr, len, co, &num);
1.1 root 3584: }
3585: int_10h_ffh_called = true;
3586: }
3587:
1.1.1.14 root 3588: inline void pcbios_int_15h_10h()
3589: {
3590: if(REG8(AL) == 0) {
3591: Sleep(10);
3592: hardware_update();
3593: } else {
3594: REG8(AH) = 0x86;
3595: m_CF = 1;
3596: }
3597: }
3598:
1.1 root 3599: inline void pcbios_int_15h_23h()
3600: {
3601: switch(REG8(AL)) {
3602: case 0:
1.1.1.8 root 3603: REG8(CL) = cmos_read(0x2d);
3604: REG8(CH) = cmos_read(0x2e);
1.1 root 3605: break;
3606: case 1:
1.1.1.8 root 3607: cmos_write(0x2d, REG8(CL));
3608: cmos_write(0x2e, REG8(CH));
1.1 root 3609: break;
3610: default:
3611: REG8(AH) = 0x86;
1.1.1.3 root 3612: m_CF = 1;
1.1 root 3613: break;
3614: }
3615: }
3616:
3617: inline void pcbios_int_15h_24h()
3618: {
3619: switch(REG8(AL)) {
3620: case 0:
1.1.1.3 root 3621: i386_set_a20_line(0);
1.1 root 3622: REG8(AH) = 0;
3623: break;
3624: case 1:
1.1.1.3 root 3625: i386_set_a20_line(1);
1.1 root 3626: REG8(AH) = 0;
3627: break;
3628: case 2:
3629: REG8(AH) = 0;
1.1.1.3 root 3630: REG8(AL) = (m_a20_mask >> 20) & 1;
1.1 root 3631: REG16(CX) = 0;
3632: break;
3633: case 3:
3634: REG16(AX) = 0;
3635: REG16(BX) = 0;
3636: break;
3637: }
3638: }
3639:
3640: inline void pcbios_int_15h_49h()
3641: {
1.1.1.14 root 3642: REG8(AH) = 0;
3643: REG8(BL) = 0; // DOS/V
1.1 root 3644: }
3645:
3646: inline void pcbios_int_15h_86h()
3647: {
3648: UINT32 usec = (REG16(CX) << 16) | REG16(DX);
1.1.1.14 root 3649: UINT32 msec = usec / 1000;
3650:
3651: while(msec) {
3652: UINT32 tmp = min(msec, 100);
3653: if(msec - tmp < 10) {
3654: tmp = msec;
3655: }
3656: Sleep(tmp);
3657:
3658: if(m_halted) {
3659: return;
3660: }
3661: msec -= tmp;
3662: }
1.1 root 3663: }
3664:
3665: inline void pcbios_int_15h_87h()
3666: {
3667: // copy extended memory (from DOSBox)
3668: int len = REG16(CX) * 2;
1.1.1.3 root 3669: int ofs = SREG_BASE(ES) + REG16(SI);
1.1 root 3670: int src = (*(UINT32 *)(mem + ofs + 0x12) & 0xffffff); // + (mem[ofs + 0x16] << 24);
3671: int dst = (*(UINT32 *)(mem + ofs + 0x1a) & 0xffffff); // + (mem[ofs + 0x1e] << 24);
3672: memcpy(mem + dst, mem + src, len);
3673: REG16(AX) = 0x00;
3674: }
3675:
3676: inline void pcbios_int_15h_88h()
3677: {
3678: REG16(AX) = ((min(MAX_MEM, 0x1000000) - 0x100000) >> 10);
3679: }
3680:
3681: inline void pcbios_int_15h_89h()
3682: {
1.1.1.3 root 3683: #if defined(HAS_I386) || defined(HAS_I286)
1.1 root 3684: // switch to protected mode (from DOSBox)
3685: write_io_byte(0x20, 0x10);
3686: write_io_byte(0x21, REG8(BH));
3687: write_io_byte(0x21, 0x00);
3688: write_io_byte(0xa0, 0x10);
3689: write_io_byte(0xa1, REG8(BL));
3690: write_io_byte(0xa1, 0x00);
1.1.1.3 root 3691: i386_set_a20_line(1);
3692: int ofs = SREG_BASE(ES) + REG16(SI);
3693: m_gdtr.limit = *(UINT16 *)(mem + ofs + 0x08);
3694: m_gdtr.base = *(UINT32 *)(mem + ofs + 0x08 + 0x02) & 0xffffff;
3695: m_idtr.limit = *(UINT16 *)(mem + ofs + 0x10);
3696: m_idtr.base = *(UINT32 *)(mem + ofs + 0x10 + 0x02) & 0xffffff;
3697: #if defined(HAS_I386)
3698: m_cr[0] |= 1;
3699: #else
3700: m_msw |= 1;
3701: #endif
3702: SREG(DS) = 0x18;
3703: SREG(ES) = 0x20;
3704: SREG(SS) = 0x28;
3705: i386_load_segment_descriptor(DS);
3706: i386_load_segment_descriptor(ES);
3707: i386_load_segment_descriptor(SS);
1.1 root 3708: REG16(SP) += 6;
1.1.1.3 root 3709: #if defined(HAS_I386)
3710: set_flags(0); // ???
3711: #else
3712: m_flags = 2;
3713: ExpandFlags(m_flags);
3714: #endif
1.1 root 3715: REG16(AX) = 0x00;
3716: i386_jmp_far(0x30, REG16(CX));
3717: #else
3718: REG8(AH) = 0x86;
1.1.1.3 root 3719: m_CF = 1;
1.1 root 3720: #endif
3721: }
3722:
1.1.1.3 root 3723: #if defined(HAS_I386)
1.1 root 3724: inline void pcbios_int_15h_c9h()
3725: {
3726: REG8(AH) = 0x00;
3727: REG8(CH) = cpu_type;
3728: REG8(CL) = cpu_step;
3729: }
1.1.1.3 root 3730: #endif
1.1 root 3731:
3732: inline void pcbios_int_15h_cah()
3733: {
3734: switch(REG8(AL)) {
3735: case 0:
3736: if(REG8(BL) > 0x3f) {
3737: REG8(AH) = 0x03;
1.1.1.3 root 3738: m_CF = 1;
1.1 root 3739: } else if(REG8(BL) < 0x0e) {
3740: REG8(AH) = 0x04;
1.1.1.3 root 3741: m_CF = 1;
1.1 root 3742: } else {
1.1.1.8 root 3743: REG8(CL) = cmos_read(REG8(BL));
1.1 root 3744: }
3745: break;
3746: case 1:
3747: if(REG8(BL) > 0x3f) {
3748: REG8(AH) = 0x03;
1.1.1.3 root 3749: m_CF = 1;
1.1 root 3750: } else if(REG8(BL) < 0x0e) {
3751: REG8(AH) = 0x04;
1.1.1.3 root 3752: m_CF = 1;
1.1 root 3753: } else {
1.1.1.8 root 3754: cmos_write(REG8(BL), REG8(CL));
1.1 root 3755: }
3756: break;
3757: default:
3758: REG8(AH) = 0x86;
1.1.1.3 root 3759: m_CF = 1;
1.1 root 3760: break;
3761: }
3762: }
3763:
3764: UINT32 get_key_code(bool clear_buffer)
3765: {
3766: UINT32 code = 0;
3767:
3768: if(key_buf_char->count() == 0) {
1.1.1.14 root 3769: if(!update_key_buffer()) {
3770: if(clear_buffer) {
3771: Sleep(10);
3772: } else {
3773: maybe_idle();
3774: }
3775: }
1.1 root 3776: }
3777: if(!clear_buffer) {
3778: key_buf_char->store_buffer();
3779: key_buf_scan->store_buffer();
3780: }
3781: if(key_buf_char->count() != 0) {
3782: code = key_buf_char->read() | (key_buf_scan->read() << 8);
3783: }
3784: if(key_buf_char->count() != 0) {
3785: code |= (key_buf_char->read() << 16) | (key_buf_scan->read() << 24);
3786: }
3787: if(!clear_buffer) {
3788: key_buf_char->restore_buffer();
3789: key_buf_scan->restore_buffer();
3790: }
3791: return code;
3792: }
3793:
3794: inline void pcbios_int_16h_00h()
3795: {
1.1.1.14 root 3796: while(key_code == 0 && !m_halted) {
1.1 root 3797: key_code = get_key_code(true);
3798: }
3799: if((key_code & 0xffff) == 0x0000 || (key_code & 0xffff) == 0xe000) {
3800: if(REG8(AH) == 0x10) {
3801: key_code = ((key_code >> 8) & 0xff) | ((key_code >> 16) & 0xff00);
3802: } else {
3803: key_code = ((key_code >> 16) & 0xff00);
3804: }
3805: }
3806: REG16(AX) = key_code & 0xffff;
3807: key_code >>= 16;
3808: }
3809:
3810: inline void pcbios_int_16h_01h()
3811: {
1.1.1.5 root 3812: UINT32 key_code_tmp = key_code;
1.1 root 3813:
1.1.1.5 root 3814: if(key_code_tmp == 0) {
3815: key_code_tmp = get_key_code(false);
3816: }
1.1.1.14 root 3817: if((key_code_tmp & 0xffff) == 0x0000 || (key_code_tmp & 0xffff) == 0xe000) {
3818: if(REG8(AH) == 0x11) {
3819: key_code_tmp = ((key_code_tmp >> 8) & 0xff) | ((key_code_tmp >> 16) & 0xff00);
3820: } else {
3821: key_code_tmp = ((key_code_tmp >> 16) & 0xff00);
1.1 root 3822: }
3823: }
1.1.1.5 root 3824: if(key_code_tmp != 0) {
3825: REG16(AX) = key_code_tmp & 0xffff;
1.1 root 3826: }
1.1.1.3 root 3827: #if defined(HAS_I386)
1.1.1.5 root 3828: m_ZF = (key_code_tmp == 0);
1.1.1.3 root 3829: #else
1.1.1.5 root 3830: m_ZeroVal = (key_code_tmp != 0);
1.1.1.3 root 3831: #endif
1.1 root 3832: }
3833:
3834: inline void pcbios_int_16h_02h()
3835: {
3836: REG8(AL) = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
3837: REG8(AL) |= (GetAsyncKeyState(VK_CAPITAL) & 0x0001) ? 0x40 : 0;
3838: REG8(AL) |= (GetAsyncKeyState(VK_NUMLOCK) & 0x0001) ? 0x20 : 0;
3839: REG8(AL) |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
3840: REG8(AL) |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
3841: REG8(AL) |= (GetAsyncKeyState(VK_CONTROL) & 0x8000) ? 0x04 : 0;
3842: REG8(AL) |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
3843: REG8(AL) |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
3844: }
3845:
3846: inline void pcbios_int_16h_03h()
3847: {
3848: static UINT16 status = 0;
3849:
3850: switch(REG8(AL)) {
3851: case 0x05:
3852: status = REG16(BX);
3853: break;
3854: case 0x06:
3855: REG16(BX) = status;
3856: break;
3857: default:
1.1.1.3 root 3858: m_CF = 1;
1.1 root 3859: break;
3860: }
3861: }
3862:
3863: inline void pcbios_int_16h_05h()
3864: {
1.1.1.14 root 3865: key_buf_char->write(REG8(CL));
3866: key_buf_scan->write(REG8(CH));
1.1 root 3867: REG8(AL) = 0x00;
3868: }
3869:
3870: inline void pcbios_int_16h_12h()
3871: {
3872: pcbios_int_16h_02h();
3873:
3874: REG8(AH) = 0;//(GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x80 : 0;
3875: REG8(AH) |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
3876: REG8(AH) |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
3877: REG8(AH) |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
3878: REG8(AH) |= (GetAsyncKeyState(VK_RMENU ) & 0x8000) ? 0x08 : 0;
3879: REG8(AH) |= (GetAsyncKeyState(VK_RCONTROL) & 0x8000) ? 0x04 : 0;
3880: REG8(AH) |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
3881: REG8(AH) |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
3882: }
3883:
3884: inline void pcbios_int_16h_13h()
3885: {
3886: static UINT16 status = 0;
3887:
3888: switch(REG8(AL)) {
3889: case 0x00:
3890: status = REG16(DX);
3891: break;
3892: case 0x01:
3893: REG16(DX) = status;
3894: break;
3895: default:
1.1.1.3 root 3896: m_CF = 1;
1.1 root 3897: break;
3898: }
3899: }
3900:
3901: inline void pcbios_int_16h_14h()
3902: {
3903: static UINT8 status = 0;
3904:
3905: switch(REG8(AL)) {
3906: case 0x00:
3907: case 0x01:
3908: status = REG8(AL);
3909: break;
3910: case 0x02:
3911: REG8(AL) = status;
3912: break;
3913: default:
1.1.1.3 root 3914: m_CF = 1;
1.1 root 3915: break;
3916: }
3917: }
3918:
3919: inline void pcbios_int_1ah_00h()
3920: {
3921: static WORD prev_day = 0;
3922: SYSTEMTIME time;
3923:
3924: GetLocalTime(&time);
1.1.1.14 root 3925: UINT32 tick = get_ticks_since_midnight();
1.1 root 3926: REG16(CX) = (tick >> 16) & 0xffff;
3927: REG16(DX) = (tick ) & 0xffff;
3928: REG8(AL) = (prev_day != 0 && prev_day != time.wDay) ? 1 : 0;
3929: prev_day = time.wDay;
3930: }
3931:
3932: inline int to_bcd(int t)
3933: {
3934: int u = (t % 100) / 10;
3935: return (u << 4) | (t % 10);
3936: }
3937:
3938: inline void pcbios_int_1ah_02h()
3939: {
3940: SYSTEMTIME time;
3941:
3942: GetLocalTime(&time);
3943: REG8(CH) = to_bcd(time.wHour);
3944: REG8(CL) = to_bcd(time.wMinute);
3945: REG8(DH) = to_bcd(time.wSecond);
3946: REG8(DL) = 0x00;
3947: }
3948:
3949: inline void pcbios_int_1ah_04h()
3950: {
3951: SYSTEMTIME time;
3952:
3953: GetLocalTime(&time);
3954: REG8(CH) = to_bcd(time.wYear / 100);
3955: REG8(CL) = to_bcd(time.wYear);
3956: REG8(DH) = to_bcd(time.wMonth);
3957: REG8(DL) = to_bcd(time.wDay);
3958: }
3959:
3960: inline void pcbios_int_1ah_0ah()
3961: {
3962: SYSTEMTIME time;
3963: FILETIME file_time;
3964: WORD dos_date, dos_time;
3965:
3966: GetLocalTime(&time);
3967: SystemTimeToFileTime(&time, &file_time);
3968: FileTimeToDosDateTime(&file_time, &dos_date, &dos_time);
3969: REG16(CX) = dos_date;
3970: }
3971:
3972: // msdos system call
3973:
3974: inline void msdos_int_21h_00h()
3975: {
1.1.1.3 root 3976: msdos_process_terminate(SREG(CS), retval, 1);
1.1 root 3977: }
3978:
3979: inline void msdos_int_21h_01h()
3980: {
3981: REG8(AL) = msdos_getche();
1.1.1.8 root 3982: // some seconds may be passed in console
1.1 root 3983: hardware_update();
3984: }
3985:
3986: inline void msdos_int_21h_02h()
3987: {
3988: msdos_putch(REG8(DL));
3989: }
3990:
3991: inline void msdos_int_21h_03h()
3992: {
3993: REG8(AL) = msdos_aux_in();
3994: }
3995:
3996: inline void msdos_int_21h_04h()
3997: {
3998: msdos_aux_out(REG8(DL));
3999: }
4000:
4001: inline void msdos_int_21h_05h()
4002: {
4003: msdos_prn_out(REG8(DL));
4004: }
4005:
4006: inline void msdos_int_21h_06h()
4007: {
4008: if(REG8(DL) == 0xff) {
4009: if(msdos_kbhit()) {
4010: REG8(AL) = msdos_getch();
1.1.1.3 root 4011: #if defined(HAS_I386)
4012: m_ZF = 0;
4013: #else
4014: m_ZeroVal = 1;
4015: #endif
1.1 root 4016: } else {
4017: REG8(AL) = 0;
1.1.1.3 root 4018: #if defined(HAS_I386)
4019: m_ZF = 1;
4020: #else
4021: m_ZeroVal = 0;
4022: #endif
1.1.1.14 root 4023: maybe_idle();
1.1 root 4024: }
4025: } else {
4026: msdos_putch(REG8(DL));
4027: }
4028: }
4029:
4030: inline void msdos_int_21h_07h()
4031: {
4032: REG8(AL) = msdos_getch();
1.1.1.8 root 4033: // some seconds may be passed in console
1.1 root 4034: hardware_update();
4035: }
4036:
4037: inline void msdos_int_21h_08h()
4038: {
4039: REG8(AL) = msdos_getch();
1.1.1.8 root 4040: // some seconds may be passed in console
1.1 root 4041: hardware_update();
4042: }
4043:
4044: inline void msdos_int_21h_09h()
4045: {
1.1.1.14 root 4046: char *str = (char *)(mem + SREG_BASE(DS) + REG16(DX));
4047: int len = 0;
1.1 root 4048:
1.1.1.14 root 4049: while(str[len] != '$' && len < 0x10000) {
4050: len++;
4051: }
1.1 root 4052: if(file_handler[1].valid && !file_handler[1].atty) {
4053: // stdout is redirected to file
1.1.1.14 root 4054: msdos_write(1, str, len);
1.1 root 4055: } else {
4056: for(int i = 0; i < len; i++) {
1.1.1.14 root 4057: msdos_putch(str[i]);
1.1 root 4058: }
4059: }
4060: }
4061:
4062: inline void msdos_int_21h_0ah()
4063: {
1.1.1.3 root 4064: int ofs = SREG_BASE(DS) + REG16(DX);
1.1 root 4065: int max = mem[ofs] - 1;
4066: UINT8 *buf = mem + ofs + 2;
4067: int chr, p = 0;
4068:
4069: while((chr = msdos_getch()) != 0x0d) {
4070: if(chr == 0x00) {
4071: // skip 2nd byte
4072: msdos_getch();
4073: } else if(chr == 0x08) {
4074: // back space
4075: if(p > 0) {
4076: p--;
4077: msdos_putch(chr);
4078: msdos_putch(' ');
4079: msdos_putch(chr);
4080: }
4081: } else if(p < max) {
4082: buf[p++] = chr;
4083: msdos_putch(chr);
4084: }
4085: }
4086: buf[p] = 0x0d;
4087: mem[ofs + 1] = p;
1.1.1.8 root 4088: // some seconds may be passed in console
1.1 root 4089: hardware_update();
4090: }
4091:
4092: inline void msdos_int_21h_0bh()
4093: {
4094: if(msdos_kbhit()) {
4095: REG8(AL) = 0xff;
4096: } else {
4097: REG8(AL) = 0x00;
1.1.1.14 root 4098: maybe_idle();
1.1 root 4099: }
4100: }
4101:
4102: inline void msdos_int_21h_0ch()
4103: {
4104: // clear key buffer
4105: if(file_handler[0].valid && !file_handler[0].atty) {
4106: // stdin is redirected to file
4107: } else {
4108: while(msdos_kbhit()) {
4109: msdos_getch();
4110: }
4111: }
4112:
4113: switch(REG8(AL)) {
4114: case 0x01:
4115: msdos_int_21h_01h();
4116: break;
4117: case 0x06:
4118: msdos_int_21h_06h();
4119: break;
4120: case 0x07:
4121: msdos_int_21h_07h();
4122: break;
4123: case 0x08:
4124: msdos_int_21h_08h();
4125: break;
4126: case 0x0a:
4127: msdos_int_21h_0ah();
4128: break;
4129: default:
4130: REG16(AX) = 0x01;
1.1.1.3 root 4131: m_CF = 1;
1.1 root 4132: break;
4133: }
4134: }
4135:
4136: inline void msdos_int_21h_0dh()
4137: {
4138: }
4139:
4140: inline void msdos_int_21h_0eh()
4141: {
4142: if(REG8(DL) < 26) {
4143: _chdrive(REG8(DL) + 1);
4144: msdos_cds_update(REG8(DL));
4145: }
4146: REG8(AL) = 26; // zdrive
4147: }
4148:
1.1.1.14 root 4149: inline void msdos_int_21h_0fh()
4150: {
4151: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4152: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
4153:
4154: char *path = msdos_fcb_path(fcb);
4155: HANDLE hFile = CreateFile(path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
4156: if(hFile == INVALID_HANDLE_VALUE) {
4157: REG8(AL) = 0xff;
4158: } else {
4159: REG8(AL) = 0;
4160: fcb->current_block = 0;
4161: fcb->record_size = 128;
4162: fcb->file_size = GetFileSize(hFile, NULL);
4163: fcb->handle = hFile;
4164: fcb->cur_record = 0;
4165: }
4166: }
4167:
4168: inline void msdos_int_21h_10h()
4169: {
4170: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4171: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
4172:
4173: REG8(AL) = CloseHandle(fcb->handle) ? 0 : 0xff;
4174: }
4175:
1.1 root 4176: inline void msdos_int_21h_11h()
4177: {
1.1.1.3 root 4178: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4179: fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 4180:
4181: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 4182: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
4183: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
4184: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 4185: char *path = msdos_fcb_path(fcb);
4186: WIN32_FIND_DATA fd;
4187:
1.1.1.13 root 4188: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
4189: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
4190: FindClose(dtainfo->find_handle);
4191: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 4192: }
4193: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 4194: dtainfo->allowable_mask = (ext_fcb->flag == 0xff) ? ext_fcb->attribute : 0x20;
4195: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 4196:
1.1.1.14 root 4197: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
4198: dtainfo->allowable_mask &= ~8;
1.1 root 4199: }
1.1.1.14 root 4200: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
4201: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 4202: !msdos_find_file_has_8dot3name(&fd)) {
4203: if(!FindNextFile(dtainfo->find_handle, &fd)) {
4204: FindClose(dtainfo->find_handle);
4205: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 4206: break;
4207: }
4208: }
4209: }
1.1.1.13 root 4210: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 4211: if(ext_fcb->flag == 0xff) {
4212: ext_find->flag = 0xff;
4213: memset(ext_find->reserved, 0, 5);
4214: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
4215: }
4216: find->drive = _getdrive();
1.1.1.13 root 4217: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 4218: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
4219: find->nt_res = 0;
4220: msdos_find_file_conv_local_time(&fd);
4221: find->create_time_ms = 0;
4222: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
4223: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
4224: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
4225: find->cluster_hi = find->cluster_lo = 0;
4226: find->file_size = fd.nFileSizeLow;
4227: REG8(AL) = 0x00;
1.1.1.14 root 4228: } else if(dtainfo->allowable_mask & 8) {
1.1 root 4229: if(ext_fcb->flag == 0xff) {
4230: ext_find->flag = 0xff;
4231: memset(ext_find->reserved, 0, 5);
4232: ext_find->attribute = 8;
4233: }
4234: find->drive = _getdrive();
4235: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
4236: find->attribute = 8;
4237: find->nt_res = 0;
4238: msdos_find_file_conv_local_time(&fd);
4239: find->create_time_ms = 0;
4240: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
4241: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
4242: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
4243: find->cluster_hi = find->cluster_lo = 0;
4244: find->file_size = 0;
1.1.1.14 root 4245: dtainfo->allowable_mask &= ~8;
1.1 root 4246: REG8(AL) = 0x00;
4247: } else {
4248: REG8(AL) = 0xff;
4249: }
4250: }
4251:
4252: inline void msdos_int_21h_12h()
4253: {
1.1.1.3 root 4254: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1.1.14 root 4255: // fcb_t *fcb = (fcb_t *)(mem + SREG_BASE(DS) + REG16(DX) + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 4256:
4257: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 4258: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
4259: ext_fcb_t *ext_find = (ext_fcb_t *)(mem + dta_laddr);
4260: find_fcb_t *find = (find_fcb_t *)(mem + dta_laddr + (ext_fcb->flag == 0xff ? 7 : 0));
1.1 root 4261: WIN32_FIND_DATA fd;
4262:
1.1.1.13 root 4263: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, dta_laddr);
4264: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
4265: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 4266: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 4267: !msdos_find_file_has_8dot3name(&fd)) {
4268: if(!FindNextFile(dtainfo->find_handle, &fd)) {
4269: FindClose(dtainfo->find_handle);
4270: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 4271: break;
4272: }
4273: }
4274: } else {
1.1.1.13 root 4275: FindClose(dtainfo->find_handle);
4276: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 4277: }
4278: }
1.1.1.13 root 4279: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 4280: if(ext_fcb->flag == 0xff) {
4281: ext_find->flag = 0xff;
4282: memset(ext_find->reserved, 0, 5);
4283: ext_find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
4284: }
4285: find->drive = _getdrive();
1.1.1.13 root 4286: msdos_set_fcb_path((fcb_t *)find, msdos_short_name(&fd));
1.1 root 4287: find->attribute = (UINT8)(fd.dwFileAttributes & 0x3f);
4288: find->nt_res = 0;
4289: msdos_find_file_conv_local_time(&fd);
4290: find->create_time_ms = 0;
4291: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
4292: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
4293: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
4294: find->cluster_hi = find->cluster_lo = 0;
4295: find->file_size = fd.nFileSizeLow;
4296: REG8(AL) = 0x00;
1.1.1.14 root 4297: } else if(dtainfo->allowable_mask & 8) {
1.1 root 4298: if(ext_fcb->flag == 0xff) {
4299: ext_find->flag = 0xff;
4300: memset(ext_find->reserved, 0, 5);
4301: ext_find->attribute = 8;
4302: }
4303: find->drive = _getdrive();
4304: msdos_set_fcb_path((fcb_t *)find, msdos_short_volume_label(process->volume_label));
4305: find->attribute = 8;
4306: find->nt_res = 0;
4307: msdos_find_file_conv_local_time(&fd);
4308: find->create_time_ms = 0;
4309: FileTimeToDosDateTime(&fd.ftCreationTime, &find->creation_date, &find->creation_time);
4310: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->last_access_date, &find->last_write_time);
4311: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->last_write_date, &find->last_write_time);
4312: find->cluster_hi = find->cluster_lo = 0;
4313: find->file_size = 0;
1.1.1.14 root 4314: dtainfo->allowable_mask &= ~8;
1.1 root 4315: REG8(AL) = 0x00;
4316: } else {
4317: REG8(AL) = 0xff;
4318: }
4319: }
4320:
4321: inline void msdos_int_21h_13h()
4322: {
1.1.1.3 root 4323: if(remove(msdos_fcb_path((fcb_t *)(mem + SREG_BASE(DS) + REG16(DX))))) {
1.1 root 4324: REG8(AL) = 0xff;
4325: } else {
4326: REG8(AL) = 0x00;
4327: }
4328: }
4329:
1.1.1.14 root 4330: inline void msdos_int_21h_16h()
4331: {
4332: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4333: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
4334:
4335: char *path = msdos_fcb_path(fcb);
4336: 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);
4337: if(hFile == INVALID_HANDLE_VALUE) {
4338: REG8(AL) = 0xff;
4339: } else {
4340: REG8(AL) = 0;
4341: fcb->current_block = 0;
4342: fcb->record_size = 128;
4343: fcb->file_size = 0;
4344: fcb->handle = hFile;
4345: fcb->cur_record = 0;
4346: }
4347: }
4348:
1.1 root 4349: inline void msdos_int_21h_18h()
4350: {
4351: REG8(AL) = 0x00;
4352: }
4353:
4354: inline void msdos_int_21h_19h()
4355: {
4356: REG8(AL) = _getdrive() - 1;
4357: }
4358:
4359: inline void msdos_int_21h_1ah()
4360: {
4361: process_t *process = msdos_process_info_get(current_psp);
4362:
4363: process->dta.w.l = REG16(DX);
1.1.1.3 root 4364: process->dta.w.h = SREG(DS);
1.1 root 4365: }
4366:
4367: inline void msdos_int_21h_1bh()
4368: {
4369: int drive_num = _getdrive() - 1;
4370: UINT16 seg, ofs;
4371:
4372: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
4373: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
4374: REG8(AL) = dpb->highest_sector_num + 1;
4375: REG16(CX) = dpb->bytes_per_sector;
4376: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 4377: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 4378: } else {
4379: REG8(AL) = 0xff;
1.1.1.3 root 4380: m_CF = 1;
1.1 root 4381: }
4382:
4383: }
4384:
4385: inline void msdos_int_21h_1ch()
4386: {
4387: int drive_num = REG8(DL) ? (REG8(DL) - 1) : (_getdrive() - 1);
4388: UINT16 seg, ofs;
4389:
4390: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
4391: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
4392: REG8(AL) = dpb->highest_sector_num + 1;
4393: REG16(CX) = dpb->bytes_per_sector;
4394: REG16(DX) = dpb->highest_cluster_num - 1;
1.1.1.3 root 4395: *(UINT8 *)(mem + SREG_BASE(DS) + REG16(BX)) = dpb->media_type;
1.1 root 4396: } else {
4397: REG8(AL) = 0xff;
1.1.1.3 root 4398: m_CF = 1;
1.1 root 4399: }
4400:
4401: }
4402:
4403: inline void msdos_int_21h_1dh()
4404: {
4405: REG8(AL) = 0;
4406: }
4407:
4408: inline void msdos_int_21h_1eh()
4409: {
4410: REG8(AL) = 0;
4411: }
4412:
4413: inline void msdos_int_21h_1fh()
4414: {
4415: int drive_num = _getdrive() - 1;
4416: UINT16 seg, ofs;
4417:
4418: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
4419: REG8(AL) = 0;
1.1.1.3 root 4420: SREG(DS) = seg;
4421: i386_load_segment_descriptor(DS);
1.1 root 4422: REG16(BX) = ofs;
4423: } else {
4424: REG8(AL) = 0xff;
1.1.1.3 root 4425: m_CF = 1;
1.1 root 4426: }
4427: }
4428:
4429: inline void msdos_int_21h_20h()
4430: {
4431: REG8(AL) = 0;
4432: }
4433:
1.1.1.14 root 4434: inline void msdos_int_21h_21h()
4435: {
4436: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4437: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
4438:
4439: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
4440: REG8(AL) = 1;
4441: } else {
4442: process_t *process = msdos_process_info_get(current_psp);
4443: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
4444: memset(mem + dta_laddr, 0, fcb->record_size);
4445: DWORD num;
4446: if(!ReadFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL) || num == 0) {
4447: REG8(AL) = 1;
4448: } else {
4449: REG8(AL) = num == fcb->record_size ? 0 : 3;
4450: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
4451: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
4452: }
4453: }
4454: }
4455:
4456: inline void msdos_int_21h_22h()
4457: {
4458: ext_fcb_t *ext_fcb = (ext_fcb_t *)(mem + SREG_BASE(DS) + REG16(DX));
4459: fcb_t *fcb = (fcb_t *)(ext_fcb + (ext_fcb->flag == 0xff ? 1 : 0));
4460:
4461: if(SetFilePointer(fcb->handle, fcb->record_size * (fcb->rand_record & 0xffffff), NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
4462: REG8(AL) = 0xff;
4463: } else {
4464: process_t *process = msdos_process_info_get(current_psp);
4465: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
4466: DWORD num;
4467: WriteFile(fcb->handle, mem + dta_laddr, fcb->record_size, &num, NULL);
4468: fcb->file_size = GetFileSize(fcb->handle, NULL);
4469: fcb->current_block = (fcb->rand_record & 0xffffff) / fcb->record_size;
4470: fcb->cur_record = (fcb->rand_record & 0xffffff) % fcb->record_size;
4471: REG8(AL) = num == fcb->record_size ? 0 : 1;
4472: }
4473: }
4474:
1.1 root 4475: inline void msdos_int_21h_25h()
4476: {
4477: *(UINT16 *)(mem + 4 * REG8(AL) + 0) = REG16(DX);
1.1.1.3 root 4478: *(UINT16 *)(mem + 4 * REG8(AL) + 2) = SREG(DS);
1.1 root 4479: }
4480:
4481: inline void msdos_int_21h_26h()
4482: {
4483: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
4484:
4485: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
4486: psp->first_mcb = REG16(DX) + 16;
4487: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
4488: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
4489: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
4490: psp->parent_psp = 0;
4491: }
4492:
4493: inline void msdos_int_21h_29h()
4494: {
1.1.1.3 root 4495: int ofs = SREG_BASE(DS) + REG16(SI);
1.1 root 4496: char name[MAX_PATH], ext[MAX_PATH];
4497: UINT8 drv = 0;
4498: char sep_chars[] = ":.;,=+";
4499: char end_chars[] = "\\<>|/\"[]";
4500: char spc_chars[] = " \t";
4501:
4502: if(REG8(AL) & 1) {
4503: ofs += strspn((char *)&mem[ofs], spc_chars);
4504: if(my_strchr(sep_chars, mem[ofs]) && mem[ofs] != '\0') {
4505: ofs++;
4506: }
4507: }
4508: ofs += strspn((char *)&mem[ofs], spc_chars);
4509:
4510: if(mem[ofs + 1] == ':') {
4511: UINT8 c = mem[ofs];
4512: if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
4513: ; // invalid drive letter
4514: } else {
4515: if(c >= 'a' && c <= 'z') {
4516: drv = c - 'a' + 1;
4517: } else {
4518: drv = c - 'A' + 1;
4519: }
4520: ofs += 2;
4521: }
4522: }
4523: memset(name, 0x20, sizeof(name));
4524: memset(ext, 0x20, sizeof(ext));
4525: for(int i = 0; i < MAX_PATH; i++) {
4526: UINT8 c = mem[ofs];
4527: if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
4528: break;
4529: } else if(c >= 'a' && c <= 'z') {
4530: c -= 0x20;
4531: }
4532: ofs++;
4533: name[i] = c;
4534: }
4535: if(mem[ofs] == '.') {
4536: ofs++;
4537: for(int i = 0; i < MAX_PATH; i++) {
4538: UINT8 c = mem[ofs];
4539: if(c <= 0x20 || my_strchr(end_chars, c) || my_strchr(sep_chars, c)) {
4540: break;
4541: } else if(c >= 'a' && c <= 'z') {
4542: c -= 0x20;
4543: }
4544: ofs++;
4545: ext[i] = c;
4546: }
4547: }
1.1.1.3 root 4548: int si = ofs - SREG_BASE(DS);
4549: int ds = SREG(DS);
1.1 root 4550: while(si > 0xffff) {
4551: si -= 0x10;
4552: ds++;
4553: }
4554: REG16(SI) = si;
1.1.1.3 root 4555: SREG(DS) = ds;
4556: i386_load_segment_descriptor(DS);
1.1 root 4557:
1.1.1.3 root 4558: UINT8 *fcb = mem + SREG_BASE(ES) + REG16(DI);
1.1 root 4559: fcb[0] = drv;
4560: memcpy(fcb + 1, name, 8);
4561: int found_star = 0;
4562: for(int i = 1; i < 1 + 8; i++) {
4563: if(fcb[i] == '*') {
4564: found_star = 1;
4565: }
4566: if(found_star) {
4567: fcb[i] = '?';
4568: }
4569: }
4570: memcpy(fcb + 9, ext, 3);
4571: found_star = 0;
4572: for(int i = 9; i < 9 + 3; i++) {
4573: if(fcb[i] == '*') {
4574: found_star = 1;
4575: }
4576: if(found_star) {
4577: fcb[i] = '?';
4578: }
4579: }
4580:
4581: REG8(AL) = 0x00;
4582: if(drv == 0 || (drv > 0 && drv <= 26 && (GetLogicalDrives() & ( 1 << (drv - 1) )))) {
4583: if(memchr(fcb + 1, '?', 8 + 3)) {
4584: REG8(AL) = 0x01;
4585: }
4586: } else {
4587: REG8(AL) = 0xff;
4588: }
4589: }
4590:
4591: inline void msdos_int_21h_2ah()
4592: {
4593: SYSTEMTIME sTime;
4594:
4595: GetLocalTime(&sTime);
4596: REG16(CX) = sTime.wYear;
4597: REG8(DH) = (UINT8)sTime.wMonth;
4598: REG8(DL) = (UINT8)sTime.wDay;
4599: REG8(AL) = (UINT8)sTime.wDayOfWeek;
4600: }
4601:
4602: inline void msdos_int_21h_2bh()
4603: {
1.1.1.14 root 4604: REG8(AL) = 0xff;
1.1 root 4605: }
4606:
4607: inline void msdos_int_21h_2ch()
4608: {
4609: SYSTEMTIME sTime;
4610:
4611: GetLocalTime(&sTime);
4612: REG8(CH) = (UINT8)sTime.wHour;
4613: REG8(CL) = (UINT8)sTime.wMinute;
4614: REG8(DH) = (UINT8)sTime.wSecond;
1.1.1.14 root 4615: REG8(DL) = (UINT8)sTime.wMilliseconds / 10;
1.1 root 4616: }
4617:
4618: inline void msdos_int_21h_2dh()
4619: {
4620: REG8(AL) = 0x00;
4621: }
4622:
4623: inline void msdos_int_21h_2eh()
4624: {
4625: process_t *process = msdos_process_info_get(current_psp);
4626:
4627: process->verify = REG8(AL);
4628: }
4629:
4630: inline void msdos_int_21h_2fh()
4631: {
4632: process_t *process = msdos_process_info_get(current_psp);
4633:
4634: REG16(BX) = process->dta.w.l;
1.1.1.3 root 4635: SREG(ES) = process->dta.w.h;
4636: i386_load_segment_descriptor(ES);
1.1 root 4637: }
4638:
4639: inline void msdos_int_21h_30h()
4640: {
4641: // Version Flag / OEM
4642: if(REG8(AL) == 1) {
4643: REG8(BH) = 0x00; // not in ROM
4644: } else {
4645: REG8(BH) = 0xff; // OEM = Microsoft
4646: }
1.1.1.9 root 4647: REG8(AL) = major_version; // 7
4648: REG8(AH) = minor_version; // 10
1.1 root 4649: }
4650:
4651: inline void msdos_int_21h_31h()
4652: {
1.1.1.14 root 4653: msdos_mem_realloc(current_psp, REG16(DX), NULL);
1.1 root 4654: msdos_process_terminate(current_psp, REG8(AL) | 0x300, 0);
4655: }
4656:
4657: inline void msdos_int_21h_32h()
4658: {
4659: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
4660: UINT16 seg, ofs;
4661:
4662: if(msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
4663: REG8(AL) = 0;
1.1.1.3 root 4664: SREG(DS) = seg;
4665: i386_load_segment_descriptor(DS);
1.1 root 4666: REG16(BX) = ofs;
4667: } else {
4668: REG8(AL) = 0xff;
1.1.1.3 root 4669: m_CF = 1;
1.1 root 4670: }
4671: }
4672:
4673: inline void msdos_int_21h_33h()
4674: {
4675: static UINT8 state = 0x00;
4676: char path[MAX_PATH];
4677:
4678: switch(REG8(AL)) {
4679: case 0x00:
4680: REG8(DL) = state;
4681: break;
4682: case 0x01:
4683: state = REG8(DL);
4684: break;
4685: case 0x05:
4686: GetSystemDirectory(path, MAX_PATH);
4687: if(path[0] >= 'a' && path[0] <= 'z') {
4688: REG8(DL) = path[0] - 'a' + 1;
4689: } else {
4690: REG8(DL) = path[0] - 'A' + 1;
4691: }
4692: break;
4693: case 0x06:
1.1.1.2 root 4694: // MS-DOS version (7.10)
1.1 root 4695: REG8(BL) = 7;
1.1.1.2 root 4696: REG8(BH) = 10;
1.1 root 4697: REG8(DL) = 0;
4698: REG8(DH) = 0x10; // in HMA
4699: break;
1.1.1.6 root 4700: case 0x07:
4701: if(REG8(DL) == 0) {
4702: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag &= ~0x20;
4703: } else if(REG8(DL) == 1) {
4704: ((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag |= 0x20;
4705: }
4706: break;
1.1 root 4707: default:
4708: REG16(AX) = 0x01;
1.1.1.3 root 4709: m_CF = 1;
1.1 root 4710: break;
4711: }
4712: }
4713:
4714: inline void msdos_int_21h_35h()
4715: {
4716: REG16(BX) = *(UINT16 *)(mem + 4 * REG8(AL) + 0);
1.1.1.3 root 4717: SREG(ES) = *(UINT16 *)(mem + 4 * REG8(AL) + 2);
4718: i386_load_segment_descriptor(ES);
1.1 root 4719: }
4720:
4721: inline void msdos_int_21h_36h()
4722: {
4723: struct _diskfree_t df = {0};
4724:
4725: if(_getdiskfree(REG8(DL), &df) == 0) {
4726: REG16(AX) = (UINT16)df.sectors_per_cluster;
4727: REG16(CX) = (UINT16)df.bytes_per_sector;
1.1.1.13 root 4728: REG16(BX) = df.avail_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.avail_clusters;
4729: REG16(DX) = df.total_clusters > 0xFFFF ? 0xFFFF : (UINT16)df.total_clusters;
1.1 root 4730: } else {
4731: REG16(AX) = 0xffff;
4732: }
4733: }
4734:
4735: inline void msdos_int_21h_37h()
4736: {
4737: process_t *process = msdos_process_info_get(current_psp);
4738:
4739: switch(REG8(AL)) {
4740: case 0x00:
4741: REG8(AL) = 0x00;
4742: REG8(DL) = process->switchar;
4743: break;
4744: case 0x01:
4745: REG8(AL) = 0x00;
4746: process->switchar = REG8(DL);
4747: break;
4748: default:
4749: REG16(AX) = 1;
4750: break;
4751: }
4752: }
4753:
1.1.1.14 root 4754: inline void msdos_int_21h_38h()
4755: {
4756: switch(REG8(AL)) {
4757: case 0x00:
4758: {
4759: char LCdata[80];
4760: struct CI {
4761: UINT16 date_format;
4762: char currency_symbol[5];
4763: char thou_sep[2];
4764: char dec_sep[2];
4765: char date_sep[2];
4766: char time_sep[2];
4767: char currency_format;
4768: char currency_dec_digits;
4769: char time_format;
4770: UINT32 case_map;
4771: char list_sep[2];
4772: // char reserved[10];
4773: } *ci = (CI *)(mem + SREG_BASE(DS) + REG16(DX));
4774: memset(ci, 0, sizeof(*ci));
4775: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRDIGITS, LCdata, sizeof(LCdata));
4776: ci->currency_dec_digits = atoi(LCdata);
4777: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ICURRENCY, LCdata, sizeof(LCdata));
4778: ci->currency_format = *LCdata - '0';
4779: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDATE, LCdata, sizeof(LCdata));
4780: ci->date_format = *LCdata - '0';
4781: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SCURRENCY, LCdata, sizeof(LCdata));
4782: memcpy(&ci->currency_symbol, LCdata, 4);
4783: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDATE, LCdata, sizeof(LCdata));
4784: *ci->date_sep = *LCdata;
4785: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, LCdata, sizeof(LCdata));
4786: *ci->dec_sep = *LCdata;
4787: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SLIST, LCdata, sizeof(LCdata));
4788: *ci->list_sep = *LCdata;
4789: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, LCdata, sizeof(LCdata));
4790: *ci->thou_sep = *LCdata;
4791: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIME, LCdata, sizeof(LCdata));
4792: *ci->time_sep = *LCdata;
4793: GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIMEFORMAT, LCdata, sizeof(LCdata));
4794: if(strchr(LCdata, 'H') != NULL) {
4795: ci->time_format = 1;
4796: }
4797: }
4798: break;
4799: default:
4800: REG16(AX) = 2;
4801: m_CF = 1;
4802: break;
4803: }
4804: }
4805:
1.1 root 4806: inline void msdos_int_21h_39h(int lfn)
4807: {
1.1.1.3 root 4808: if(_mkdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 4809: REG16(AX) = errno;
1.1.1.3 root 4810: m_CF = 1;
1.1 root 4811: }
4812: }
4813:
4814: inline void msdos_int_21h_3ah(int lfn)
4815: {
1.1.1.3 root 4816: if(_rmdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 4817: REG16(AX) = errno;
1.1.1.3 root 4818: m_CF = 1;
1.1 root 4819: }
4820: }
4821:
4822: inline void msdos_int_21h_3bh(int lfn)
4823: {
1.1.1.3 root 4824: if(_chdir(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 4825: REG16(AX) = errno;
1.1.1.3 root 4826: m_CF = 1;
1.1 root 4827: }
4828: }
4829:
4830: inline void msdos_int_21h_3ch()
4831: {
1.1.1.3 root 4832: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 4833: int attr = GetFileAttributes(path);
4834: int fd = -1;
1.1.1.11 root 4835: UINT16 info;
1.1 root 4836:
1.1.1.11 root 4837: if(msdos_is_con_path(path)) {
4838: fd = _open("CON", _O_WRONLY | _O_BINARY);
4839: info = 0x80d3;
1.1.1.14 root 4840: } else if(msdos_is_nul_path(path)) {
4841: fd = _open("NUL", _O_WRONLY | _O_BINARY);
4842: info = 0x80d3;
1.1 root 4843: } else {
4844: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
1.1.1.11 root 4845: info = msdos_drive_number(path);
1.1 root 4846: }
4847: if(fd != -1) {
4848: if(attr == -1) {
4849: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
4850: }
4851: SetFileAttributes(path, attr);
4852: REG16(AX) = fd;
1.1.1.11 root 4853: msdos_file_handler_open(fd, path, _isatty(fd), 2, info, current_psp);
1.1 root 4854: } else {
4855: REG16(AX) = errno;
1.1.1.3 root 4856: m_CF = 1;
1.1 root 4857: }
4858: }
4859:
4860: inline void msdos_int_21h_3dh()
4861: {
1.1.1.3 root 4862: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 4863: int mode = REG8(AL) & 0x03;
1.1.1.11 root 4864: int fd = -1;
4865: UINT16 info;
1.1 root 4866:
4867: if(mode < 0x03) {
1.1.1.11 root 4868: if(msdos_is_con_path(path)) {
1.1.1.13 root 4869: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 4870: info = 0x80d3;
1.1.1.14 root 4871: } else if(msdos_is_nul_path(path)) {
4872: fd = msdos_open("NUL", file_mode[mode].mode);
4873: info = 0x80d3;
1.1.1.11 root 4874: } else {
1.1.1.13 root 4875: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 4876: info = msdos_drive_number(path);
4877: }
1.1 root 4878: if(fd != -1) {
4879: REG16(AX) = fd;
1.1.1.11 root 4880: msdos_file_handler_open(fd, path, _isatty(fd), mode, info, current_psp);
1.1 root 4881: } else {
4882: REG16(AX) = errno;
1.1.1.3 root 4883: m_CF = 1;
1.1 root 4884: }
4885: } else {
4886: REG16(AX) = 0x0c;
1.1.1.3 root 4887: m_CF = 1;
1.1 root 4888: }
4889: }
4890:
4891: inline void msdos_int_21h_3eh()
4892: {
4893: process_t *process = msdos_process_info_get(current_psp);
4894:
4895: if(REG16(BX) < process->max_files && file_handler[REG16(BX)].valid) {
4896: _close(REG16(BX));
4897: msdos_file_handler_close(REG16(BX), current_psp);
4898: } else {
4899: REG16(AX) = 0x06;
1.1.1.3 root 4900: m_CF = 1;
1.1 root 4901: }
4902: }
4903:
4904: inline void msdos_int_21h_3fh()
4905: {
4906: process_t *process = msdos_process_info_get(current_psp);
4907:
4908: if(REG16(BX) < process->max_files && file_handler[REG16(BX)].valid) {
4909: if(file_mode[file_handler[REG16(BX)].mode].in) {
4910: if(file_handler[REG16(BX)].atty) {
4911: // BX is stdin or is redirected to stdin
1.1.1.3 root 4912: UINT8 *buf = mem + SREG_BASE(DS) + REG16(DX);
1.1 root 4913: int max = REG16(CX);
4914: int p = 0;
4915:
4916: while(max > p) {
4917: int chr = msdos_getch();
4918:
4919: if(chr == 0x00) {
4920: // skip 2nd byte
4921: msdos_getch();
4922: } else if(chr == 0x0d) {
4923: // carriage return
4924: buf[p++] = 0x0d;
4925: if(max > p) {
4926: buf[p++] = 0x0a;
4927: }
1.1.1.14 root 4928: msdos_putch('\n');
1.1 root 4929: break;
4930: } else if(chr == 0x08) {
4931: // back space
4932: if(p > 0) {
4933: p--;
4934: msdos_putch(chr);
4935: msdos_putch(' ');
4936: msdos_putch(chr);
4937: }
4938: } else {
4939: buf[p++] = chr;
4940: msdos_putch(chr);
4941: }
4942: }
4943: REG16(AX) = p;
1.1.1.8 root 4944: // some seconds may be passed in console
1.1 root 4945: hardware_update();
4946: } else {
1.1.1.3 root 4947: REG16(AX) = _read(REG16(BX), mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 4948: }
4949: } else {
4950: REG16(AX) = 0x05;
1.1.1.3 root 4951: m_CF = 1;
1.1 root 4952: }
4953: } else {
4954: REG16(AX) = 0x06;
1.1.1.3 root 4955: m_CF = 1;
1.1 root 4956: }
4957: }
4958:
4959: inline void msdos_int_21h_40h()
4960: {
4961: process_t *process = msdos_process_info_get(current_psp);
4962:
4963: if(REG16(BX) < process->max_files && file_handler[REG16(BX)].valid) {
4964: if(file_mode[file_handler[REG16(BX)].mode].out) {
4965: if(REG16(CX)) {
4966: if(file_handler[REG16(BX)].atty) {
4967: // BX is stdout/stderr or is redirected to stdout
4968: for(int i = 0; i < REG16(CX); i++) {
1.1.1.3 root 4969: msdos_putch(mem[SREG_BASE(DS) + REG16(DX) + i]);
1.1 root 4970: }
4971: REG16(AX) = REG16(CX);
4972: } else {
1.1.1.3 root 4973: REG16(AX) = msdos_write(REG16(BX), mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 4974: }
4975: } else {
4976: UINT32 pos = _tell(REG16(BX));
4977: _lseek(REG16(BX), 0, SEEK_END);
4978: UINT32 size = _tell(REG16(BX));
4979: REG16(AX) = 0;
1.1.1.12 root 4980: if(pos < size) {
4981: _lseek(REG16(BX), pos, SEEK_SET);
4982: SetEndOfFile((HANDLE)_get_osfhandle(REG16(BX)));
4983: } else {
4984: for(UINT32 i = size; i < pos; i++) {
4985: UINT8 tmp = 0;
4986: REG16(AX) += msdos_write(REG16(BX), &tmp, 1);
4987: }
4988: _lseek(REG16(BX), pos, SEEK_SET);
1.1 root 4989: }
4990: }
4991: } else {
4992: REG16(AX) = 0x05;
1.1.1.3 root 4993: m_CF = 1;
1.1 root 4994: }
4995: } else {
4996: REG16(AX) = 0x06;
1.1.1.3 root 4997: m_CF = 1;
1.1 root 4998: }
4999: }
5000:
5001: inline void msdos_int_21h_41h(int lfn)
5002: {
1.1.1.3 root 5003: if(remove(msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn))) {
1.1 root 5004: REG16(AX) = errno;
1.1.1.3 root 5005: m_CF = 1;
1.1 root 5006: }
5007: }
5008:
5009: inline void msdos_int_21h_42h()
5010: {
5011: process_t *process = msdos_process_info_get(current_psp);
5012:
5013: if(REG16(BX) < process->max_files && file_handler[REG16(BX)].valid) {
5014: if(REG8(AL) < 0x03) {
5015: static int ptrname[] = { SEEK_SET, SEEK_CUR, SEEK_END };
5016: _lseek(REG16(BX), (REG16(CX) << 16) | REG16(DX), ptrname[REG8(AL)]);
5017: UINT32 pos = _tell(REG16(BX));
5018: REG16(AX) = pos & 0xffff;
5019: REG16(DX) = (pos >> 16);
5020: } else {
5021: REG16(AX) = 0x01;
1.1.1.3 root 5022: m_CF = 1;
1.1 root 5023: }
5024: } else {
5025: REG16(AX) = 0x06;
1.1.1.3 root 5026: m_CF = 1;
1.1 root 5027: }
5028: }
5029:
5030: inline void msdos_int_21h_43h(int lfn)
5031: {
1.1.1.3 root 5032: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn);
1.1 root 5033: int attr;
5034:
1.1.1.14 root 5035: if(!lfn && REG8(AL) > 2) {
5036: REG16(AX) = 0x01;
5037: m_CF = 1;
5038: return;
5039: }
5040: switch(REG8(lfn ? BL : AL)) {
1.1 root 5041: case 0x00:
5042: if((attr = GetFileAttributes(path)) != -1) {
1.1.1.14 root 5043: REG16(CX) = (UINT16)msdos_file_attribute_create((UINT16)attr);
5044: } else {
5045: REG16(AX) = (UINT16)GetLastError();
5046: m_CF = 1;
5047: }
5048: break;
5049: case 0x01:
5050: if(!SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)))) {
5051: REG16(AX) = (UINT16)GetLastError();
5052: m_CF = 1;
5053: }
5054: break;
5055: case 0x02:
5056: {
5057: DWORD size = GetCompressedFileSize(path, NULL);
5058: if(size != INVALID_FILE_SIZE) {
5059: if(size != 0 && size == GetFileSize(path, NULL)) {
5060: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
5061: // this isn't correct if the file is in the NTFS MFT
5062: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
5063: size = ((size - 1) | (sectors_per_cluster * bytes_per_sector - 1)) + 1;
5064: }
5065: }
5066: REG16(AX) = LOWORD(size);
5067: REG16(DX) = HIWORD(size);
5068: } else {
5069: REG16(AX) = (UINT16)GetLastError();
5070: m_CF = 1;
1.1 root 5071: }
1.1.1.14 root 5072: }
5073: break;
5074: case 0x03:
5075: case 0x05:
5076: case 0x07:
5077: {
5078: HANDLE hFile = CreateFile(path, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
5079: if(hFile != INVALID_HANDLE_VALUE) {
5080: FILETIME local, time;
5081: DosDateTimeToFileTime(REG16(DI), /*REG8(BL) == 5 ? 0 : */REG16(CX), &local);
5082: if(REG8(BL) == 7) {
5083: ULARGE_INTEGER hund;
5084: hund.LowPart = local.dwLowDateTime;
5085: hund.HighPart = local.dwHighDateTime;
5086: hund.QuadPart += REG16(SI) * 100000;
5087: local.dwLowDateTime = hund.LowPart;
5088: local.dwHighDateTime = hund.HighPart;
5089: }
5090: LocalFileTimeToFileTime(&local, &time);
5091: if(!SetFileTime(hFile, REG8(BL) == 0x07 ? &time : NULL,
5092: REG8(BL) == 0x05 ? &time : NULL,
5093: REG8(BL) == 0x03 ? &time : NULL)) {
5094: REG16(AX) = (UINT16)GetLastError();
5095: m_CF = 1;
5096: }
5097: CloseHandle(hFile);
5098: } else {
5099: REG16(AX) = (UINT16)GetLastError();
5100: m_CF = 1;
1.1 root 5101: }
1.1.1.14 root 5102: }
5103: break;
5104: case 0x04:
5105: case 0x06:
5106: case 0x08:
5107: {
5108: WIN32_FILE_ATTRIBUTE_DATA fad;
5109: if(GetFileAttributesEx(path, GetFileExInfoStandard, (LPVOID)&fad)) {
5110: FILETIME *time, local;
5111: time = REG8(BL) == 0x04 ? &fad.ftLastWriteTime :
5112: 0x06 ? &fad.ftLastAccessTime :
5113: &fad.ftCreationTime;
5114: FileTimeToLocalFileTime(time, &local);
5115: FileTimeToDosDateTime(&local, ®16(DI), ®16(CX));
5116: if(REG8(BL) == 0x08) {
5117: ULARGE_INTEGER hund;
5118: hund.LowPart = local.dwLowDateTime;
5119: hund.HighPart = local.dwHighDateTime;
5120: hund.QuadPart /= 100000;
5121: REG16(SI) = (UINT16)(hund.QuadPart % 200);
5122: }
5123: } else {
5124: REG16(AX) = (UINT16)GetLastError();
5125: m_CF = 1;
1.1 root 5126: }
1.1.1.14 root 5127: }
5128: break;
5129: default:
5130: REG16(AX) = 0x01;
5131: m_CF = 1;
5132: break;
5133: }
5134: }
5135:
5136: inline void msdos_int_21h_44h()
5137: {
5138: UINT32 val = DRIVE_NO_ROOT_DIR;
5139:
5140: switch(REG8(AL)) {
5141: case 0x00:
5142: case 0x01:
5143: case 0x02:
5144: case 0x03:
5145: case 0x04:
5146: case 0x05:
5147: case 0x06:
5148: case 0x07:
5149: {
5150: process_t *process = msdos_process_info_get(current_psp);
5151:
5152: if(REG16(BX) >= process->max_files || !file_handler[REG16(BX)].valid) {
5153: REG16(AX) = 0x06;
5154: m_CF = 1;
5155: return;
5156: }
5157: }
5158: break;
5159: case 0x08:
5160: case 0x09:
5161: if(REG8(BL) >= ('Z' - 'A' + 1)) {
5162: // invalid drive number
5163: REG16(AX) = 0x0f;
5164: m_CF = 1;
5165: return;
5166: } else {
5167: if(REG8(BL) == 0) {
5168: val = GetDriveType(NULL);
5169: } else {
5170: char tmp[8];
5171: sprintf(tmp, "%c:\\", 'A' + REG8(BL) - 1);
5172: val = GetDriveType(tmp);
5173: }
5174: if(val == DRIVE_NO_ROOT_DIR) {
5175: // no drive
5176: REG16(AX) = 0x0f;
5177: m_CF = 1;
5178: return;
1.1 root 5179: }
5180: }
5181: break;
5182: }
5183: switch(REG8(AL)) {
5184: case 0x00: // get ioctrl data
5185: REG16(DX) = file_handler[REG16(BX)].info;
5186: break;
5187: case 0x01: // set ioctrl data
5188: file_handler[REG16(BX)].info |= REG8(DL);
5189: break;
5190: case 0x02: // recv from character device
5191: case 0x03: // send to character device
5192: case 0x04: // recv from block device
5193: case 0x05: // send to block device
5194: REG16(AX) = 0x05;
1.1.1.3 root 5195: m_CF = 1;
1.1 root 5196: break;
5197: case 0x06: // get read status
1.1.1.14 root 5198: if(file_mode[file_handler[REG16(BX)].mode].in) {
5199: if(file_handler[REG16(BX)].atty) {
5200: REG8(AL) = msdos_kbhit() ? 0xff : 0x00;
1.1 root 5201: } else {
1.1.1.14 root 5202: REG8(AL) = eof(REG16(BX)) ? 0x00 : 0xff;
1.1 root 5203: }
1.1.1.14 root 5204: } else {
5205: REG8(AL) = 0x00;
1.1 root 5206: }
5207: break;
5208: case 0x07: // get write status
1.1.1.14 root 5209: if(file_mode[file_handler[REG16(BX)].mode].out) {
5210: REG8(AL) = 0xff;
5211: } else {
5212: REG8(AL) = 0x00;
1.1 root 5213: }
5214: break;
5215: case 0x08: // check removable drive
1.1.1.14 root 5216: if(val == DRIVE_REMOVABLE || val == DRIVE_CDROM) {
5217: // removable drive
5218: REG16(AX) = 0x00;
1.1 root 5219: } else {
1.1.1.14 root 5220: // fixed drive
5221: REG16(AX) = 0x01;
1.1 root 5222: }
5223: break;
5224: case 0x09: // check remote drive
1.1.1.14 root 5225: if(val == DRIVE_REMOTE) {
5226: // remote drive
5227: REG16(DX) = 0x1000;
1.1 root 5228: } else {
1.1.1.14 root 5229: // local drive
5230: REG16(DX) = 0x00;
1.1 root 5231: }
5232: break;
5233: case 0x0b: // set retry count
5234: break;
5235: default:
5236: REG16(AX) = 0x01;
1.1.1.3 root 5237: m_CF = 1;
1.1 root 5238: break;
5239: }
5240: }
5241:
5242: inline void msdos_int_21h_45h()
5243: {
5244: process_t *process = msdos_process_info_get(current_psp);
5245:
5246: if(REG16(BX) < process->max_files && file_handler[REG16(BX)].valid) {
5247: int fd = _dup(REG16(BX));
5248: if(fd != -1) {
5249: REG16(AX) = fd;
5250: msdos_file_handler_dup(REG16(AX), REG16(BX), current_psp);
5251: } else {
5252: REG16(AX) = errno;
1.1.1.3 root 5253: m_CF = 1;
1.1 root 5254: }
5255: } else {
5256: REG16(AX) = 0x06;
1.1.1.3 root 5257: m_CF = 1;
1.1 root 5258: }
5259: }
5260:
5261: inline void msdos_int_21h_46h()
5262: {
5263: process_t *process = msdos_process_info_get(current_psp);
5264:
5265: if(REG16(BX) < process->max_files && REG16(CX) < process->max_files && file_handler[REG16(BX)].valid) {
5266: if(_dup2(REG16(BX), REG16(CX)) != -1) {
5267: msdos_file_handler_dup(REG16(CX), REG16(BX), current_psp);
5268: } else {
5269: REG16(AX) = errno;
1.1.1.3 root 5270: m_CF = 1;
1.1 root 5271: }
5272: } else {
5273: REG16(AX) = 0x06;
1.1.1.3 root 5274: m_CF = 1;
1.1 root 5275: }
5276: }
5277:
5278: inline void msdos_int_21h_47h(int lfn)
5279: {
5280: char path[MAX_PATH];
5281:
5282: if(_getdcwd(REG8(DL), path, MAX_PATH) != NULL) {
5283: if(path[1] == ':') {
5284: // the returned path does not include a drive or the initial backslash
1.1.1.3 root 5285: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), (lfn ? path : msdos_short_path(path)) + 3);
1.1 root 5286: } else {
1.1.1.3 root 5287: strcpy((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn ? path : msdos_short_path(path));
1.1 root 5288: }
5289: } else {
5290: REG16(AX) = errno;
1.1.1.3 root 5291: m_CF = 1;
1.1 root 5292: }
5293: }
5294:
5295: inline void msdos_int_21h_48h()
5296: {
5297: int seg;
5298:
1.1.1.8 root 5299: if((malloc_strategy & 0xf0) == 0x00) {
5300: if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
5301: REG16(AX) = seg;
5302: } else {
5303: REG16(AX) = 0x08;
5304: REG16(BX) = msdos_mem_get_free(first_mcb, 0);
5305: m_CF = 1;
5306: }
5307: } else if((malloc_strategy & 0xf0) == 0x40) {
5308: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
5309: REG16(AX) = seg;
5310: } else {
5311: REG16(AX) = 0x08;
5312: REG16(BX) = msdos_mem_get_free(UMB_TOP >> 4, 0);
5313: m_CF = 1;
5314: }
5315: } else if((malloc_strategy & 0xf0) == 0x80) {
5316: if((seg = msdos_mem_alloc(UMB_TOP >> 4, REG16(BX), 0)) != -1) {
5317: REG16(AX) = seg;
5318: } else if((seg = msdos_mem_alloc(first_mcb, REG16(BX), 0)) != -1) {
5319: REG16(AX) = seg;
5320: } else {
5321: REG16(AX) = 0x08;
5322: REG16(BX) = max(msdos_mem_get_free(UMB_TOP >> 4, 0), msdos_mem_get_free(first_mcb, 0));
5323: m_CF = 1;
5324: }
1.1 root 5325: }
5326: }
5327:
5328: inline void msdos_int_21h_49h()
5329: {
1.1.1.14 root 5330: int mcb_seg = SREG(ES) - 1;
5331: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
5332:
5333: if(mcb->mz == 'M' || mcb->mz == 'Z') {
5334: msdos_mem_free(SREG(ES));
5335: } else {
5336: REG16(AX) = 9;
5337: m_CF = 1;
5338: }
1.1 root 5339: }
5340:
5341: inline void msdos_int_21h_4ah()
5342: {
1.1.1.14 root 5343: int mcb_seg = SREG(ES) - 1;
5344: mcb_t *mcb = (mcb_t *)(mem + (mcb_seg << 4));
1.1 root 5345: int max_paragraphs;
5346:
1.1.1.14 root 5347: if(mcb->mz == 'M' || mcb->mz == 'Z') {
5348: if(msdos_mem_realloc(SREG(ES), REG16(BX), &max_paragraphs)) {
5349: REG16(AX) = 0x08;
5350: REG16(BX) = max_paragraphs > 0x7fff && limit_max_memory ? 0x7fff : max_paragraphs;
5351: m_CF = 1;
5352: }
5353: } else {
5354: REG16(AX) = 7;
1.1.1.3 root 5355: m_CF = 1;
1.1 root 5356: }
5357: }
5358:
5359: inline void msdos_int_21h_4bh()
5360: {
1.1.1.3 root 5361: char *command = (char *)(mem + SREG_BASE(DS) + REG16(DX));
5362: param_block_t *param = (param_block_t *)(mem + SREG_BASE(ES) + REG16(BX));
1.1 root 5363:
5364: switch(REG8(AL)) {
5365: case 0x00:
5366: case 0x01:
5367: if(msdos_process_exec(command, param, REG8(AL))) {
5368: REG16(AX) = 0x02;
1.1.1.3 root 5369: m_CF = 1;
1.1 root 5370: }
5371: break;
1.1.1.14 root 5372: case 0x03:
5373: {
5374: int fd;
5375: if((fd = _open(command, _O_RDONLY | _O_BINARY)) == -1) {
5376: REG16(AX) = 0x02;
5377: m_CF = 1;
5378: break;
5379: }
5380: int size = _read(fd, file_buffer, sizeof(file_buffer));
5381: _close(fd);
5382:
5383: UINT16 *overlay = (UINT16 *)param;
5384:
5385: // check exe header
5386: exe_header_t *header = (exe_header_t *)file_buffer;
5387: int header_size = 0;
5388: if(header->mz == 0x4d5a || header->mz == 0x5a4d) {
5389: header_size = header->header_size * 16;
5390: // relocation
5391: int start_seg = overlay[1];
5392: for(int i = 0; i < header->relocations; i++) {
5393: int ofs = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 0);
5394: int seg = *(UINT16 *)(file_buffer + header->relocation_table + i * 4 + 2);
5395: *(UINT16 *)(file_buffer + header_size + (seg << 4) + ofs) += start_seg;
5396: }
5397: }
5398: memcpy(mem + (overlay[0] << 4), file_buffer + header_size, size - header_size);
5399: }
5400: break;
1.1 root 5401: default:
5402: REG16(AX) = 0x01;
1.1.1.3 root 5403: m_CF = 1;
1.1 root 5404: break;
5405: }
5406: }
5407:
5408: inline void msdos_int_21h_4ch()
5409: {
5410: msdos_process_terminate(current_psp, REG8(AL), 1);
5411: }
5412:
5413: inline void msdos_int_21h_4dh()
5414: {
5415: REG16(AX) = retval;
5416: }
5417:
5418: inline void msdos_int_21h_4eh()
5419: {
5420: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 5421: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5422: find_t *find = (find_t *)(mem + dta_laddr);
1.1.1.3 root 5423: char *path = msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 5424: WIN32_FIND_DATA fd;
5425:
1.1.1.14 root 5426: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
5427: find->find_magic = FIND_MAGIC;
5428: find->dta_index = dtainfo - dtalist;
1.1 root 5429: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 5430: dtainfo->allowable_mask = REG8(CL);
5431: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 5432:
1.1.1.14 root 5433: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
5434: dtainfo->allowable_mask &= ~8;
1.1 root 5435: }
1.1.1.14 root 5436: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
5437: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 5438: !msdos_find_file_has_8dot3name(&fd)) {
5439: if(!FindNextFile(dtainfo->find_handle, &fd)) {
5440: FindClose(dtainfo->find_handle);
5441: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 5442: break;
5443: }
5444: }
5445: }
1.1.1.13 root 5446: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 5447: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
5448: msdos_find_file_conv_local_time(&fd);
5449: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
5450: find->size = fd.nFileSizeLow;
1.1.1.13 root 5451: strcpy(find->name, msdos_short_name(&fd));
1.1 root 5452: REG16(AX) = 0;
1.1.1.14 root 5453: } else if(dtainfo->allowable_mask & 8) {
1.1 root 5454: find->attrib = 8;
5455: find->size = 0;
5456: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 5457: dtainfo->allowable_mask &= ~8;
1.1 root 5458: REG16(AX) = 0;
5459: } else {
5460: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 5461: m_CF = 1;
1.1 root 5462: }
5463: }
5464:
5465: inline void msdos_int_21h_4fh()
5466: {
5467: process_t *process = msdos_process_info_get(current_psp);
1.1.1.13 root 5468: UINT32 dta_laddr = (process->dta.w.h << 4) + process->dta.w.l;
5469: find_t *find = (find_t *)(mem + dta_laddr);
1.1 root 5470: WIN32_FIND_DATA fd;
5471:
1.1.1.14 root 5472: if(find->find_magic != FIND_MAGIC || find->dta_index >= MAX_DTAINFO) {
5473: REG16(AX) = 0x12;
5474: m_CF = 1;
5475: return;
5476: }
5477: dtainfo_t *dtainfo = &dtalist[find->dta_index];
1.1.1.13 root 5478: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
5479: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 5480: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, 0) ||
1.1.1.13 root 5481: !msdos_find_file_has_8dot3name(&fd)) {
5482: if(!FindNextFile(dtainfo->find_handle, &fd)) {
5483: FindClose(dtainfo->find_handle);
5484: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 5485: break;
5486: }
5487: }
5488: } else {
1.1.1.13 root 5489: FindClose(dtainfo->find_handle);
5490: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 5491: }
5492: }
1.1.1.13 root 5493: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 5494: find->attrib = (UINT8)(fd.dwFileAttributes & 0x3f);
5495: msdos_find_file_conv_local_time(&fd);
5496: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->date, &find->time);
5497: find->size = fd.nFileSizeLow;
1.1.1.13 root 5498: strcpy(find->name, msdos_short_name(&fd));
1.1 root 5499: REG16(AX) = 0;
1.1.1.14 root 5500: } else if(dtainfo->allowable_mask & 8) {
1.1 root 5501: find->attrib = 8;
5502: find->size = 0;
5503: strcpy(find->name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 5504: dtainfo->allowable_mask &= ~8;
1.1 root 5505: REG16(AX) = 0;
5506: } else {
5507: REG16(AX) = 0x12;
1.1.1.3 root 5508: m_CF = 1;
1.1 root 5509: }
5510: }
5511:
5512: inline void msdos_int_21h_50h()
5513: {
1.1.1.8 root 5514: if(current_psp != REG16(BX)) {
5515: process_t *process = msdos_process_info_get(current_psp);
5516: if(process != NULL) {
5517: process->psp = REG16(BX);
5518: }
5519: current_psp = REG16(BX);
5520: }
1.1 root 5521: }
5522:
5523: inline void msdos_int_21h_51h()
5524: {
5525: REG16(BX) = current_psp;
5526: }
5527:
5528: inline void msdos_int_21h_52h()
5529: {
1.1.1.3 root 5530: SREG(ES) = (DOS_INFO_BASE >> 4);
5531: i386_load_segment_descriptor(ES);
1.1 root 5532: REG16(BX) = (DOS_INFO_BASE & 0x0f);
5533: }
5534:
5535: inline void msdos_int_21h_54h()
5536: {
5537: process_t *process = msdos_process_info_get(current_psp);
5538:
5539: REG8(AL) = process->verify;
5540: }
5541:
5542: inline void msdos_int_21h_55h()
5543: {
5544: psp_t *psp = (psp_t *)(mem + (REG16(DX) << 4));
5545:
5546: memcpy(mem + (REG16(DX) << 4), mem + (current_psp << 4), sizeof(psp_t));
5547: psp->int_22h.dw = *(UINT32 *)(mem + 4 * 0x22);
5548: psp->int_23h.dw = *(UINT32 *)(mem + 4 * 0x23);
5549: psp->int_24h.dw = *(UINT32 *)(mem + 4 * 0x24);
5550: psp->parent_psp = current_psp;
5551: }
5552:
5553: inline void msdos_int_21h_56h(int lfn)
5554: {
5555: char src[MAX_PATH], dst[MAX_PATH];
1.1.1.3 root 5556: strcpy(src, msdos_trimmed_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), lfn));
5557: strcpy(dst, msdos_trimmed_path((char *)(mem + SREG_BASE(ES) + REG16(DI)), lfn));
1.1 root 5558:
5559: if(rename(src, dst)) {
5560: REG16(AX) = errno;
1.1.1.3 root 5561: m_CF = 1;
1.1 root 5562: }
5563: }
5564:
5565: inline void msdos_int_21h_57h()
5566: {
5567: FILETIME time, local;
1.1.1.14 root 5568: FILETIME *ctime, *atime, *mtime;
1.1.1.6 root 5569: HANDLE handle;
1.1 root 5570:
1.1.1.14 root 5571: if((handle = (HANDLE)_get_osfhandle(REG16(BX))) == INVALID_HANDLE_VALUE) {
5572: REG16(AX) = (UINT16)GetLastError();
5573: m_CF = 1;
5574: return;
5575: }
5576: ctime = atime = mtime = NULL;
5577:
1.1 root 5578: switch(REG8(AL)) {
5579: case 0x00:
1.1.1.6 root 5580: case 0x01:
1.1.1.14 root 5581: mtime = &time;
1.1.1.6 root 5582: break;
5583: case 0x04:
5584: case 0x05:
1.1.1.14 root 5585: atime = &time;
1.1 root 5586: break;
1.1.1.6 root 5587: case 0x06:
5588: case 0x07:
1.1.1.14 root 5589: ctime = &time;
5590: break;
5591: default:
5592: REG16(AX) = 0x01;
5593: m_CF = 1;
5594: return;
5595: }
5596: if(REG8(AL) & 1) {
1.1 root 5597: DosDateTimeToFileTime(REG16(DX), REG16(CX), &local);
5598: LocalFileTimeToFileTime(&local, &time);
1.1.1.14 root 5599: if(!SetFileTime(handle, ctime, atime, mtime)) {
1.1 root 5600: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 5601: m_CF = 1;
1.1 root 5602: }
1.1.1.14 root 5603: } else {
5604: if(!GetFileTime(handle, ctime, atime, mtime)) {
5605: // assume a device and use the current time
5606: GetSystemTimeAsFileTime(&time);
5607: }
5608: FileTimeToLocalFileTime(&time, &local);
5609: FileTimeToDosDateTime(&local, ®16(DX), ®16(CX));
1.1 root 5610: }
5611: }
5612:
5613: inline void msdos_int_21h_58h()
5614: {
5615: switch(REG8(AL)) {
5616: case 0x00:
1.1.1.7 root 5617: REG16(AX) = malloc_strategy;
5618: break;
5619: case 0x01:
5620: switch(REG16(BX)) {
5621: case 0x0000:
5622: case 0x0001:
5623: case 0x0002:
5624: case 0x0040:
5625: case 0x0041:
5626: case 0x0042:
5627: case 0x0080:
5628: case 0x0081:
5629: case 0x0082:
5630: malloc_strategy = REG16(BX);
5631: break;
5632: default:
5633: REG16(AX) = 0x01;
5634: m_CF = 1;
5635: break;
5636: }
5637: break;
5638: case 0x02:
5639: REG8(AL) = umb_linked;
5640: break;
5641: case 0x03:
5642: switch(REG16(BX)) {
5643: case 0x0000:
5644: case 0x0001:
5645: umb_linked = REG8(BL);
5646: break;
5647: default:
5648: REG16(AX) = 0x01;
5649: m_CF = 1;
5650: break;
5651: }
1.1 root 5652: break;
5653: default:
5654: REG16(AX) = 0x01;
1.1.1.3 root 5655: m_CF = 1;
1.1 root 5656: break;
5657: }
5658: }
5659:
5660: inline void msdos_int_21h_59h()
5661: {
5662: REG16(AX) = error_code;
5663: switch(error_code) {
5664: case 4: // Too many open files
5665: case 8: // Insufficient memory
5666: REG8(BH) = 1; // Out of resource
5667: break;
5668: case 5: // Access denied
5669: REG8(BH) = 3; // Authorization
5670: break;
5671: case 7: // Memory control block destroyed
5672: REG8(BH) = 4; // Internal
5673: break;
5674: case 2: // File not found
5675: case 3: // Path not found
5676: case 15: // Invaid drive specified
5677: case 18: // No more files
5678: REG8(BH) = 8; // Not found
5679: break;
5680: case 32: // Sharing violation
5681: case 33: // Lock violation
5682: REG8(BH) = 10; // Locked
5683: break;
5684: // case 16: // Removal of current directory attempted
5685: case 19: // Attempted write on protected disk
5686: case 21: // Drive not ready
5687: // case 29: // Write failure
5688: // case 30: // Read failure
5689: // case 82: // Cannot create subdirectory
5690: REG8(BH) = 11; // Media
5691: break;
5692: case 80: // File already exists
5693: REG8(BH) = 12; // Already exist
5694: break;
5695: default:
5696: REG8(BH) = 13; // Unknown
5697: break;
5698: }
5699: REG8(BL) = 1; // Retry
5700: REG8(CH) = 1; // Unknown
5701: }
5702:
5703: inline void msdos_int_21h_5ah()
5704: {
1.1.1.3 root 5705: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 5706: int len = strlen(path);
5707: char tmp[MAX_PATH];
5708:
5709: if(GetTempFileName(path, "TMP", 0, tmp)) {
5710: int fd = _open(tmp, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
5711:
5712: SetFileAttributes(tmp, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
5713: REG16(AX) = fd;
5714: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
5715:
5716: strcpy(path, tmp);
5717: int dx = REG16(DX) + len;
1.1.1.3 root 5718: int ds = SREG(DS);
1.1 root 5719: while(dx > 0xffff) {
5720: dx -= 0x10;
5721: ds++;
5722: }
5723: REG16(DX) = dx;
1.1.1.3 root 5724: SREG(DS) = ds;
5725: i386_load_segment_descriptor(DS);
1.1 root 5726: } else {
5727: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 5728: m_CF = 1;
1.1 root 5729: }
5730: }
5731:
5732: inline void msdos_int_21h_5bh()
5733: {
1.1.1.3 root 5734: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(DX)), 0);
1.1 root 5735:
5736: if(_access(path, 0) == 0) {
5737: // already exists
5738: REG16(AX) = 0x50;
1.1.1.3 root 5739: m_CF = 1;
1.1 root 5740: } else {
5741: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
5742:
5743: if(fd != -1) {
5744: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
5745: REG16(AX) = fd;
5746: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
5747: } else {
5748: REG16(AX) = errno;
1.1.1.3 root 5749: m_CF = 1;
1.1 root 5750: }
5751: }
5752: }
5753:
5754: inline void msdos_int_21h_5ch()
5755: {
5756: process_t *process = msdos_process_info_get(current_psp);
5757:
5758: if(REG16(BX) < process->max_files && file_handler[REG16(BX)].valid) {
5759: if(REG8(AL) == 0 || REG8(AL) == 1) {
5760: static int modes[2] = {_LK_LOCK, _LK_UNLCK};
5761: UINT32 pos = _tell(REG16(BX));
5762: _lseek(REG16(BX), (REG16(CX) << 16) | REG16(DX), SEEK_SET);
5763: if(_locking(REG16(BX), modes[REG8(AL)], (REG16(SI) << 16) | REG16(DI))) {
5764: REG16(AX) = errno;
1.1.1.3 root 5765: m_CF = 1;
1.1 root 5766: }
5767: _lseek(REG16(BX), pos, SEEK_SET);
5768: // some seconds may be passed in _locking()
5769: hardware_update();
5770: } else {
5771: REG16(AX) = 0x01;
1.1.1.3 root 5772: m_CF = 1;
1.1 root 5773: }
5774: } else {
5775: REG16(AX) = 0x06;
1.1.1.3 root 5776: m_CF = 1;
1.1 root 5777: }
5778: }
5779:
5780: inline void msdos_int_21h_60h(int lfn)
5781: {
1.1.1.14 root 5782: char full[MAX_PATH], *path;
5783:
1.1 root 5784: if(lfn) {
1.1.1.14 root 5785: char *name;
5786: *full = '\0';
1.1.1.3 root 5787: GetFullPathName((char *)(mem + SREG_BASE(DS) + REG16(SI)), MAX_PATH, full, &name);
1.1.1.14 root 5788: switch(REG8(CL)) {
5789: case 1:
5790: GetShortPathName(full, full, MAX_PATH);
5791: my_strupr(full);
5792: break;
5793: case 2:
5794: GetLongPathName(full, full, MAX_PATH);
5795: break;
5796: }
5797: path = full;
5798: } else {
5799: path = msdos_short_full_path((char *)(mem + SREG_BASE(DS) + REG16(SI)));
5800: }
5801: if(*path != '\0') {
5802: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), path);
1.1 root 5803: } else {
1.1.1.14 root 5804: REG16(AX) = (UINT16)GetLastError();
5805: m_CF = 1;
1.1 root 5806: }
5807: }
5808:
5809: inline void msdos_int_21h_61h()
5810: {
5811: REG8(AL) = 0;
5812: }
5813:
5814: inline void msdos_int_21h_62h()
5815: {
5816: REG16(BX) = current_psp;
5817: }
5818:
5819: inline void msdos_int_21h_63h()
5820: {
5821: switch(REG8(AL)) {
5822: case 0x00:
1.1.1.3 root 5823: SREG(DS) = (DBCS_TABLE >> 4);
5824: i386_load_segment_descriptor(DS);
1.1 root 5825: REG16(SI) = (DBCS_TABLE & 0x0f);
5826: REG8(AL) = 0x00;
5827: break;
5828: default:
5829: REG16(AX) = 0x01;
1.1.1.3 root 5830: m_CF = 1;
1.1 root 5831: break;
5832: }
5833: }
5834:
5835: inline void msdos_int_21h_65h()
5836: {
5837: char tmp[0x10000];
5838:
5839: switch(REG8(AL)) {
5840: case 0x07:
1.1.1.3 root 5841: *(UINT8 *)(mem + SREG_BASE(ES) + REG16(DI) + 0) = 0x07;
5842: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 1) = (DBCS_TOP & 0x0f);
5843: *(UINT16 *)(mem + SREG_BASE(ES) + REG16(DI) + 3) = (DBCS_TOP >> 4);
1.1 root 5844: REG16(CX) = 0x05;
5845: break;
5846: case 0x20:
5847: sprintf(tmp, "%c", REG8(DL));
5848: my_strupr(tmp);
5849: REG8(DL) = tmp[0];
5850: break;
5851: case 0x21:
5852: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 5853: memcpy(tmp, mem + SREG_BASE(DS) + REG16(DX), REG16(CX));
1.1 root 5854: my_strupr(tmp);
1.1.1.3 root 5855: memcpy(mem + SREG_BASE(DS) + REG16(DX), tmp, REG16(CX));
1.1 root 5856: break;
5857: case 0x22:
1.1.1.3 root 5858: my_strupr((char *)(mem + SREG_BASE(DS) + REG16(DX)));
1.1 root 5859: break;
5860: default:
5861: REG16(AX) = 0x01;
1.1.1.3 root 5862: m_CF = 1;
1.1 root 5863: break;
5864: }
5865: }
5866:
5867: inline void msdos_int_21h_66h()
5868: {
5869: switch(REG8(AL)) {
5870: case 0x01:
5871: REG16(BX) = active_code_page;
5872: REG16(DX) = system_code_page;
5873: break;
5874: case 0x02:
5875: if(active_code_page == REG16(BX)) {
5876: REG16(AX) = 0xeb41;
5877: } else if(_setmbcp(REG16(BX)) == 0) {
5878: active_code_page = REG16(BX);
5879: msdos_dbcs_table_update();
5880: REG16(AX) = 0xeb41;
5881: } else {
5882: REG16(AX) = 0x25;
1.1.1.3 root 5883: m_CF = 1;
1.1 root 5884: }
5885: break;
5886: default:
5887: REG16(AX) = 0x01;
1.1.1.3 root 5888: m_CF = 1;
1.1 root 5889: break;
5890: }
5891: }
5892:
5893: inline void msdos_int_21h_67h()
5894: {
5895: process_t *process = msdos_process_info_get(current_psp);
5896:
5897: if(REG16(BX) <= MAX_FILES) {
5898: process->max_files = max(REG16(BX), 20);
5899: } else {
5900: REG16(AX) = 0x08;
1.1.1.3 root 5901: m_CF = 1;
1.1 root 5902: }
5903: }
5904:
5905: inline void msdos_int_21h_68h()
5906: {
5907: process_t *process = msdos_process_info_get(current_psp);
5908:
5909: if(REG16(BX) < process->max_files && file_handler[REG16(BX)].valid) {
5910: // fflush(_fdopen(REG16(BX), ""));
5911: } else {
5912: REG16(AX) = 0x06;
1.1.1.3 root 5913: m_CF = 1;
1.1 root 5914: }
5915: }
5916:
5917: inline void msdos_int_21h_69h()
5918: {
1.1.1.3 root 5919: drive_info_t *info = (drive_info_t *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 5920: char path[] = "A:\\";
5921: char volume_label[MAX_PATH];
5922: DWORD serial_number = 0;
5923: char file_system[MAX_PATH];
5924:
5925: if(REG8(BL) == 0) {
5926: path[0] = 'A' + _getdrive() - 1;
5927: } else {
5928: path[0] = 'A' + REG8(BL) - 1;
5929: }
5930:
5931: switch(REG8(AL)) {
5932: case 0x00:
5933: if(GetVolumeInformation(path, volume_label, MAX_PATH, &serial_number, NULL, NULL, file_system, MAX_PATH)) {
5934: info->info_level = 0;
5935: info->serial_number = serial_number;
5936: memset(info->volume_label, 0x20, 11);
5937: memcpy(info->volume_label, volume_label, min(strlen(volume_label), 11));
5938: memset(info->file_system, 0x20, 8);
5939: memcpy(info->file_system, file_system, min(strlen(file_system), 8));
5940: } else {
5941: REG16(AX) = errno;
1.1.1.3 root 5942: m_CF = 1;
1.1 root 5943: }
5944: break;
5945: case 0x01:
5946: REG16(AX) = 0x03;
1.1.1.3 root 5947: m_CF = 1;
1.1 root 5948: }
5949: }
5950:
5951: inline void msdos_int_21h_6ah()
5952: {
5953: REG8(AH) = 0x68;
5954: msdos_int_21h_68h();
5955: }
5956:
5957: inline void msdos_int_21h_6bh()
5958: {
5959: REG8(AL) = 0;
5960: }
5961:
5962: inline void msdos_int_21h_6ch(int lfn)
5963: {
1.1.1.3 root 5964: char *path = msdos_local_file_path((char *)(mem + SREG_BASE(DS) + REG16(SI)), lfn);
1.1 root 5965: int mode = REG8(BL) & 0x03;
5966:
5967: if(mode < 0x03) {
5968: if(_access(path, 0) == 0) {
5969: // file exists
5970: if(REG8(DL) & 1) {
1.1.1.11 root 5971: int fd = -1;
5972: UINT16 info;
1.1 root 5973:
1.1.1.11 root 5974: if(msdos_is_con_path(path)) {
1.1.1.13 root 5975: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 5976: info = 0x80d3;
1.1.1.14 root 5977: } else if(msdos_is_nul_path(path)) {
5978: fd = msdos_open("NUL", file_mode[mode].mode);
5979: info = 0x80d3;
1.1.1.11 root 5980: } else {
1.1.1.13 root 5981: fd = msdos_open(path, file_mode[mode].mode);
1.1.1.11 root 5982: info = msdos_drive_number(path);
5983: }
1.1 root 5984: if(fd != -1) {
5985: REG16(AX) = fd;
5986: REG16(CX) = 1;
1.1.1.11 root 5987: msdos_file_handler_open(fd, path, _isatty(fd), mode, info, current_psp);
1.1 root 5988: } else {
5989: REG16(AX) = errno;
1.1.1.3 root 5990: m_CF = 1;
1.1 root 5991: }
5992: } else if(REG8(DL) & 2) {
5993: int attr = GetFileAttributes(path);
5994: int fd = -1;
1.1.1.11 root 5995: UINT16 info;
1.1 root 5996:
1.1.1.11 root 5997: if(msdos_is_con_path(path)) {
1.1.1.13 root 5998: fd = msdos_open("CON", file_mode[mode].mode);
1.1.1.11 root 5999: info = 0x80d3;
1.1.1.14 root 6000: } else if(msdos_is_nul_path(path)) {
6001: fd = msdos_open("NUL", file_mode[mode].mode);
6002: info = 0x80d3;
1.1 root 6003: } else {
6004: fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
1.1.1.11 root 6005: info = msdos_drive_number(path);
1.1 root 6006: }
6007: if(fd != -1) {
6008: if(attr == -1) {
6009: attr = msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY;
6010: }
6011: SetFileAttributes(path, attr);
6012: REG16(AX) = fd;
6013: REG16(CX) = 3;
1.1.1.11 root 6014: msdos_file_handler_open(fd, path, _isatty(fd), 2, info, current_psp);
1.1 root 6015: } else {
6016: REG16(AX) = errno;
1.1.1.3 root 6017: m_CF = 1;
1.1 root 6018: }
6019: } else {
6020: REG16(AX) = 0x50;
1.1.1.3 root 6021: m_CF = 1;
1.1 root 6022: }
6023: } else {
6024: // file not exists
6025: if(REG8(DL) & 0x10) {
6026: int fd = _open(path, _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE);
6027:
6028: if(fd != -1) {
6029: SetFileAttributes(path, msdos_file_attribute_create(REG16(CX)) & ~FILE_ATTRIBUTE_READONLY);
6030: REG16(AX) = fd;
6031: REG16(CX) = 2;
6032: msdos_file_handler_open(fd, path, _isatty(fd), 2, msdos_drive_number(path), current_psp);
6033: } else {
6034: REG16(AX) = errno;
1.1.1.3 root 6035: m_CF = 1;
1.1 root 6036: }
6037: } else {
6038: REG16(AX) = 0x02;
1.1.1.3 root 6039: m_CF = 1;
1.1 root 6040: }
6041: }
6042: } else {
6043: REG16(AX) = 0x0c;
1.1.1.3 root 6044: m_CF = 1;
1.1 root 6045: }
6046: }
6047:
6048: inline void msdos_int_21h_710dh()
6049: {
6050: // reset drive
6051: }
6052:
6053: inline void msdos_int_21h_714eh()
6054: {
6055: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 6056: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
6057: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 6058: WIN32_FIND_DATA fd;
6059:
1.1.1.13 root 6060: dtainfo_t *dtainfo = msdos_dta_info_get(current_psp, LFN_DTA_LADDR);
6061: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
6062: FindClose(dtainfo->find_handle);
6063: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6064: }
6065: strcpy(process->volume_label, msdos_volume_label(path));
1.1.1.14 root 6066: dtainfo->allowable_mask = REG8(CL);
6067: dtainfo->required_mask = REG8(CH);
6068: bool label_only = (dtainfo->allowable_mask == 8);
1.1 root 6069:
1.1.1.14 root 6070: if((dtainfo->allowable_mask & 8) && !msdos_match_volume_label(path, msdos_short_volume_label(process->volume_label))) {
6071: dtainfo->allowable_mask &= ~8;
1.1 root 6072: }
1.1.1.14 root 6073: if(!label_only && (dtainfo->find_handle = FindFirstFile(path, &fd)) != INVALID_HANDLE_VALUE) {
6074: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 6075: if(!FindNextFile(dtainfo->find_handle, &fd)) {
6076: FindClose(dtainfo->find_handle);
6077: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6078: break;
6079: }
6080: }
6081: }
1.1.1.13 root 6082: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 6083: find->attrib = fd.dwFileAttributes;
6084: msdos_find_file_conv_local_time(&fd);
6085: if(REG16(SI) == 0) {
6086: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
6087: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
6088: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
6089: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
6090: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
6091: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
6092: } else {
6093: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
6094: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
6095: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
6096: }
6097: find->size_hi = fd.nFileSizeHigh;
6098: find->size_lo = fd.nFileSizeLow;
6099: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 6100: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14 root 6101: REG16(AX) = dtainfo - dtalist + 1;
6102: } else if(dtainfo->allowable_mask & 8) {
1.1 root 6103: // volume label
6104: find->attrib = 8;
6105: find->size_hi = find->size_lo = 0;
6106: strcpy(find->full_name, process->volume_label);
6107: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 6108: dtainfo->allowable_mask &= ~8;
6109: REG16(AX) = dtainfo - dtalist + 1;
1.1 root 6110: } else {
6111: REG16(AX) = 0x12; // NOTE: return 0x02 if file path is invalid
1.1.1.3 root 6112: m_CF = 1;
1.1 root 6113: }
6114: }
6115:
6116: inline void msdos_int_21h_714fh()
6117: {
6118: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 6119: find_lfn_t *find = (find_lfn_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 6120: WIN32_FIND_DATA fd;
6121:
1.1.1.14 root 6122: if(REG16(BX) - 1u >= MAX_DTAINFO) {
6123: REG16(AX) = 6;
1.1.1.13 root 6124: m_CF = 1;
6125: return;
6126: }
1.1.1.14 root 6127: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 6128: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
6129: if(FindNextFile(dtainfo->find_handle, &fd)) {
1.1.1.14 root 6130: while(!msdos_find_file_check_attribute(fd.dwFileAttributes, dtainfo->allowable_mask, dtainfo->required_mask)) {
1.1.1.13 root 6131: if(!FindNextFile(dtainfo->find_handle, &fd)) {
6132: FindClose(dtainfo->find_handle);
6133: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6134: break;
6135: }
6136: }
6137: } else {
1.1.1.13 root 6138: FindClose(dtainfo->find_handle);
6139: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6140: }
6141: }
1.1.1.13 root 6142: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
1.1 root 6143: find->attrib = fd.dwFileAttributes;
6144: msdos_find_file_conv_local_time(&fd);
6145: if(REG16(SI) == 0) {
6146: find->ctime_lo.dw = fd.ftCreationTime.dwLowDateTime;
6147: find->ctime_hi.dw = fd.ftCreationTime.dwHighDateTime;
6148: find->atime_lo.dw = fd.ftLastAccessTime.dwLowDateTime;
6149: find->atime_hi.dw = fd.ftLastAccessTime.dwHighDateTime;
6150: find->mtime_lo.dw = fd.ftLastWriteTime.dwLowDateTime;
6151: find->mtime_hi.dw = fd.ftLastWriteTime.dwHighDateTime;
6152: } else {
6153: FileTimeToDosDateTime(&fd.ftCreationTime, &find->ctime_lo.w.h, &find->ctime_lo.w.l);
6154: FileTimeToDosDateTime(&fd.ftLastAccessTime, &find->atime_lo.w.h, &find->atime_lo.w.l);
6155: FileTimeToDosDateTime(&fd.ftLastWriteTime, &find->mtime_lo.w.h, &find->mtime_lo.w.l);
6156: }
6157: find->size_hi = fd.nFileSizeHigh;
6158: find->size_lo = fd.nFileSizeLow;
6159: strcpy(find->full_name, fd.cFileName);
1.1.1.13 root 6160: strcpy(find->short_name, fd.cAlternateFileName);
1.1.1.14 root 6161: } else if(dtainfo->allowable_mask & 8) {
1.1 root 6162: // volume label
6163: find->attrib = 8;
6164: find->size_hi = find->size_lo = 0;
6165: strcpy(find->full_name, process->volume_label);
6166: strcpy(find->short_name, msdos_short_volume_label(process->volume_label));
1.1.1.14 root 6167: dtainfo->allowable_mask &= ~8;
1.1 root 6168: } else {
6169: REG16(AX) = 0x12;
1.1.1.3 root 6170: m_CF = 1;
1.1 root 6171: }
6172: }
6173:
6174: inline void msdos_int_21h_71a0h()
6175: {
6176: DWORD max_component_len, file_sys_flag;
6177:
1.1.1.14 root 6178: 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))) {
6179: REG16(BX) = (UINT16)file_sys_flag & (FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK | FILE_VOLUME_IS_COMPRESSED);
6180: REG16(BX) |= 0x4000; // supports LFN functions
1.1 root 6181: REG16(CX) = (UINT16)max_component_len; // 255
6182: REG16(DX) = (UINT16)max_component_len + 5; // 260
6183: } else {
6184: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 6185: m_CF = 1;
1.1 root 6186: }
6187: }
6188:
6189: inline void msdos_int_21h_71a1h()
6190: {
1.1.1.14 root 6191: if(REG16(BX) - 1u >= MAX_DTAINFO) {
6192: REG16(AX) = 6;
1.1.1.13 root 6193: m_CF = 1;
6194: return;
6195: }
1.1.1.14 root 6196: dtainfo_t *dtainfo = &dtalist[REG16(BX) - 1];
1.1.1.13 root 6197: if(dtainfo->find_handle != INVALID_HANDLE_VALUE) {
6198: FindClose(dtainfo->find_handle);
6199: dtainfo->find_handle = INVALID_HANDLE_VALUE;
1.1 root 6200: }
6201: }
6202:
6203: inline void msdos_int_21h_71a6h()
6204: {
6205: process_t *process = msdos_process_info_get(current_psp);
1.1.1.3 root 6206: UINT8 *buffer = (UINT8 *)(mem + SREG_BASE(DS) + REG16(DX));
1.1 root 6207: struct _stat64 status;
6208: DWORD serial_number = 0;
6209:
6210: if(REG16(BX) < process->max_files && file_handler[REG16(BX)].valid) {
6211: if(_fstat64(REG16(BX), &status) == 0) {
6212: if(file_handler[REG16(BX)].path[1] == ':') {
6213: // NOTE: we need to consider the network file path "\\host\share\"
6214: char volume[] = "A:\\";
6215: volume[0] = file_handler[REG16(BX)].path[1];
6216: GetVolumeInformation(volume, NULL, 0, &serial_number, NULL, NULL, NULL, 0);
6217: }
6218: *(UINT32 *)(buffer + 0x00) = GetFileAttributes(file_handler[REG16(BX)].path);
6219: *(UINT32 *)(buffer + 0x04) = (UINT32)(status.st_ctime & 0xffffffff);
6220: *(UINT32 *)(buffer + 0x08) = (UINT32)((status.st_ctime >> 32) & 0xffffffff);
6221: *(UINT32 *)(buffer + 0x0c) = (UINT32)(status.st_atime & 0xffffffff);
6222: *(UINT32 *)(buffer + 0x10) = (UINT32)((status.st_atime >> 32) & 0xffffffff);
6223: *(UINT32 *)(buffer + 0x14) = (UINT32)(status.st_mtime & 0xffffffff);
6224: *(UINT32 *)(buffer + 0x18) = (UINT32)((status.st_mtime >> 32) & 0xffffffff);
6225: *(UINT32 *)(buffer + 0x1c) = serial_number;
6226: *(UINT32 *)(buffer + 0x20) = (UINT32)((status.st_size >> 32) & 0xffffffff);
6227: *(UINT32 *)(buffer + 0x24) = (UINT32)(status.st_size & 0xffffffff);
6228: *(UINT32 *)(buffer + 0x28) = status.st_nlink;
1.1.1.14 root 6229: // this is dummy id and it will be changed when it is reopened...
1.1 root 6230: *(UINT32 *)(buffer + 0x2c) = 0;
6231: *(UINT32 *)(buffer + 0x30) = file_handler[REG16(BX)].id;
6232: } else {
6233: REG16(AX) = errno;
1.1.1.3 root 6234: m_CF = 1;
1.1 root 6235: }
6236: } else {
6237: REG16(AX) = 0x06;
1.1.1.3 root 6238: m_CF = 1;
1.1 root 6239: }
6240: }
6241:
6242: inline void msdos_int_21h_71a7h()
6243: {
6244: switch(REG8(BL)) {
6245: case 0x00:
1.1.1.3 root 6246: if(!FileTimeToDosDateTime((FILETIME *)(mem + SREG_BASE(DS) + REG16(SI)), ®16(DX), ®16(CX))) {
1.1 root 6247: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 6248: m_CF = 1;
1.1 root 6249: }
6250: break;
6251: case 0x01:
6252: // NOTE: we need to check BH that shows 10-millisecond untils past time in CX
1.1.1.3 root 6253: if(!DosDateTimeToFileTime(REG16(DX), REG16(CX), (FILETIME *)(mem + SREG_BASE(ES) + REG16(DI)))) {
1.1 root 6254: REG16(AX) = (UINT16)GetLastError();
1.1.1.3 root 6255: m_CF = 1;
1.1 root 6256: }
6257: break;
6258: default:
6259: REG16(AX) = 0x01;
1.1.1.3 root 6260: m_CF = 1;
1.1 root 6261: break;
6262: }
6263: }
6264:
6265: inline void msdos_int_21h_71a8h()
6266: {
6267: if(REG8(DH) == 0) {
6268: char tmp[MAX_PATH], fcb[MAX_PATH];
1.1.1.3 root 6269: strcpy(tmp, msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 6270: memset(fcb, 0x20, sizeof(fcb));
6271: int len = strlen(tmp);
6272: int pos = 0;
6273: for(int i = 0; i < len; i++) {
6274: if(tmp[i] == '.') {
6275: pos = 8;
6276: } else {
6277: if(msdos_lead_byte_check(tmp[i])) {
6278: fcb[pos++] = tmp[i++];
6279: }
6280: fcb[pos++] = tmp[i];
6281: }
6282: }
1.1.1.3 root 6283: memcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), fcb, 11);
1.1 root 6284: } else {
1.1.1.3 root 6285: strcpy((char *)(mem + SREG_BASE(ES) + REG16(DI)), msdos_short_path((char *)(mem + SREG_BASE(DS) + REG16(SI))));
1.1 root 6286: }
6287: }
6288:
1.1.1.14 root 6289: inline void msdos_int_21h_7300h()
6290: {
6291: if(REG8(AL) == 0) {
6292: REG8(AL) = REG8(CL);
6293: REG8(AH) = 0;
6294: } else {
6295: REG16(AX) = 0x01;
6296: m_CF = 1;
6297: }
6298: }
6299:
6300: inline void msdos_int_21h_7302h()
6301: {
6302: int drive_num = (REG8(DL) == 0) ? (_getdrive() - 1) : (REG8(DL) - 1);
6303: UINT16 seg, ofs;
6304:
6305: if(REG16(CX) < 0x3f) {
6306: REG8(AL) = 0x18;
6307: m_CF = 1;
6308: } else if(!msdos_drive_param_block_update(drive_num, &seg, &ofs, 1)) {
6309: REG8(AL) = 0xff;
6310: m_CF = 1;
6311: } else {
6312: memcpy(mem + SREG_BASE(ES) + REG16(DI) + 2, mem + (seg << 4) + ofs, sizeof(dpb_t));
6313: }
6314: }
6315:
1.1 root 6316: inline void msdos_int_21h_7303h()
6317: {
1.1.1.3 root 6318: char *path = (char *)(mem + SREG_BASE(DS) + REG16(DX));
6319: ext_space_info_t *info = (ext_space_info_t *)(mem + SREG_BASE(ES) + REG16(DI));
1.1 root 6320: DWORD sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
6321:
6322: if(GetDiskFreeSpace(path, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
6323: info->size_of_structure = sizeof(ext_space_info_t);
6324: info->structure_version = 0;
6325: info->sectors_per_cluster = sectors_per_cluster;
6326: info->bytes_per_sector = bytes_per_sector;
6327: info->available_clusters_on_drive = free_clusters;
6328: info->total_clusters_on_drive = total_clusters;
6329: info->available_sectors_on_drive = sectors_per_cluster * free_clusters;
6330: info->total_sectors_on_drive = sectors_per_cluster * total_clusters;
6331: info->available_allocation_units = free_clusters; // ???
6332: info->total_allocation_units = total_clusters; // ???
6333: } else {
6334: REG16(AX) = errno;
1.1.1.3 root 6335: m_CF = 1;
1.1 root 6336: }
6337: }
6338:
6339: inline void msdos_int_25h()
6340: {
6341: UINT16 seg, ofs;
6342: DWORD dwSize;
6343:
1.1.1.3 root 6344: #if defined(HAS_I386)
6345: I386OP(pushf)();
6346: #else
6347: PREFIX86(_pushf());
6348: #endif
1.1 root 6349:
6350: if(!(REG8(AL) < 26)) {
6351: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 6352: m_CF = 1;
1.1 root 6353: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
6354: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 6355: m_CF = 1;
1.1 root 6356: } else {
6357: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
6358: char dev[64];
6359: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
6360:
6361: HANDLE hFile = CreateFile(dev, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
6362: if(hFile == INVALID_HANDLE_VALUE) {
6363: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 6364: m_CF = 1;
1.1 root 6365: } else {
6366: if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
6367: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 6368: m_CF = 1;
1.1 root 6369: } else if(SetFilePointer(hFile, REG16(DX) * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
6370: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 6371: m_CF = 1;
6372: } else if(ReadFile(hFile, mem + SREG_BASE(DS) + REG16(BX), REG16(CX) * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 6373: REG8(AL) = 0x0b; // read error
1.1.1.3 root 6374: m_CF = 1;
1.1 root 6375: }
6376: CloseHandle(hFile);
6377: }
6378: }
6379: }
6380:
6381: inline void msdos_int_26h()
6382: {
6383: // this operation may cause serious damage for drives, so always returns error...
6384: UINT16 seg, ofs;
6385: DWORD dwSize;
6386:
1.1.1.3 root 6387: #if defined(HAS_I386)
6388: I386OP(pushf)();
6389: #else
6390: PREFIX86(_pushf());
6391: #endif
1.1 root 6392:
6393: if(!(REG8(AL) < 26)) {
6394: REG8(AL) = 0x01; // unit unknown
1.1.1.3 root 6395: m_CF = 1;
1.1 root 6396: } else if(!msdos_drive_param_block_update(REG8(AL), &seg, &ofs, 0)) {
6397: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 6398: m_CF = 1;
1.1 root 6399: } else {
6400: dpb_t *dpb = (dpb_t *)(mem + (seg << 4) + ofs);
6401: char dev[64];
6402: sprintf(dev, "\\\\.\\%c:", 'A' + REG8(AL));
6403:
6404: if(dpb->media_type == 0xf8) {
6405: // this drive is not a floppy
1.1.1.6 root 6406: // if(!(((dos_info_t *)(mem + DOS_INFO_TOP))->dos_flag & 0x40)) {
6407: // fatalerror("This application tried the absolute disk write to drive %c:\n", 'A' + REG8(AL));
6408: // }
1.1 root 6409: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 6410: m_CF = 1;
1.1 root 6411: } else {
6412: HANDLE hFile = CreateFile(dev, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);
6413: if(hFile == INVALID_HANDLE_VALUE) {
6414: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 6415: m_CF = 1;
1.1 root 6416: } else {
6417: if(DeviceIoControl(hFile, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL) == 0) {
6418: REG8(AL) = 0x02; // drive not ready
1.1.1.3 root 6419: m_CF = 1;
1.1 root 6420: } else if(SetFilePointer(hFile, REG16(DX) * dpb->bytes_per_sector, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
6421: REG8(AL) = 0x08; // sector not found
1.1.1.3 root 6422: m_CF = 1;
6423: } else if(WriteFile(hFile, mem + SREG_BASE(DS) + REG16(BX), REG16(CX) * dpb->bytes_per_sector, &dwSize, NULL) == 0) {
1.1 root 6424: REG8(AL) = 0x0a; // write error
1.1.1.3 root 6425: m_CF = 1;
1.1 root 6426: }
6427: CloseHandle(hFile);
6428: }
6429: }
6430: }
6431: }
6432:
6433: inline void msdos_int_27h()
6434: {
1.1.1.14 root 6435: msdos_mem_realloc(SREG(CS), (REG16(DX) + 15) >> 4, NULL);
1.1.1.3 root 6436: msdos_process_terminate(SREG(CS), retval | 0x300, 0);
1.1.1.14 root 6437:
6438: // int_21h_4bh succeeded
6439: m_CF = 0;
1.1 root 6440: }
6441:
6442: inline void msdos_int_29h()
6443: {
1.1.1.14 root 6444: #if 1
6445: // need to check escape sequences
1.1 root 6446: msdos_putch(REG8(AL));
1.1.1.14 root 6447: #else
6448: DWORD num;
6449:
6450: vram_flush();
6451: WriteConsole(hStdout, ®8(AL), 1, &num, NULL);
6452: cursor_moved = true;
6453: #endif
1.1 root 6454: }
6455:
6456: inline void msdos_int_2eh()
6457: {
6458: char tmp[MAX_PATH], command[MAX_PATH], opt[MAX_PATH];
6459: memset(tmp, 0, sizeof(tmp));
1.1.1.3 root 6460: strcpy(tmp, (char *)(mem + SREG_BASE(DS) + REG16(SI)));
1.1 root 6461: char *token = my_strtok(tmp, " ");
6462: strcpy(command, token);
6463: strcpy(opt, token + strlen(token) + 1);
6464:
6465: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
6466: param->env_seg = 0;
6467: param->cmd_line.w.l = 44;
6468: param->cmd_line.w.h = (WORK_TOP >> 4);
6469: param->fcb1.w.l = 24;
6470: param->fcb1.w.h = (WORK_TOP >> 4);
6471: param->fcb2.w.l = 24;
6472: param->fcb2.w.h = (WORK_TOP >> 4);
6473:
6474: memset(mem + WORK_TOP + 24, 0x20, 20);
6475:
6476: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
6477: cmd_line->len = strlen(opt);
6478: strcpy(cmd_line->cmd, opt);
6479: cmd_line->cmd[cmd_line->len] = 0x0d;
6480:
6481: msdos_process_exec(command, param, 0);
6482: REG8(AL) = 0;
6483: }
6484:
6485: inline void msdos_int_2fh_16h()
6486: {
6487: switch(REG8(AL)) {
6488: case 0x00:
1.1.1.14 root 6489: if(no_windows) {
6490: REG8(AL) = 0;
6491: } else {
1.1 root 6492: OSVERSIONINFO osvi;
6493: ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
6494: osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
6495: GetVersionEx(&osvi);
6496: REG8(AL) = osvi.dwMajorVersion;
6497: REG8(AH) = osvi.dwMinorVersion;
6498: }
6499: break;
1.1.1.14 root 6500: case 0x80:
6501: Sleep(10);
6502: hardware_update();
6503: REG8(AL) = 0;
6504: break;
1.1 root 6505: default:
6506: REG16(AX) = 0x01;
1.1.1.3 root 6507: m_CF = 1;
1.1 root 6508: break;
6509: }
6510: }
6511:
6512: inline void msdos_int_2fh_1ah()
6513: {
6514: switch(REG8(AL)) {
6515: case 0x00:
6516: // ansi.sys is installed
6517: REG8(AL) = 0xff;
6518: break;
6519: default:
6520: REG16(AX) = 0x01;
1.1.1.3 root 6521: m_CF = 1;
1.1 root 6522: break;
6523: }
6524: }
6525:
6526: inline void msdos_int_2fh_43h()
6527: {
6528: switch(REG8(AL)) {
6529: case 0x00:
6530: // xms is not installed
6531: REG8(AL) = 0;
6532: break;
6533: default:
6534: REG16(AX) = 0x01;
1.1.1.3 root 6535: m_CF = 1;
1.1 root 6536: break;
6537: }
6538: }
6539:
6540: inline void msdos_int_2fh_4ah()
6541: {
6542: switch(REG8(AL)) {
6543: case 0x01:
6544: case 0x02:
6545: // hma is not installed
6546: REG16(BX) = 0;
1.1.1.3 root 6547: SREG(ES) = 0xffff;
6548: i386_load_segment_descriptor(ES);
1.1 root 6549: REG16(DI) = 0xffff;
6550: break;
6551: default:
6552: REG16(AX) = 0x01;
1.1.1.3 root 6553: m_CF = 1;
1.1 root 6554: break;
6555: }
6556: }
6557:
6558: inline void msdos_int_2fh_4fh()
6559: {
6560: switch(REG8(AL)) {
6561: case 0x00:
6562: REG16(AX) = 0;
6563: REG8(DL) = 1; // major version
6564: REG8(DH) = 0; // minor version
6565: break;
6566: case 0x01:
6567: REG16(AX) = 0;
6568: REG16(BX) = active_code_page;
6569: break;
6570: default:
6571: REG16(AX) = 0x01;
1.1.1.3 root 6572: m_CF = 1;
1.1 root 6573: break;
6574: }
6575: }
6576:
6577: inline void msdos_int_2fh_aeh()
6578: {
6579: switch(REG8(AL)) {
6580: case 0x00:
6581: REG8(AL) = 0;
6582: break;
6583: case 0x01:
6584: {
6585: char command[MAX_PATH];
6586: memset(command, 0, sizeof(command));
1.1.1.3 root 6587: memcpy(command, mem + SREG_BASE(DS) + REG16(SI) + 1, mem[SREG_BASE(DS) + REG16(SI)]);
1.1 root 6588:
6589: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
6590: param->env_seg = 0;
6591: param->cmd_line.w.l = 44;
6592: param->cmd_line.w.h = (WORK_TOP >> 4);
6593: param->fcb1.w.l = 24;
6594: param->fcb1.w.h = (WORK_TOP >> 4);
6595: param->fcb2.w.l = 24;
6596: param->fcb2.w.h = (WORK_TOP >> 4);
6597:
6598: memset(mem + WORK_TOP + 24, 0x20, 20);
6599:
6600: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
1.1.1.3 root 6601: cmd_line->len = mem[SREG_BASE(DS) + REG16(BX) + 1];
6602: memcpy(cmd_line->cmd, mem + SREG_BASE(DS) + REG16(BX) + 2, cmd_line->len);
1.1 root 6603: cmd_line->cmd[cmd_line->len] = 0x0d;
6604:
6605: if(msdos_process_exec(command, param, 0)) {
6606: REG16(AX) = 0x02;
1.1.1.3 root 6607: m_CF = 1;
1.1 root 6608: }
6609: }
6610: break;
6611: default:
6612: REG16(AX) = 0x01;
1.1.1.3 root 6613: m_CF = 1;
1.1 root 6614: break;
6615: }
6616: }
6617:
6618: inline void msdos_int_2fh_b7h()
6619: {
6620: switch(REG8(AL)) {
6621: case 0x00:
6622: // append is not installed
6623: REG8(AL) = 0;
6624: break;
6625: default:
6626: REG16(AX) = 0x01;
1.1.1.3 root 6627: m_CF = 1;
1.1 root 6628: break;
6629: }
6630: }
6631:
6632: void msdos_syscall(unsigned num)
6633: {
6634: switch(num) {
6635: case 0x00:
6636: error("division by zero\n");
6637: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
6638: break;
6639: case 0x04:
6640: error("overflow\n");
6641: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
6642: break;
6643: case 0x06:
6644: // NOTE: ish.com has illegal instruction...
1.1.1.14 root 6645: if(!ignore_illegal_insn) {
6646: error("illegal instruction\n");
6647: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
6648: } else {
6649: #if defined(HAS_I386)
6650: m_eip++;
6651: #else
6652: m_pc++;
6653: #endif
6654: }
1.1 root 6655: break;
1.1.1.8 root 6656: case 0x08:
1.1.1.14 root 6657: // pcbios_irq0(); // this causes too slow emulation...
1.1.1.8 root 6658: case 0x09:
6659: case 0x0a:
6660: case 0x0b:
6661: case 0x0c:
6662: case 0x0d:
6663: case 0x0e:
6664: case 0x0f:
6665: // EOI
6666: pic[0].isr &= ~(1 << (num - 0x08));
6667: pic_update();
6668: break;
1.1 root 6669: case 0x10:
6670: // PC BIOS - Video
1.1.1.14 root 6671: if(!restore_console_on_exit) {
1.1.1.15! root 6672: change_console_size(scr_width, scr_height);
1.1 root 6673: }
1.1.1.3 root 6674: m_CF = 0;
1.1 root 6675: switch(REG8(AH)) {
1.1.1.14 root 6676: case 0x00: pcbios_int_10h_00h(25); break;
1.1 root 6677: case 0x01: pcbios_int_10h_01h(); break;
6678: case 0x02: pcbios_int_10h_02h(); break;
6679: case 0x03: pcbios_int_10h_03h(); break;
6680: case 0x05: pcbios_int_10h_05h(); break;
6681: case 0x06: pcbios_int_10h_06h(); break;
6682: case 0x07: pcbios_int_10h_07h(); break;
6683: case 0x08: pcbios_int_10h_08h(); break;
6684: case 0x09: pcbios_int_10h_09h(); break;
6685: case 0x0a: pcbios_int_10h_0ah(); break;
6686: case 0x0b: break;
6687: case 0x0c: break;
6688: case 0x0d: break;
6689: case 0x0e: pcbios_int_10h_0eh(); break;
6690: case 0x0f: pcbios_int_10h_0fh(); break;
6691: case 0x10: break;
1.1.1.14 root 6692: case 0x11: pcbios_int_10h_11h(); break;
6693: case 0x12: pcbios_int_10h_12h(); break;
1.1 root 6694: case 0x13: pcbios_int_10h_13h(); break;
6695: case 0x18: REG8(AL) = 0x86; break;
1.1.1.14 root 6696: case 0x1a: pcbios_int_10h_1ah(); break;
1.1.1.11 root 6697: case 0x1b: break;
1.1 root 6698: case 0x1c: REG8(AL) = 0x00; break;
6699: case 0x1d: pcbios_int_10h_1dh(); break;
6700: case 0x82: pcbios_int_10h_82h(); break;
1.1.1.11 root 6701: case 0xef: REG16(DX) = 0xffff; break;
1.1 root 6702: case 0xfe: pcbios_int_10h_feh(); break;
6703: case 0xff: pcbios_int_10h_ffh(); break;
6704: default:
1.1.1.14 root 6705: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
1.1 root 6706: break;
6707: }
6708: break;
6709: case 0x11:
6710: // PC BIOS - Get Equipment List
1.1.1.11 root 6711: #ifdef SUPPORT_FPU
6712: REG16(AX) = 0x22;
6713: #else
1.1 root 6714: REG16(AX) = 0x20;
1.1.1.11 root 6715: #endif
1.1 root 6716: break;
6717: case 0x12:
6718: // PC BIOS - Get Memory Size
6719: REG16(AX) = MEMORY_END / 1024;
6720: break;
6721: case 0x13:
6722: // PC BIOS - Disk
6723: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
6724: REG8(AH) = 0xff;
1.1.1.3 root 6725: m_CF = 1;
1.1 root 6726: break;
6727: case 0x14:
6728: // PC BIOS - Serial I/O
6729: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
6730: REG8(AH) = 0xff;
1.1.1.3 root 6731: m_CF = 1;
1.1 root 6732: break;
6733: case 0x15:
6734: // PC BIOS
1.1.1.3 root 6735: m_CF = 0;
1.1 root 6736: switch(REG8(AH)) {
1.1.1.14 root 6737: case 0x10: pcbios_int_15h_10h(); break;
1.1 root 6738: case 0x23: pcbios_int_15h_23h(); break;
6739: case 0x24: pcbios_int_15h_24h(); break;
6740: case 0x49: pcbios_int_15h_49h(); break;
6741: case 0x86: pcbios_int_15h_86h(); break;
6742: case 0x87: pcbios_int_15h_87h(); break;
6743: case 0x88: pcbios_int_15h_88h(); break;
6744: case 0x89: pcbios_int_15h_89h(); break;
1.1.1.3 root 6745: #if defined(HAS_I386)
1.1 root 6746: case 0xc9: pcbios_int_15h_c9h(); break;
1.1.1.3 root 6747: #endif
1.1 root 6748: case 0xca: pcbios_int_15h_cah(); break;
6749: default:
6750: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
6751: REG8(AH)=0x86;
1.1.1.3 root 6752: m_CF = 1;
1.1 root 6753: break;
6754: }
6755: break;
6756: case 0x16:
6757: // PC BIOS - Keyboard
1.1.1.3 root 6758: m_CF = 0;
1.1 root 6759: switch(REG8(AH)) {
6760: case 0x00: pcbios_int_16h_00h(); break;
6761: case 0x01: pcbios_int_16h_01h(); break;
6762: case 0x02: pcbios_int_16h_02h(); break;
6763: case 0x03: pcbios_int_16h_03h(); break;
6764: case 0x05: pcbios_int_16h_05h(); break;
6765: case 0x10: pcbios_int_16h_00h(); break;
6766: case 0x11: pcbios_int_16h_01h(); break;
6767: case 0x12: pcbios_int_16h_12h(); break;
6768: case 0x13: pcbios_int_16h_13h(); break;
6769: case 0x14: pcbios_int_16h_14h(); break;
6770: default:
1.1.1.14 root 6771: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
1.1 root 6772: break;
6773: }
6774: break;
6775: case 0x17:
6776: // PC BIOS - Printer
6777: fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
6778: break;
6779: case 0x1a:
6780: // PC BIOS - Timer
1.1.1.3 root 6781: m_CF = 0;
1.1 root 6782: switch(REG8(AH)) {
6783: case 0x00: pcbios_int_1ah_00h(); break;
6784: case 0x01: break;
6785: case 0x02: pcbios_int_1ah_02h(); break;
6786: case 0x03: break;
6787: case 0x04: pcbios_int_1ah_04h(); break;
6788: case 0x05: break;
6789: case 0x0a: pcbios_int_1ah_0ah(); break;
6790: case 0x0b: break;
1.1.1.14 root 6791: case 0x35: break; // Word Perfect Third Party Interface?
6792: case 0x36: break; // Word Perfect Third Party Interface
6793: case 0x70: break; // SNAP? (Simple Network Application Protocol)
1.1 root 6794: default:
6795: fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
6796: break;
6797: }
6798: break;
6799: case 0x20:
1.1.1.3 root 6800: msdos_process_terminate(SREG(CS), retval, 1);
1.1 root 6801: break;
6802: case 0x21:
6803: // MS-DOS System Call
1.1.1.3 root 6804: m_CF = 0;
1.1 root 6805: switch(REG8(AH)) {
6806: case 0x00: msdos_int_21h_00h(); break;
6807: case 0x01: msdos_int_21h_01h(); break;
6808: case 0x02: msdos_int_21h_02h(); break;
6809: case 0x03: msdos_int_21h_03h(); break;
6810: case 0x04: msdos_int_21h_04h(); break;
6811: case 0x05: msdos_int_21h_05h(); break;
6812: case 0x06: msdos_int_21h_06h(); break;
6813: case 0x07: msdos_int_21h_07h(); break;
6814: case 0x08: msdos_int_21h_08h(); break;
6815: case 0x09: msdos_int_21h_09h(); break;
6816: case 0x0a: msdos_int_21h_0ah(); break;
6817: case 0x0b: msdos_int_21h_0bh(); break;
6818: case 0x0c: msdos_int_21h_0ch(); break;
6819: case 0x0d: msdos_int_21h_0dh(); break;
6820: case 0x0e: msdos_int_21h_0eh(); break;
1.1.1.14 root 6821: case 0x0f: msdos_int_21h_0fh(); break;
6822: case 0x10: msdos_int_21h_10h(); break;
1.1 root 6823: case 0x11: msdos_int_21h_11h(); break;
6824: case 0x12: msdos_int_21h_12h(); break;
6825: case 0x13: msdos_int_21h_13h(); break;
6826: // 0x14: sequential read with fcb
6827: // 0x15: sequential write with fcb
1.1.1.14 root 6828: case 0x16: msdos_int_21h_16h(); break;
1.1 root 6829: // 0x17: rename file with fcb
6830: case 0x18: msdos_int_21h_18h(); break;
6831: case 0x19: msdos_int_21h_19h(); break;
6832: case 0x1a: msdos_int_21h_1ah(); break;
6833: case 0x1b: msdos_int_21h_1bh(); break;
6834: case 0x1c: msdos_int_21h_1ch(); break;
6835: case 0x1d: msdos_int_21h_1dh(); break;
6836: case 0x1e: msdos_int_21h_1eh(); break;
6837: case 0x1f: msdos_int_21h_1fh(); break;
6838: case 0x20: msdos_int_21h_20h(); break;
1.1.1.14 root 6839: case 0x21: msdos_int_21h_21h(); break;
6840: case 0x22: msdos_int_21h_22h(); break;
1.1 root 6841: // 0x23: get file size with fcb
6842: // 0x24: set relative record field with fcb
6843: case 0x25: msdos_int_21h_25h(); break;
6844: case 0x26: msdos_int_21h_26h(); break;
6845: // 0x27: random block read with fcb
6846: // 0x28: random block write with fcb
6847: case 0x29: msdos_int_21h_29h(); break;
6848: case 0x2a: msdos_int_21h_2ah(); break;
6849: case 0x2b: msdos_int_21h_2bh(); break;
6850: case 0x2c: msdos_int_21h_2ch(); break;
6851: case 0x2d: msdos_int_21h_2dh(); break;
6852: case 0x2e: msdos_int_21h_2eh(); break;
6853: case 0x2f: msdos_int_21h_2fh(); break;
6854: case 0x30: msdos_int_21h_30h(); break;
6855: case 0x31: msdos_int_21h_31h(); break;
6856: case 0x32: msdos_int_21h_32h(); break;
6857: case 0x33: msdos_int_21h_33h(); break;
6858: // 0x34: get address of indos flag
6859: case 0x35: msdos_int_21h_35h(); break;
6860: case 0x36: msdos_int_21h_36h(); break;
6861: case 0x37: msdos_int_21h_37h(); break;
1.1.1.14 root 6862: case 0x38: msdos_int_21h_38h(); break;
1.1 root 6863: case 0x39: msdos_int_21h_39h(0); break;
6864: case 0x3a: msdos_int_21h_3ah(0); break;
6865: case 0x3b: msdos_int_21h_3bh(0); break;
6866: case 0x3c: msdos_int_21h_3ch(); break;
6867: case 0x3d: msdos_int_21h_3dh(); break;
6868: case 0x3e: msdos_int_21h_3eh(); break;
6869: case 0x3f: msdos_int_21h_3fh(); break;
6870: case 0x40: msdos_int_21h_40h(); break;
6871: case 0x41: msdos_int_21h_41h(0); break;
6872: case 0x42: msdos_int_21h_42h(); break;
6873: case 0x43: msdos_int_21h_43h(0); break;
6874: case 0x44: msdos_int_21h_44h(); break;
6875: case 0x45: msdos_int_21h_45h(); break;
6876: case 0x46: msdos_int_21h_46h(); break;
6877: case 0x47: msdos_int_21h_47h(0); break;
6878: case 0x48: msdos_int_21h_48h(); break;
6879: case 0x49: msdos_int_21h_49h(); break;
6880: case 0x4a: msdos_int_21h_4ah(); break;
6881: case 0x4b: msdos_int_21h_4bh(); break;
6882: case 0x4c: msdos_int_21h_4ch(); break;
6883: case 0x4d: msdos_int_21h_4dh(); break;
6884: case 0x4e: msdos_int_21h_4eh(); break;
6885: case 0x4f: msdos_int_21h_4fh(); break;
6886: case 0x50: msdos_int_21h_50h(); break;
6887: case 0x51: msdos_int_21h_51h(); break;
6888: case 0x52: msdos_int_21h_52h(); break;
6889: // 0x53: translate bios parameter block to drive param bock
6890: case 0x54: msdos_int_21h_54h(); break;
6891: case 0x55: msdos_int_21h_55h(); break;
6892: case 0x56: msdos_int_21h_56h(0); break;
6893: case 0x57: msdos_int_21h_57h(); break;
6894: case 0x58: msdos_int_21h_58h(); break;
6895: case 0x59: msdos_int_21h_59h(); break;
6896: case 0x5a: msdos_int_21h_5ah(); break;
6897: case 0x5b: msdos_int_21h_5bh(); break;
6898: case 0x5c: msdos_int_21h_5ch(); break;
6899: // 0x5e: ms-network
6900: // 0x5f: ms-network
6901: case 0x60: msdos_int_21h_60h(0); break;
6902: case 0x61: msdos_int_21h_61h(); break;
6903: case 0x62: msdos_int_21h_62h(); break;
6904: case 0x63: msdos_int_21h_63h(); break;
6905: // 0x64: set device driver lockahead flag
6906: case 0x65: msdos_int_21h_65h(); break;
6907: case 0x66: msdos_int_21h_66h(); break;
6908: case 0x67: msdos_int_21h_67h(); break;
6909: case 0x68: msdos_int_21h_68h(); break;
6910: case 0x69: msdos_int_21h_69h(); break;
6911: case 0x6a: msdos_int_21h_6ah(); break;
6912: case 0x6b: msdos_int_21h_6bh(); break;
6913: case 0x6c: msdos_int_21h_6ch(0); break;
6914: // 0x6d: find first rom program
6915: // 0x6e: find next rom program
6916: // 0x6f: get/set rom scan start address
6917: // 0x70: windows95 get/set internationalization information
6918: case 0x71:
6919: // windows95 long filename functions
6920: switch(REG8(AL)) {
6921: case 0x0d: msdos_int_21h_710dh(); break;
6922: case 0x39: msdos_int_21h_39h(1); break;
6923: case 0x3a: msdos_int_21h_3ah(1); break;
6924: case 0x3b: msdos_int_21h_3bh(1); break;
6925: case 0x41: msdos_int_21h_41h(1); break;
6926: case 0x43: msdos_int_21h_43h(1); break;
6927: case 0x47: msdos_int_21h_47h(1); break;
6928: case 0x4e: msdos_int_21h_714eh(); break;
6929: case 0x4f: msdos_int_21h_714fh(); break;
6930: case 0x56: msdos_int_21h_56h(1); break;
6931: case 0x60: msdos_int_21h_60h(1); break;
6932: case 0x6c: msdos_int_21h_6ch(1); break;
6933: case 0xa0: msdos_int_21h_71a0h(); break;
6934: case 0xa1: msdos_int_21h_71a1h(); break;
6935: case 0xa6: msdos_int_21h_71a6h(); break;
6936: case 0xa7: msdos_int_21h_71a7h(); break;
6937: case 0xa8: msdos_int_21h_71a8h(); break;
6938: // 0xa9: server create/open file
6939: // 0xaa: create/terminate SUBST
6940: default:
6941: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
6942: REG16(AX) = 0x7100;
1.1.1.3 root 6943: m_CF = 1;
1.1 root 6944: break;
6945: }
6946: break;
6947: // 0x72: Windows95 beta - LFN FindClose
6948: case 0x73:
6949: // windows95 fat32 functions
6950: switch(REG8(AL)) {
1.1.1.14 root 6951: case 0x00: msdos_int_21h_7300h(); break;
6952: // 0x01: set drive locking ???
6953: case 0x02: msdos_int_21h_7302h(); break;
1.1 root 6954: case 0x03: msdos_int_21h_7303h(); break;
6955: // 0x04: set dpb to use for formatting
6956: default:
6957: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
6958: REG16(AX) = 0x7300;
1.1.1.3 root 6959: m_CF = 1;
1.1 root 6960: break;
6961: }
6962: break;
6963: default:
6964: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
6965: REG16(AX) = 0x01;
1.1.1.3 root 6966: m_CF = 1;
1.1 root 6967: break;
6968: }
1.1.1.3 root 6969: if(m_CF) {
1.1 root 6970: error_code = REG16(AX);
6971: }
6972: break;
6973: case 0x22:
6974: fatalerror("int 22h (terminate address)\n");
6975: case 0x23:
6976: msdos_process_terminate(current_psp, (retval & 0xff) | 0x100, 1);
6977: break;
6978: case 0x24:
6979: msdos_process_terminate(current_psp, (retval & 0xff) | 0x200, 1);
6980: break;
6981: case 0x25:
6982: msdos_int_25h();
6983: break;
6984: case 0x26:
6985: msdos_int_26h();
6986: break;
6987: case 0x27:
6988: msdos_int_27h();
6989: break;
6990: case 0x28:
6991: Sleep(10);
6992: break;
6993: case 0x29:
6994: msdos_int_29h();
6995: break;
6996: case 0x2e:
6997: msdos_int_2eh();
6998: break;
6999: case 0x2f:
7000: // multiplex interrupt
7001: switch(REG8(AH)) {
7002: case 0x16: msdos_int_2fh_16h(); break;
7003: case 0x1a: msdos_int_2fh_1ah(); break;
7004: case 0x43: msdos_int_2fh_43h(); break;
7005: case 0x4a: msdos_int_2fh_4ah(); break;
7006: case 0x4f: msdos_int_2fh_4fh(); break;
7007: case 0xae: msdos_int_2fh_aeh(); break;
7008: case 0xb7: msdos_int_2fh_b7h(); break;
7009: }
7010: break;
1.1.1.8 root 7011: case 0x70:
7012: case 0x71:
7013: case 0x72:
7014: case 0x73:
7015: case 0x74:
7016: case 0x75:
7017: case 0x76:
7018: case 0x77:
7019: // EOI
7020: if((pic[1].isr &= ~(1 << (num - 0x70))) == 0) {
7021: pic[0].isr &= ~(1 << 2); // master
7022: }
7023: pic_update();
7024: break;
1.1 root 7025: default:
7026: // fatalerror("int %02xh (ax=%04xh bx=%04xh cx=%04xh dx=%04x)\n", num, REG16(AX), REG16(BX), REG16(CX), REG16(DX));
7027: break;
7028: }
7029:
7030: // update cursor position
7031: if(cursor_moved) {
7032: CONSOLE_SCREEN_BUFFER_INFO csbi;
7033: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.15! root 7034: if(!restore_console_on_exit) {
! 7035: scr_top = csbi.srWindow.Top;
! 7036: }
1.1 root 7037: mem[0x450 + mem[0x462] * 2] = csbi.dwCursorPosition.X;
1.1.1.14 root 7038: mem[0x451 + mem[0x462] * 2] = csbi.dwCursorPosition.Y - scr_top;
1.1 root 7039: cursor_moved = false;
7040: }
7041: }
7042:
7043: // init
7044:
7045: int msdos_init(int argc, char *argv[], char *envp[], int standard_env)
7046: {
7047: // init file handler
7048: memset(file_handler, 0, sizeof(file_handler));
7049: msdos_file_handler_open(0, "STDIN", _isatty(0), 0, 0x80d3, 0);
7050: msdos_file_handler_open(1, "STDOUT", _isatty(1), 1, 0x80d3, 0);
7051: msdos_file_handler_open(2, "STDERR", _isatty(2), 1, 0x80d3, 0);
7052: #ifdef SUPPORT_AUX_PRN
7053: if(_open("stdaux.txt", _O_RDWR | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 3) {
7054: msdos_file_handler_open(3, 0, 2, 0x80c0, 0);
7055: }
7056: if(_open("stdprn.txt", _O_WRONLY | _O_BINARY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE) == 4) {
7057: msdos_file_handler_open(4, 0, 1, 0xa8c0, 0);
7058: }
7059: #endif
7060: _dup2(0, DUP_STDIN);
7061: _dup2(1, DUP_STDOUT);
7062: _dup2(2, DUP_STDERR);
7063:
7064: // init process
7065: memset(process, 0, sizeof(process));
7066:
1.1.1.13 root 7067: // init dtainfo
7068: msdos_dta_info_init();
7069:
1.1 root 7070: // init memory
7071: memset(mem, 0, sizeof(mem));
1.1.1.14 root 7072: for(int i = 0; i < 0x80; i++) {
1.1 root 7073: *(UINT16 *)(mem + 4 * i + 0) = i;
7074: *(UINT16 *)(mem + 4 * i + 2) = (IRET_TOP >> 4);
7075: }
1.1.1.14 root 7076: *(UINT16 *)(mem + 4 * 0x08 + 0) = 0xfea5;
7077: *(UINT16 *)(mem + 4 * 0x08 + 2) = 0xf000;
1.1 root 7078: *(UINT16 *)(mem + 4 * 0x22 + 0) = 0xfff0;
7079: *(UINT16 *)(mem + 4 * 0x22 + 2) = 0xf000;
7080: memset(mem + IRET_TOP, 0xcf, IRET_SIZE);
7081:
7082: // bios data area
7083: CONSOLE_SCREEN_BUFFER_INFO csbi;
7084: GetConsoleScreenBufferInfo(hStdout, &csbi);
1.1.1.14 root 7085: CONSOLE_FONT_INFO cfi;
7086: GetCurrentConsoleFont(hStdout, FALSE, &cfi);
7087:
7088: int regen = min(scr_width * scr_height * 2, 0x8000);
7089: text_vram_top_address = TEXT_VRAM_TOP;
7090: text_vram_end_address = text_vram_top_address + regen;
7091: shadow_buffer_top_address = SHADOW_BUF_TOP;
7092: shadow_buffer_end_address = shadow_buffer_top_address + regen;
7093:
7094: if(regen > 0x4000) {
7095: regen = 0x8000;
7096: vram_pages = 1;
7097: } else if(regen > 0x2000) {
7098: regen = 0x4000;
7099: vram_pages = 2;
7100: } else if(regen > 0x1000) {
7101: regen = 0x2000;
7102: vram_pages = 4;
7103: } else {
7104: regen = 0x1000;
7105: vram_pages = 8;
7106: }
1.1 root 7107:
1.1.1.14 root 7108: #ifdef SUPPORT_FPU
7109: *(UINT16 *)(mem + 0x410) = 0x22;
7110: #else
1.1 root 7111: *(UINT16 *)(mem + 0x410) = 0x20;
1.1.1.14 root 7112: #endif
1.1 root 7113: *(UINT16 *)(mem + 0x413) = MEMORY_END / 1024;
7114: *(UINT8 *)(mem + 0x449) = 0x03;//0x73;
1.1.1.14 root 7115: *(UINT16 *)(mem + 0x44a) = csbi.dwSize.X;
7116: *(UINT16 *)(mem + 0x44c) = regen;
1.1 root 7117: *(UINT16 *)(mem + 0x44e) = 0;
7118: *(UINT8 *)(mem + 0x450) = csbi.dwCursorPosition.X;
1.1.1.14 root 7119: *(UINT8 *)(mem + 0x451) = csbi.dwCursorPosition.Y - scr_top;
1.1 root 7120: *(UINT8 *)(mem + 0x460) = 7;
7121: *(UINT8 *)(mem + 0x461) = 7;
7122: *(UINT8 *)(mem + 0x462) = 0;
7123: *(UINT16 *)(mem + 0x463) = 0x3d4;
1.1.1.14 root 7124: *(UINT8 *)(mem + 0x465) = 0x9;
7125: *(UINT32 *)(mem + 0x46c) = get_ticks_since_midnight();
7126: *(UINT8 *)(mem + 0x484) = csbi.srWindow.Bottom - csbi.srWindow.Top;
7127: *(UINT8 *)(mem + 0x485) = cfi.dwFontSize.Y;
7128: *(UINT8 *)(mem + 0x487) = 0x60;
7129: *(UINT8 *)(mem + 0x496) = 0x10; // enhanced keyboard installed
7130:
7131: // initial screen
7132: SMALL_RECT rect;
7133: SET_RECT(rect, 0, csbi.srWindow.Top, csbi.dwSize.X - 1, csbi.srWindow.Bottom);
7134: ReadConsoleOutput(hStdout, scr_buf, scr_buf_size, scr_buf_pos, &rect);
7135: for(int y = 0, ofs1 = TEXT_VRAM_TOP, ofs2 = SHADOW_BUF_TOP; y < scr_height; y++) {
7136: for(int x = 0; x < scr_width; x++) {
7137: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Char.AsciiChar;
7138: mem[ofs1++] = mem[ofs2++] = SCR_BUF(y,x).Attributes;
7139: }
7140: }
1.1 root 7141:
7142: // dos info
7143: dos_info_t *dos_info = (dos_info_t *)(mem + DOS_INFO_TOP);
7144: dos_info->first_mcb = MEMORY_TOP >> 4;
7145: dos_info->first_dpb.w.l = 0;
7146: dos_info->first_dpb.w.h = DPB_TOP >> 4;
7147: dos_info->first_sft.w.l = 0;
7148: dos_info->first_sft.w.h = FILE_TABLE_TOP >> 4;
7149: dos_info->cds.w.l = 0;
7150: dos_info->cds.w.h = CDS_TOP >> 4;
7151: dos_info->fcb_table.w.l = 0;
7152: dos_info->fcb_table.w.h = FCB_TABLE_TOP >> 4;
7153: dos_info->last_drive = 'Z' - 'A' + 1;
7154: dos_info->buffers_x = 20;
7155: dos_info->buffers_y = 0;
1.1.1.14 root 7156: dos_info->boot_drive = 'C' - 'A' + 1;
1.1 root 7157: char *env;
7158: if((env = getenv("LASTDRIVE")) != NULL) {
7159: if(env[0] >= 'A' && env[0] <= 'Z') {
7160: dos_info->last_drive = env[0] - 'A' + 1;
7161: } else if(env[0] >= 'a' && env[0] <= 'z') {
7162: dos_info->last_drive = env[0] - 'a' + 1;
7163: }
7164: }
7165: if((env = getenv("windir")) != NULL) {
7166: if(env[0] >= 'A' && env[0] <= 'Z') {
7167: dos_info->boot_drive = env[0] - 'A' + 1;
7168: } else if(env[0] >= 'a' && env[0] <= 'z') {
7169: dos_info->boot_drive = env[0] - 'a' + 1;
7170: }
7171: }
1.1.1.3 root 7172: #if defined(HAS_I386)
1.1 root 7173: dos_info->i386_or_later = 1;
1.1.1.3 root 7174: #else
7175: dos_info->i386_or_later = 0;
7176: #endif
1.1 root 7177: dos_info->ext_mem_size = (MAX_MEM - 0x100000) >> 10;
7178:
7179: // environment
7180: int seg = MEMORY_TOP >> 4;
7181: msdos_mcb_create(seg++, 'M', -1, ENV_SIZE >> 4);
7182: int env_seg = seg;
7183: int ofs = 0;
1.1.1.15! root 7184: char env_path[8192] = "", *path;
1.1 root 7185:
7186: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1.1.14 root 7187: if(_strnicmp(*p, "MSDOS_PATH=", 11) == 0) {
7188: sprintf(env_path, "%s;", *p + 11);
7189: break;
7190: }
7191: }
7192: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1.1.9 root 7193: if(_strnicmp(*p, "PATH=", 5) == 0) {
1.1.1.14 root 7194: strcat(env_path, *p + 5);
1.1.1.9 root 7195: break;
7196: }
7197: }
1.1.1.15! root 7198: if((path = msdos_search_command_com(argv[0], env_path)) != NULL) {
! 7199: strcpy(comspec_path, path);
! 7200: }
! 7201:
1.1.1.9 root 7202: for(char **p = envp; p != NULL && *p != NULL; p++) {
1.1 root 7203: // lower to upper
7204: char tmp[ENV_SIZE], name[ENV_SIZE], value[ENV_SIZE];
7205: int value_pos = 0;
7206: strcpy(tmp, *p);
7207: for(int i = 0;; i++) {
7208: if(tmp[i] == '=') {
7209: tmp[i] = '\0';
7210: sprintf(name, ";%s;", tmp);
7211: strcpy(value, tmp + (value_pos = i + 1));
7212: tmp[i] = '=';
7213: break;
7214: } else if(tmp[i] >= 'a' && tmp[i] <= 'z') {
7215: tmp[i] = tmp[i] - 'a' + 'A';
7216: }
7217: }
7218: if(!(standard_env && strstr(";COMSPEC;INCLUDE;LIB;PATH;PROMPT;TEMP;TMP;TZ;", name) == NULL)) {
7219: if(strncmp(tmp, "COMSPEC=", 8) == 0) {
1.1.1.14 root 7220: strcpy(tmp, "COMSPEC=C:\\COMMAND.COM");
1.1 root 7221: } else if(strncmp(tmp, "PATH=", 5) == 0 || strncmp(tmp, "TEMP=", 5) == 0 || strncmp(tmp, "TMP=", 4) == 0) {
7222: tmp[value_pos] = '\0';
7223: char *token = my_strtok(value, ";");
7224: while(token != NULL) {
7225: if(strlen(token) != 0) {
1.1.1.8 root 7226: char *path = msdos_remove_double_quote(token), tmp_path[MAX_PATH];
7227: if(strlen(path) != 0) {
7228: GetShortPathName(path, tmp_path, MAX_PATH);
7229: strcat(tmp, tmp_path);
7230: strcat(tmp, ";");
1.1 root 7231: }
7232: }
7233: token = my_strtok(NULL, ";");
7234: }
7235: tmp[strlen(tmp) - 1] = '\0';
7236: my_strupr(tmp);
7237: }
7238: int len = strlen(tmp);
1.1.1.14 root 7239: if(ofs + len + 1 + (2 + (8 + 1 + 3)) + 2 > ENV_SIZE) {
1.1 root 7240: fatalerror("too many environments\n");
7241: }
7242: memcpy(mem + (seg << 4) + ofs, tmp, len);
7243: ofs += len + 1;
7244: }
7245: }
7246: seg += (ENV_SIZE >> 4);
7247:
7248: // psp
7249: msdos_mcb_create(seg++, 'M', -1, PSP_SIZE >> 4);
7250: current_psp = seg;
1.1.1.14 root 7251: msdos_psp_create(seg, seg + (PSP_SIZE >> 4), -1, env_seg);
1.1 root 7252: seg += (PSP_SIZE >> 4);
7253:
1.1.1.8 root 7254: // first mcb in conventional memory
1.1 root 7255: msdos_mcb_create(seg, 'Z', 0, (MEMORY_END >> 4) - seg - 1);
1.1.1.8 root 7256: first_mcb = seg;
7257:
7258: // first mcb in upper memory block
7259: msdos_mcb_create(UMB_TOP >> 4, 'Z', 0, (UMB_END >> 4) - (UMB_TOP >> 4) - 1);
1.1 root 7260:
1.1.1.14 root 7261: // have irq0 call system timer tick
7262: mem[0xffea5] = 0xcd; // int 1ch
7263: mem[0xffea6] = 0x1c;
7264: mem[0xffea7] = 0xea; // jmp 80:08
7265: mem[0xffea8] = 0x08;
7266: mem[0xffea9] = 0x00;
7267: mem[0xffeaa] = ((IRET_TOP >> 4) ) & 0xff;
7268: mem[0xffeab] = ((IRET_TOP >> 4) >> 8) & 0xff;
7269:
1.1 root 7270: // boot
7271: mem[0xffff0] = 0xf4; // halt
7272: mem[0xffff1] = 0xcd; // int 21h
7273: mem[0xffff2] = 0x21;
7274: mem[0xffff3] = 0xcb; // retf
7275:
7276: // param block
7277: // + 0: param block (22bytes)
7278: // +24: fcb1/2 (20bytes)
7279: // +44: command tail (128bytes)
7280: param_block_t *param = (param_block_t *)(mem + WORK_TOP);
7281: param->env_seg = 0;
7282: param->cmd_line.w.l = 44;
7283: param->cmd_line.w.h = (WORK_TOP >> 4);
7284: param->fcb1.w.l = 24;
7285: param->fcb1.w.h = (WORK_TOP >> 4);
7286: param->fcb2.w.l = 24;
7287: param->fcb2.w.h = (WORK_TOP >> 4);
7288:
7289: memset(mem + WORK_TOP + 24, 0x20, 20);
7290:
7291: cmd_line_t *cmd_line = (cmd_line_t *)(mem + WORK_TOP + 44);
7292: if(argc > 1) {
7293: sprintf(cmd_line->cmd, " %s", argv[1]);
7294: for(int i = 2; i < argc; i++) {
7295: char tmp[128];
7296: sprintf(tmp, "%s %s", cmd_line->cmd, argv[i]);
7297: strcpy(cmd_line->cmd, tmp);
7298: }
7299: cmd_line->len = (UINT8)strlen(cmd_line->cmd);
7300: } else {
7301: cmd_line->len = 0;
7302: }
7303: cmd_line->cmd[cmd_line->len] = 0x0d;
7304:
7305: // system file table
1.1.1.14 root 7306: *(UINT32 *)(mem + FILE_TABLE_TOP + 0) = 0xffffffff;
7307: *(UINT16 *)(mem + FILE_TABLE_TOP + 4) = 0;
1.1 root 7308:
7309: // current directory structure
7310: msdos_cds_update(_getdrive() - 1);
7311:
7312: // fcb table
7313: *(UINT32 *)(mem + FCB_TABLE_TOP + 0) = 0xffffffff;
1.1.1.14 root 7314: *(UINT16 *)(mem + FCB_TABLE_TOP + 4) = 0;
1.1 root 7315:
7316: // dbcs table
7317: msdos_dbcs_table_init();
7318:
7319: // execute command
7320: if(msdos_process_exec(argv[0], param, 0)) {
7321: fatalerror("'%s' not found\n", argv[0]);
7322: }
7323: retval = 0;
7324: return(0);
7325: }
7326:
7327: #define remove_std_file(path) { \
7328: int fd = _open(path, _O_RDONLY | _O_BINARY); \
7329: if(fd != -1) { \
7330: _lseek(fd, 0, SEEK_END); \
7331: int size = _tell(fd); \
7332: _close(fd); \
7333: if(size == 0) { \
7334: remove(path); \
7335: } \
7336: } \
7337: }
7338:
7339: void msdos_finish()
7340: {
7341: for(int i = 0; i < MAX_FILES; i++) {
7342: if(file_handler[i].valid) {
7343: _close(i);
7344: }
7345: }
7346: #ifdef SUPPORT_AUX_PRN
7347: remove_std_file("stdaux.txt");
7348: remove_std_file("stdprn.txt");
7349: #endif
7350: msdos_dbcs_table_finish();
7351: }
7352:
7353: /* ----------------------------------------------------------------------------
7354: PC/AT hardware emulation
7355: ---------------------------------------------------------------------------- */
7356:
7357: void hardware_init()
7358: {
1.1.1.3 root 7359: CPU_INIT_CALL(CPU_MODEL);
1.1 root 7360: CPU_RESET_CALL(CPU_MODEL);
1.1.1.14 root 7361: m_IF = 1;
1.1.1.3 root 7362: #if defined(HAS_I386)
1.1 root 7363: cpu_type = (REG32(EDX) >> 8) & 0x0f;
7364: cpu_step = (REG32(EDX) >> 0) & 0x0f;
1.1.1.3 root 7365: #endif
7366: i386_set_a20_line(0);
1.1.1.14 root 7367:
1.1 root 7368: pic_init();
1.1.1.8 root 7369: #ifdef PIT_ALWAYS_RUNNING
7370: pit_init();
7371: #else
1.1 root 7372: pit_active = 0;
7373: #endif
1.1.1.8 root 7374: cmos_init();
7375: kbd_init();
1.1 root 7376: }
7377:
1.1.1.10 root 7378: void hardware_finish()
7379: {
7380: #if defined(HAS_I386)
7381: vtlb_free(m_vtlb);
7382: #endif
7383: }
7384:
1.1 root 7385: void hardware_run()
7386: {
7387: int ops = 0;
7388:
1.1.1.3 root 7389: while(!m_halted) {
1.1 root 7390: #ifdef SUPPORT_DISASSEMBLER
7391: if(dasm) {
7392: char buffer[256];
1.1.1.3 root 7393: #if defined(HAS_I386)
7394: UINT64 eip = m_eip;
7395: #else
7396: UINT64 eip = m_pc - SREG_BASE(CS);
7397: #endif
7398: UINT8 *oprom = mem + SREG_BASE(CS) + eip;
1.1 root 7399:
1.1.1.3 root 7400: #if defined(HAS_I386)
7401: if(m_operand_size) {
1.1 root 7402: CPU_DISASSEMBLE_CALL(x86_32);
1.1.1.3 root 7403: } else
7404: #endif
7405: CPU_DISASSEMBLE_CALL(x86_16);
1.1.1.12 root 7406: fprintf(stderr, "%04x:%04x\t%s\n", SREG(CS), (unsigned)eip, buffer);
1.1 root 7407: }
7408: #endif
1.1.1.3 root 7409: #if defined(HAS_I386)
7410: m_cycles = 1;
1.1 root 7411: CPU_EXECUTE_CALL(i386);
1.1.1.3 root 7412: #else
7413: CPU_EXECUTE_CALL(CPU_MODEL);
7414: #endif
1.1.1.14 root 7415: #if defined(HAS_I386)
7416: if(m_eip != m_prev_eip) {
7417: #else
7418: if(m_pc != m_prevpc) {
7419: #endif
7420: iops++;
7421: }
1.1.1.8 root 7422: if(++ops == 16384) {
1.1 root 7423: hardware_update();
7424: ops = 0;
7425: }
7426: }
7427: }
7428:
7429: void hardware_update()
7430: {
1.1.1.8 root 7431: static UINT32 prev_time = 0;
7432: UINT32 cur_time = timeGetTime();
7433:
7434: if(prev_time != cur_time) {
7435: // update pit and raise irq0
7436: #ifndef PIT_ALWAYS_RUNNING
7437: if(pit_active)
7438: #endif
7439: {
7440: if(pit_run(0, cur_time)) {
7441: pic_req(0, 0, 1);
7442: }
7443: pit_run(1, cur_time);
7444: pit_run(2, cur_time);
7445: }
7446: // check key input and raise irq1
1.1.1.14 root 7447: static UINT32 prev_tick = 0;
7448: UINT32 cur_tick = cur_time / 32;
7449: if(prev_tick != cur_tick) {
7450: // update keyboard flags
7451: UINT8 state;
7452: state = (GetAsyncKeyState(VK_INSERT ) & 0x0001) ? 0x80 : 0;
7453: state |= (GetAsyncKeyState(VK_CAPITAL) & 0x0001) ? 0x40 : 0;
7454: state |= (GetAsyncKeyState(VK_NUMLOCK) & 0x0001) ? 0x20 : 0;
7455: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x0001) ? 0x10 : 0;
7456: state |= (GetAsyncKeyState(VK_MENU ) & 0x8000) ? 0x08 : 0;
7457: state |= (GetAsyncKeyState(VK_CONTROL) & 0x8000) ? 0x04 : 0;
7458: state |= (GetAsyncKeyState(VK_LSHIFT ) & 0x8000) ? 0x02 : 0;
7459: state |= (GetAsyncKeyState(VK_RSHIFT ) & 0x8000) ? 0x01 : 0;
7460: mem[0x417] = state;
7461: state = (GetAsyncKeyState(VK_INSERT ) & 0x8000) ? 0x80 : 0;
7462: state |= (GetAsyncKeyState(VK_CAPITAL ) & 0x8000) ? 0x40 : 0;
7463: state |= (GetAsyncKeyState(VK_NUMLOCK ) & 0x8000) ? 0x20 : 0;
7464: state |= (GetAsyncKeyState(VK_SCROLL ) & 0x8000) ? 0x10 : 0;
7465: // state |= (GetAsyncKeyState(VK_PAUSE ) & 0x0001) ? 0x08 : 0;
7466: // state |= (GetAsyncKeyState(VK_SYSREQ ) & 0x8000) ? 0x04 : 0;
7467: state |= (GetAsyncKeyState(VK_LMENU ) & 0x8000) ? 0x02 : 0;
7468: state |= (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ? 0x01 : 0;
7469: mem[0x418] = state;
7470:
7471: // update keyboard input
1.1.1.8 root 7472: if(check_key_input()) {
7473: pic_req(0, 1, 1);
7474: }
1.1.1.14 root 7475: prev_tick = cur_tick;
1.1.1.8 root 7476: }
7477: prev_time = cur_time;
1.1 root 7478: }
7479: }
7480:
7481: // pic
7482:
7483: void pic_init()
7484: {
1.1.1.8 root 7485: memset(pic, 0, sizeof(pic));
7486: pic[0].imr = pic[1].imr = 0xff;
1.1 root 7487:
7488: // from bochs bios
7489: pic_write(0, 0, 0x11); // icw1 = 11h
7490: pic_write(0, 1, 0x08); // icw2 = 08h
7491: pic_write(0, 1, 0x04); // icw3 = 04h
7492: pic_write(0, 1, 0x01); // icw4 = 01h
7493: pic_write(0, 1, 0xb8); // ocw1 = b8h
7494: pic_write(1, 0, 0x11); // icw1 = 11h
7495: pic_write(1, 1, 0x70); // icw2 = 70h
7496: pic_write(1, 1, 0x02); // icw3 = 02h
7497: pic_write(1, 1, 0x01); // icw4 = 01h
7498: }
7499:
7500: void pic_write(int c, UINT32 addr, UINT8 data)
7501: {
7502: if(addr & 1) {
7503: if(pic[c].icw2_r) {
7504: // icw2
7505: pic[c].icw2 = data;
7506: pic[c].icw2_r = 0;
7507: } else if(pic[c].icw3_r) {
7508: // icw3
7509: pic[c].icw3 = data;
7510: pic[c].icw3_r = 0;
7511: } else if(pic[c].icw4_r) {
7512: // icw4
7513: pic[c].icw4 = data;
7514: pic[c].icw4_r = 0;
7515: } else {
7516: // ocw1
7517: pic[c].imr = data;
7518: }
7519: } else {
7520: if(data & 0x10) {
7521: // icw1
7522: pic[c].icw1 = data;
7523: pic[c].icw2_r = 1;
7524: pic[c].icw3_r = (data & 2) ? 0 : 1;
7525: pic[c].icw4_r = data & 1;
7526: pic[c].irr = 0;
7527: pic[c].isr = 0;
7528: pic[c].imr = 0;
7529: pic[c].prio = 0;
7530: if(!(pic[c].icw1 & 1)) {
7531: pic[c].icw4 = 0;
7532: }
7533: pic[c].ocw3 = 0;
7534: } else if(data & 8) {
7535: // ocw3
7536: if(!(data & 2)) {
7537: data = (data & ~1) | (pic[c].ocw3 & 1);
7538: }
7539: if(!(data & 0x40)) {
7540: data = (data & ~0x20) | (pic[c].ocw3 & 0x20);
7541: }
7542: pic[c].ocw3 = data;
7543: } else {
7544: // ocw2
7545: int level = 0;
7546: if(data & 0x40) {
7547: level = data & 7;
7548: } else {
7549: if(!pic[c].isr) {
7550: return;
7551: }
7552: level = pic[c].prio;
7553: while(!(pic[c].isr & (1 << level))) {
7554: level = (level + 1) & 7;
7555: }
7556: }
7557: if(data & 0x80) {
7558: pic[c].prio = (level + 1) & 7;
7559: }
7560: if(data & 0x20) {
7561: pic[c].isr &= ~(1 << level);
7562: }
7563: }
7564: }
7565: pic_update();
7566: }
7567:
7568: UINT8 pic_read(int c, UINT32 addr)
7569: {
7570: if(addr & 1) {
7571: return(pic[c].imr);
7572: } else {
7573: // polling mode is not supported...
7574: //if(pic[c].ocw3 & 4) {
7575: // return ???;
7576: //}
7577: if(pic[c].ocw3 & 1) {
7578: return(pic[c].isr);
7579: } else {
7580: return(pic[c].irr);
7581: }
7582: }
7583: }
7584:
7585: void pic_req(int c, int level, int signal)
7586: {
7587: if(signal) {
7588: pic[c].irr |= (1 << level);
7589: } else {
7590: pic[c].irr &= ~(1 << level);
7591: }
7592: pic_update();
7593: }
7594:
7595: int pic_ack()
7596: {
7597: // ack (INTA=L)
7598: pic[pic_req_chip].isr |= pic_req_bit;
7599: pic[pic_req_chip].irr &= ~pic_req_bit;
7600: if(pic_req_chip > 0) {
7601: // update isr and irr of master
7602: UINT8 slave = 1 << (pic[pic_req_chip].icw3 & 7);
7603: pic[pic_req_chip - 1].isr |= slave;
7604: pic[pic_req_chip - 1].irr &= ~slave;
7605: }
7606: //if(pic[pic_req_chip].icw4 & 1) {
7607: // 8086 mode
7608: int vector = (pic[pic_req_chip].icw2 & 0xf8) | pic_req_level;
7609: //} else {
7610: // // 8080 mode
7611: // UINT16 addr = (UINT16)pic[pic_req_chip].icw2 << 8;
7612: // if(pic[pic_req_chip].icw1 & 4) {
7613: // addr |= (pic[pic_req_chip].icw1 & 0xe0) | (pic_req_level << 2);
7614: // } else {
7615: // addr |= (pic[pic_req_chip].icw1 & 0xc0) | (pic_req_level << 3);
7616: // }
7617: // vector = 0xcd | (addr << 8);
7618: //}
7619: if(pic[pic_req_chip].icw4 & 2) {
7620: // auto eoi
7621: pic[pic_req_chip].isr &= ~pic_req_bit;
7622: }
7623: return(vector);
7624: }
7625:
7626: void pic_update()
7627: {
7628: for(int c = 0; c < 2; c++) {
7629: UINT8 irr = pic[c].irr;
7630: if(c + 1 < 2) {
7631: // this is master
7632: if(pic[c + 1].irr & (~pic[c + 1].imr)) {
7633: // request from slave
7634: irr |= 1 << (pic[c + 1].icw3 & 7);
7635: }
7636: }
7637: irr &= (~pic[c].imr);
7638: if(!irr) {
7639: break;
7640: }
7641: if(!(pic[c].ocw3 & 0x20)) {
7642: irr |= pic[c].isr;
7643: }
7644: int level = pic[c].prio;
7645: UINT8 bit = 1 << level;
7646: while(!(irr & bit)) {
7647: level = (level + 1) & 7;
7648: bit = 1 << level;
7649: }
7650: if((c + 1 < 2) && (pic[c].icw3 & bit)) {
7651: // check slave
7652: continue;
7653: }
7654: if(pic[c].isr & bit) {
7655: break;
7656: }
7657: // interrupt request
7658: pic_req_chip = c;
7659: pic_req_level = level;
7660: pic_req_bit = bit;
1.1.1.3 root 7661: i386_set_irq_line(INPUT_LINE_IRQ, HOLD_LINE);
1.1 root 7662: return;
7663: }
1.1.1.3 root 7664: i386_set_irq_line(INPUT_LINE_IRQ, CLEAR_LINE);
1.1.1.2 root 7665: }
1.1 root 7666:
7667: // pit
7668:
7669: #define PIT_FREQ 1193182
7670: #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)
7671:
7672: void pit_init()
7673: {
1.1.1.8 root 7674: memset(pit, 0, sizeof(pit));
1.1 root 7675: for(int ch = 0; ch < 3; ch++) {
7676: pit[ch].count = 0x10000;
7677: pit[ch].ctrl_reg = 0x34;
7678: pit[ch].mode = 3;
7679: }
7680:
7681: // from bochs bios
7682: pit_write(3, 0x34);
7683: pit_write(0, 0x00);
7684: pit_write(0, 0x00);
7685: }
7686:
7687: void pit_write(int ch, UINT8 val)
7688: {
1.1.1.8 root 7689: #ifndef PIT_ALWAYS_RUNNING
1.1 root 7690: if(!pit_active) {
7691: pit_active = 1;
7692: pit_init();
7693: }
1.1.1.8 root 7694: #endif
1.1 root 7695: switch(ch) {
7696: case 0:
7697: case 1:
7698: case 2:
7699: // write count register
7700: if(!pit[ch].low_write && !pit[ch].high_write) {
7701: if(pit[ch].ctrl_reg & 0x10) {
7702: pit[ch].low_write = 1;
7703: }
7704: if(pit[ch].ctrl_reg & 0x20) {
7705: pit[ch].high_write = 1;
7706: }
7707: }
7708: if(pit[ch].low_write) {
7709: pit[ch].count_reg = val;
7710: pit[ch].low_write = 0;
7711: } else if(pit[ch].high_write) {
7712: if((pit[ch].ctrl_reg & 0x30) == 0x20) {
7713: pit[ch].count_reg = val << 8;
7714: } else {
7715: pit[ch].count_reg |= val << 8;
7716: }
7717: pit[ch].high_write = 0;
7718: }
7719: // start count
1.1.1.8 root 7720: if(!pit[ch].low_write && !pit[ch].high_write) {
7721: if(pit[ch].mode == 0 || pit[ch].mode == 4 || pit[ch].prev_time == 0) {
7722: pit[ch].count = PIT_COUNT_VALUE(ch);
7723: pit[ch].prev_time = timeGetTime();
7724: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 7725: }
7726: }
7727: break;
7728: case 3: // ctrl reg
7729: if((val & 0xc0) == 0xc0) {
7730: // i8254 read-back command
7731: for(ch = 0; ch < 3; ch++) {
7732: if(!(val & 0x10) && !pit[ch].status_latched) {
7733: pit[ch].status = pit[ch].ctrl_reg & 0x3f;
7734: pit[ch].status_latched = 1;
7735: }
7736: if(!(val & 0x20) && !pit[ch].count_latched) {
7737: pit_latch_count(ch);
7738: }
7739: }
7740: break;
7741: }
7742: ch = (val >> 6) & 3;
7743: if(val & 0x30) {
7744: static int modes[8] = {0, 1, 2, 3, 4, 5, 2, 3};
7745: pit[ch].mode = modes[(val >> 1) & 7];
7746: pit[ch].count_latched = 0;
7747: pit[ch].low_read = pit[ch].high_read = 0;
7748: pit[ch].low_write = pit[ch].high_write = 0;
7749: pit[ch].ctrl_reg = val;
7750: // stop count
1.1.1.8 root 7751: pit[ch].prev_time = pit[ch].expired_time = 0;
1.1 root 7752: pit[ch].count_reg = 0;
7753: } else if(!pit[ch].count_latched) {
7754: pit_latch_count(ch);
7755: }
7756: break;
7757: }
7758: }
7759:
7760: UINT8 pit_read(int ch)
7761: {
1.1.1.8 root 7762: #ifndef PIT_ALWAYS_RUNNING
1.1 root 7763: if(!pit_active) {
7764: pit_active = 1;
7765: pit_init();
7766: }
1.1.1.8 root 7767: #endif
1.1 root 7768: switch(ch) {
7769: case 0:
7770: case 1:
7771: case 2:
7772: if(pit[ch].status_latched) {
7773: pit[ch].status_latched = 0;
7774: return(pit[ch].status);
7775: }
7776: // if not latched, through current count
7777: if(!pit[ch].count_latched) {
7778: if(!pit[ch].low_read && !pit[ch].high_read) {
7779: pit_latch_count(ch);
7780: }
7781: }
7782: // return latched count
7783: if(pit[ch].low_read) {
7784: pit[ch].low_read = 0;
7785: if(!pit[ch].high_read) {
7786: pit[ch].count_latched = 0;
7787: }
7788: return(pit[ch].latch & 0xff);
7789: } else if(pit[ch].high_read) {
7790: pit[ch].high_read = 0;
7791: pit[ch].count_latched = 0;
7792: return((pit[ch].latch >> 8) & 0xff);
7793: }
7794: }
7795: return(0xff);
7796: }
7797:
1.1.1.8 root 7798: int pit_run(int ch, UINT32 cur_time)
1.1 root 7799: {
1.1.1.8 root 7800: if(pit[ch].expired_time != 0 && cur_time >= pit[ch].expired_time) {
1.1 root 7801: pit[ch].count = PIT_COUNT_VALUE(ch);
1.1.1.8 root 7802: pit[ch].prev_time = pit[ch].expired_time;
7803: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
7804: if(cur_time >= pit[ch].expired_time) {
7805: pit[ch].prev_time = cur_time;
7806: pit[ch].expired_time = pit[ch].prev_time + pit_get_expired_time(ch);
1.1 root 7807: }
1.1.1.8 root 7808: return(1);
1.1 root 7809: }
1.1.1.8 root 7810: return(0);
1.1 root 7811: }
7812:
7813: void pit_latch_count(int ch)
7814: {
1.1.1.8 root 7815: UINT32 cur_time = timeGetTime();
7816:
7817: if(pit[ch].expired_time != 0) {
7818: pit_run(ch, cur_time);
7819: UINT32 tmp = (pit[ch].count * (pit[ch].expired_time - cur_time)) / (pit[ch].expired_time - pit[ch].prev_time);
7820: pit[ch].latch = (tmp != 0) ? (UINT16)tmp : 1;
7821: } else {
7822: pit[ch].latch = (UINT16)pit[ch].count;
1.1 root 7823: }
7824: pit[ch].count_latched = 1;
7825: if((pit[ch].ctrl_reg & 0x30) == 0x10) {
7826: // lower byte
7827: pit[ch].low_read = 1;
7828: pit[ch].high_read = 0;
7829: } else if((pit[ch].ctrl_reg & 0x30) == 0x20) {
7830: // upper byte
7831: pit[ch].low_read = 0;
7832: pit[ch].high_read = 1;
7833: } else {
7834: // lower -> upper
1.1.1.14 root 7835: pit[ch].low_read = pit[ch].high_read = 1;
1.1 root 7836: }
7837: }
7838:
1.1.1.8 root 7839: int pit_get_expired_time(int ch)
1.1 root 7840: {
1.1.1.8 root 7841: UINT32 val = (1000 * pit[ch].count) / PIT_FREQ;
7842: return((val > 0) ? val : 1);
7843: }
7844:
7845: // cmos
7846:
7847: void cmos_init()
7848: {
7849: memset(cmos, 0, sizeof(cmos));
7850: cmos_addr = 0;
1.1 root 7851:
1.1.1.8 root 7852: // from DOSBox
7853: cmos_write(0x0a, 0x26);
7854: cmos_write(0x0b, 0x02);
7855: cmos_write(0x0d, 0x80);
1.1 root 7856: }
7857:
1.1.1.8 root 7858: void cmos_write(int addr, UINT8 val)
1.1 root 7859: {
1.1.1.8 root 7860: cmos[addr & 0x7f] = val;
7861: }
7862:
7863: #define CMOS_GET_TIME() { \
7864: UINT32 cur_sec = timeGetTime() / 1000 ; \
7865: if(prev_sec != cur_sec) { \
7866: GetLocalTime(&time); \
7867: prev_sec = cur_sec; \
7868: } \
1.1 root 7869: }
1.1.1.8 root 7870: #define CMOS_BCD(v) ((cmos[0x0b] & 4) ? (v) : to_bcd(v))
1.1 root 7871:
1.1.1.8 root 7872: UINT8 cmos_read(int addr)
1.1 root 7873: {
1.1.1.8 root 7874: static SYSTEMTIME time;
7875: static UINT32 prev_sec = 0;
1.1 root 7876:
1.1.1.8 root 7877: switch(addr & 0x7f) {
7878: case 0x00: CMOS_GET_TIME(); return(CMOS_BCD(time.wSecond));
7879: case 0x02: CMOS_GET_TIME(); return(CMOS_BCD(time.wMinute));
7880: case 0x04: CMOS_GET_TIME(); return(CMOS_BCD(time.wHour));
7881: case 0x06: CMOS_GET_TIME(); return(time.wDayOfWeek + 1);
7882: case 0x07: CMOS_GET_TIME(); return(CMOS_BCD(time.wDay));
7883: case 0x08: CMOS_GET_TIME(); return(CMOS_BCD(time.wMonth));
7884: case 0x09: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear));
7885: // case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 2 ? 0x80 : 0)); // 2msec
7886: case 0x0a: return((cmos[0x0a] & 0x7f) | ((timeGetTime() % 1000) < 20 ? 0x80 : 0)); // precision of timeGetTime() may not be 1msec
7887: case 0x15: return((MEMORY_END >> 10) & 0xff);
7888: case 0x16: return((MEMORY_END >> 18) & 0xff);
7889: case 0x17: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
7890: case 0x18: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
7891: case 0x30: return(((MAX_MEM - 0x100000) >> 10) & 0xff);
7892: case 0x31: return(((MAX_MEM - 0x100000) >> 18) & 0xff);
7893: case 0x32: CMOS_GET_TIME(); return(CMOS_BCD(time.wYear / 100));
1.1 root 7894: }
1.1.1.8 root 7895: return(cmos[addr & 0x7f]);
1.1 root 7896: }
7897:
1.1.1.7 root 7898: // kbd (a20)
7899:
7900: void kbd_init()
7901: {
1.1.1.8 root 7902: kbd_data = kbd_command = 0;
1.1.1.7 root 7903: kbd_status = 0x18;
7904: }
7905:
7906: UINT8 kbd_read_data()
7907: {
1.1.1.8 root 7908: kbd_status &= ~1;
1.1.1.7 root 7909: return(kbd_data);
7910: }
7911:
7912: void kbd_write_data(UINT8 val)
7913: {
7914: switch(kbd_command) {
7915: case 0xd1:
7916: i386_set_a20_line((val >> 1) & 1);
7917: break;
7918: }
7919: kbd_command = 0;
1.1.1.8 root 7920: kbd_status &= ~8;
1.1.1.7 root 7921: }
7922:
7923: UINT8 kbd_read_status()
7924: {
7925: return(kbd_status);
7926: }
7927:
7928: void kbd_write_command(UINT8 val)
7929: {
7930: switch(val) {
7931: case 0xd0:
7932: kbd_data = ((m_a20_mask >> 19) & 2) | 1;
1.1.1.8 root 7933: kbd_status |= 1;
1.1.1.7 root 7934: break;
7935: case 0xdd:
7936: i386_set_a20_line(0);
7937: break;
7938: case 0xdf:
7939: i386_set_a20_line(1);
7940: break;
7941: case 0xf0:
7942: case 0xf1:
7943: case 0xf2:
7944: case 0xf3:
7945: case 0xf4:
7946: case 0xf5:
7947: case 0xf6:
7948: case 0xf7:
7949: case 0xf8:
7950: case 0xf9:
7951: case 0xfa:
7952: case 0xfb:
7953: case 0xfc:
7954: case 0xfd:
7955: case 0xfe:
7956: case 0xff:
7957: if(!(val & 1)) {
1.1.1.8 root 7958: if((cmos[0x0f] & 0x7f) == 5) {
1.1.1.7 root 7959: // reset pic
7960: pic_init();
7961: pic[0].irr = pic[1].irr = 0x00;
7962: pic[0].imr = pic[1].imr = 0xff;
7963: }
7964: CPU_RESET_CALL(CPU_MODEL);
7965: i386_jmp_far(0x40, 0x67);
7966: }
7967: i386_set_a20_line((val >> 1) & 1);
7968: break;
7969: }
7970: kbd_command = val;
1.1.1.8 root 7971: kbd_status |= 8;
1.1.1.7 root 7972: }
7973:
1.1.1.9 root 7974: // vga
7975:
7976: UINT8 vga_read_status()
7977: {
7978: // 60hz
7979: static const int period[3] = {16, 17, 17};
7980: static int index = 0;
7981: UINT32 time = timeGetTime() % period[index];
7982:
7983: index = (index + 1) % 3;
1.1.1.14 root 7984: return((time < 4 ? 0x08 : 0) | (time == 0 ? 0 : 0x01));
1.1.1.9 root 7985: }
7986:
1.1 root 7987: // i/o bus
7988:
7989: UINT8 read_io_byte(offs_t addr)
7990: {
7991: switch(addr) {
7992: case 0x20:
7993: case 0x21:
7994: return(pic_read(0, addr));
7995: case 0x40:
7996: case 0x41:
7997: case 0x42:
7998: case 0x43:
7999: return(pit_read(addr & 0x03));
1.1.1.7 root 8000: case 0x60:
8001: return(kbd_read_data());
1.1.1.9 root 8002: case 0x61:
8003: return(system_port);
1.1.1.7 root 8004: case 0x64:
8005: return(kbd_read_status());
1.1 root 8006: case 0x71:
1.1.1.8 root 8007: return(cmos_read(cmos_addr));
1.1 root 8008: case 0x92:
1.1.1.3 root 8009: return((m_a20_mask >> 19) & 2);
1.1 root 8010: case 0xa0:
8011: case 0xa1:
8012: return(pic_read(1, addr));
1.1.1.9 root 8013: case 0x3ba:
8014: case 0x3da:
8015: return(vga_read_status());
1.1 root 8016: default:
8017: // error("inb %4x\n", addr);
8018: break;
8019: }
8020: return(0xff);
8021: }
8022:
8023: UINT16 read_io_word(offs_t addr)
8024: {
8025: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8));
8026: }
8027:
8028: UINT32 read_io_dword(offs_t addr)
8029: {
8030: return(read_io_byte(addr) | (read_io_byte(addr + 1) << 8) | (read_io_byte(addr + 2) << 16) | (read_io_byte(addr + 3) << 24));
8031: }
8032:
8033: void write_io_byte(offs_t addr, UINT8 val)
8034: {
8035: switch(addr) {
8036: case 0x20:
8037: case 0x21:
8038: pic_write(0, addr, val);
8039: break;
8040: case 0x40:
8041: case 0x41:
8042: case 0x42:
8043: case 0x43:
8044: pit_write(addr & 0x03, val);
8045: break;
1.1.1.7 root 8046: case 0x60:
8047: kbd_write_data(val);
8048: break;
1.1.1.9 root 8049: case 0x61:
8050: if((system_port & 3) != 3 && (val & 3) == 3) {
8051: // beep on
8052: // MessageBeep(-1);
8053: } else if((system_port & 3) == 3 && (val & 3) != 3) {
8054: // beep off
8055: }
8056: system_port = val;
8057: break;
1.1 root 8058: case 0x64:
1.1.1.7 root 8059: kbd_write_command(val);
1.1 root 8060: break;
8061: case 0x70:
8062: cmos_addr = val;
8063: break;
8064: case 0x71:
1.1.1.8 root 8065: cmos_write(cmos_addr, val);
1.1 root 8066: break;
8067: case 0x92:
1.1.1.7 root 8068: i386_set_a20_line((val >> 1) & 1);
1.1 root 8069: break;
8070: case 0xa0:
8071: case 0xa1:
8072: pic_write(1, addr, val);
8073: break;
8074: default:
8075: // error("outb %4x,%2x\n", addr, val);
8076: break;
8077: }
8078: }
8079:
8080: void write_io_word(offs_t addr, UINT16 val)
8081: {
8082: write_io_byte(addr + 0, (val >> 0) & 0xff);
8083: write_io_byte(addr + 1, (val >> 8) & 0xff);
8084: }
8085:
8086: void write_io_dword(offs_t addr, UINT32 val)
8087: {
8088: write_io_byte(addr + 0, (val >> 0) & 0xff);
8089: write_io_byte(addr + 1, (val >> 8) & 0xff);
8090: write_io_byte(addr + 2, (val >> 16) & 0xff);
8091: write_io_byte(addr + 3, (val >> 24) & 0xff);
8092: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.