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