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