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