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