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