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