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