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