rev |
line source |
pascal@11674
|
1 /*
|
pascal@11674
|
2 * Simple example of use of vm86: launch a basic .com DOS executable
|
pascal@11674
|
3 */
|
pascal@11674
|
4 #include <stdlib.h>
|
pascal@11674
|
5 #include <stdio.h>
|
pascal@11674
|
6 #include <string.h>
|
pascal@11674
|
7 #include <inttypes.h>
|
pascal@11674
|
8 #include <unistd.h>
|
pascal@11674
|
9 #include <fcntl.h>
|
pascal@11674
|
10 #include <time.h>
|
pascal@11674
|
11 #include <sys/mman.h>
|
pascal@11674
|
12 #include <sys/ioctl.h>
|
pascal@11674
|
13 #include <sys/time.h>
|
pascal@11674
|
14 #include <sys/types.h>
|
pascal@11674
|
15 #include <sys/stat.h>
|
pascal@17124
|
16 #include <sys/statfs.h>
|
pascal@11674
|
17 #include <signal.h>
|
pascal@11674
|
18 #include <errno.h>
|
pascal@11674
|
19 #include <ctype.h>
|
pascal@11674
|
20 #include <termios.h>
|
pascal@17124
|
21 #include <dirent.h>
|
pascal@17124
|
22 #include <fnmatch.h>
|
pascal@11674
|
23
|
pascal@11674
|
24 #include <sys/syscall.h>
|
pascal@11674
|
25 #include <asm/vm86.h>
|
pascal@11674
|
26
|
pascal@11674
|
27 //#define DUMP_INT21
|
pascal@11674
|
28
|
pascal@11674
|
29 static inline int vm86(int func, struct vm86plus_struct *v86)
|
pascal@11674
|
30 {
|
pascal@11674
|
31 return syscall(__NR_vm86, func, v86);
|
pascal@11674
|
32 }
|
pascal@11674
|
33
|
pascal@11674
|
34 #define CF_MASK 0x00000001
|
pascal@11674
|
35 #define ZF_MASK 0x00000040
|
pascal@11674
|
36 #define TF_MASK 0x00000100
|
pascal@11674
|
37 #define IF_MASK 0x00000200
|
pascal@11674
|
38 #define DF_MASK 0x00000400
|
pascal@11674
|
39 #define IOPL_MASK 0x00003000
|
pascal@11674
|
40 #define NT_MASK 0x00004000
|
pascal@11674
|
41 #define RF_MASK 0x00010000
|
pascal@11674
|
42 #define VM_MASK 0x00020000
|
pascal@11674
|
43 #define AC_MASK 0x00040000
|
pascal@11674
|
44 #define VIF_MASK 0x00080000
|
pascal@11674
|
45 #define VIP_MASK 0x00100000
|
pascal@11674
|
46 #define ID_MASK 0x00200000
|
pascal@11674
|
47
|
pascal@11674
|
48 void usage(void)
|
pascal@11674
|
49 {
|
pascal@11674
|
50 printf("runcom version 0.2-slitaz (c) 2003-2011 Fabrice Bellard\n"
|
pascal@11674
|
51 "usage: runcom file.com [args...]\n"
|
pascal@11674
|
52 "Run simple .com DOS executables (linux vm86 test mode)\n");
|
pascal@11674
|
53 exit(1);
|
pascal@11674
|
54 }
|
pascal@11674
|
55
|
pascal@11674
|
56 static inline void set_bit(uint8_t *a, unsigned int bit)
|
pascal@11674
|
57 {
|
pascal@11674
|
58 a[bit / 8] |= (1 << (bit % 8));
|
pascal@11674
|
59 }
|
pascal@11674
|
60
|
pascal@11674
|
61 static inline uint8_t *seg_to_linear(unsigned int seg, unsigned int reg)
|
pascal@11674
|
62 {
|
pascal@11674
|
63 return (uint8_t *)((seg << 4) + (reg & 0xffff));
|
pascal@11674
|
64 }
|
pascal@11674
|
65
|
pascal@11674
|
66 static inline void pushw(struct vm86_regs *r, int val)
|
pascal@11674
|
67 {
|
pascal@11674
|
68 r->esp = (r->esp & ~0xffff) | ((r->esp - 2) & 0xffff);
|
pascal@11674
|
69 *(uint16_t *)seg_to_linear(r->ss, r->esp) = val;
|
pascal@11674
|
70 }
|
pascal@11674
|
71
|
pascal@11674
|
72 void dump_regs(struct vm86_regs *r)
|
pascal@11674
|
73 {
|
pascal@11674
|
74 int i;
|
pascal@11674
|
75 uint8_t *p8;
|
pascal@11674
|
76 uint16_t *p16;
|
pascal@11674
|
77 fprintf(stderr,
|
pascal@11674
|
78 "EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx\n"
|
pascal@11674
|
79 "ESI=%08lx EDI=%08lx EBP=%08lx ESP=%08lx\n"
|
pascal@11674
|
80 "EIP=%08lx EFL=%08lx "
|
pascal@11674
|
81 "CS=%04x DS=%04x ES=%04x SS=%04x FS=%04x GS=%04x\n[SP]",
|
pascal@11674
|
82 r->eax, r->ebx, r->ecx, r->edx, r->esi, r->edi, r->ebp, r->esp,
|
pascal@11674
|
83 r->eip, r->eflags,
|
pascal@11674
|
84 r->cs, r->ds, r->es, r->ss, r->fs, r->gs);
|
pascal@11674
|
85 for (p16 = (uint16_t *) seg_to_linear(r->ss, r->esp), i = 0; i < 15; i++)
|
pascal@11674
|
86 fprintf(stderr," %04x", *p16++);
|
pascal@11674
|
87 fprintf(stderr,"\n[IP]");
|
pascal@11674
|
88 for (p8 = seg_to_linear(r->cs, r->eip), i = 0; i < 25; i++)
|
pascal@11674
|
89 fprintf(stderr," %02x", *p8++);
|
pascal@11674
|
90 fprintf(stderr,"\n");
|
pascal@11674
|
91 }
|
pascal@11674
|
92
|
pascal@17124
|
93 static int argflags;
|
pascal@17124
|
94 #define DEBUG 1
|
pascal@17124
|
95
|
pascal@11674
|
96 #define DOS_FD_MAX 256
|
pascal@11674
|
97 typedef struct {
|
pascal@11674
|
98 int fd; /* -1 means closed */
|
pascal@11674
|
99 } DOSFile;
|
pascal@11674
|
100
|
pascal@11674
|
101 DOSFile dos_files[DOS_FD_MAX];
|
pascal@11674
|
102 uint16_t cur_psp;
|
pascal@17124
|
103 uint16_t cur_dta_seg;
|
pascal@17124
|
104 uint16_t cur_dta_ofs;
|
pascal@11674
|
105
|
pascal@11674
|
106 void dos_init(void)
|
pascal@11674
|
107 {
|
pascal@11674
|
108 int i;
|
pascal@11674
|
109 for(i = 0; i < DOS_FD_MAX; i++)
|
pascal@11674
|
110 dos_files[i].fd = (i < 3) ? i : -1;
|
pascal@11674
|
111 }
|
pascal@11674
|
112
|
pascal@11674
|
113 static inline void set_error(struct vm86_regs *r, int val)
|
pascal@11674
|
114 {
|
pascal@11674
|
115 r->eflags &= ~CF_MASK;
|
pascal@11674
|
116 if (val) {
|
pascal@11674
|
117 r->eax = (r->eax & ~0xffff) | val;
|
pascal@11674
|
118 r->eflags |= CF_MASK;
|
pascal@11674
|
119 }
|
pascal@11674
|
120 }
|
pascal@11674
|
121 static DOSFile *get_file(int h)
|
pascal@11674
|
122 {
|
pascal@11674
|
123 DOSFile *fh;
|
pascal@11674
|
124
|
pascal@11674
|
125 if (h < DOS_FD_MAX) {
|
pascal@11674
|
126 fh = &dos_files[h];
|
pascal@11674
|
127 if (fh->fd != -1)
|
pascal@11674
|
128 return fh;
|
pascal@11674
|
129 }
|
pascal@11674
|
130 return NULL;
|
pascal@11674
|
131 }
|
pascal@11674
|
132
|
pascal@11674
|
133 /* return -1 if error */
|
pascal@11674
|
134 static int get_new_handle(void)
|
pascal@11674
|
135 {
|
pascal@11674
|
136 DOSFile *fh;
|
pascal@11674
|
137 int i;
|
pascal@11674
|
138
|
pascal@11674
|
139 for(i = 0; i < DOS_FD_MAX; i++) {
|
pascal@11674
|
140 fh = &dos_files[i];
|
pascal@11674
|
141 if (fh->fd == -1)
|
pascal@11674
|
142 return i;
|
pascal@11674
|
143 }
|
pascal@11674
|
144 return -1;
|
pascal@11674
|
145 }
|
pascal@11674
|
146
|
pascal@11674
|
147 static char *get_filename1(struct vm86_regs *r, char *buf, int buf_size,
|
pascal@11674
|
148 uint16_t seg, uint16_t offset)
|
pascal@11674
|
149 {
|
pascal@11674
|
150 char *q;
|
pascal@11674
|
151 int c;
|
pascal@11674
|
152 q = buf;
|
pascal@11674
|
153 for(;;) {
|
pascal@11674
|
154 c = *seg_to_linear(seg, offset);
|
pascal@11674
|
155 if (c == 0)
|
pascal@11674
|
156 break;
|
pascal@11674
|
157 if (q >= buf + buf_size - 1)
|
pascal@11674
|
158 break;
|
pascal@11674
|
159 c = tolower(c);
|
pascal@11674
|
160 if (c == '\\')
|
pascal@11674
|
161 c = '/';
|
pascal@11674
|
162 *q++ = c;
|
pascal@11674
|
163 offset++;
|
pascal@11674
|
164 }
|
pascal@11674
|
165 *q = '\0';
|
pascal@17124
|
166 if (buf[1] == ':')
|
pascal@17124
|
167 strcpy(buf, buf+2);
|
pascal@11674
|
168 return buf;
|
pascal@11674
|
169 }
|
pascal@11674
|
170
|
pascal@11674
|
171 static char *get_filename(struct vm86_regs *r, char *buf, int buf_size)
|
pascal@11674
|
172 {
|
pascal@11674
|
173 return get_filename1(r, buf, buf_size, r->ds, r->edx & 0xffff);
|
pascal@11674
|
174 }
|
pascal@11674
|
175
|
pascal@17124
|
176 static char *upcase(const char *s)
|
pascal@17124
|
177 {
|
pascal@17124
|
178 static char buffer[80];
|
pascal@17124
|
179 int i;
|
pascal@17124
|
180 for (i = 0; i < sizeof(buffer)-1; i++, s++)
|
pascal@17124
|
181 buffer[i] = (*s >= 'a' && *s <= 'z') ? *s + 'A' - 'a' : *s;
|
pascal@17124
|
182 return buffer;
|
pascal@17124
|
183 }
|
pascal@17124
|
184
|
pascal@11674
|
185 typedef struct __attribute__((packed)) {
|
pascal@11674
|
186 uint8_t drive_num;
|
pascal@11674
|
187 uint8_t file_name[8];
|
pascal@11674
|
188 uint8_t file_ext[3];
|
pascal@11674
|
189 uint16_t current_block;
|
pascal@11674
|
190 uint16_t logical_record_size;
|
pascal@11674
|
191 uint32_t file_size;
|
pascal@11674
|
192 uint16_t date;
|
pascal@11674
|
193 uint16_t time;
|
pascal@11674
|
194 uint8_t reserved[8];
|
pascal@11674
|
195 uint8_t record_in_block;
|
pascal@11674
|
196 uint32_t record_num;
|
pascal@11674
|
197 } FCB;
|
pascal@11674
|
198
|
pascal@11674
|
199 typedef struct __attribute__((packed)) {
|
pascal@11674
|
200 uint16_t environ;
|
pascal@11674
|
201 uint16_t cmdtail_off;
|
pascal@11674
|
202 uint16_t cmdtail_seg;
|
pascal@11674
|
203 uint32_t fcb1;
|
pascal@11674
|
204 uint32_t fcb2;
|
pascal@11674
|
205 uint16_t sp, ss;
|
pascal@11674
|
206 uint16_t ip, cs;
|
pascal@11674
|
207 } ExecParamBlock;
|
pascal@11674
|
208
|
pascal@17124
|
209 typedef struct __attribute__((packed)) {
|
pascal@17124
|
210 /* internals */
|
pascal@17124
|
211 uint8_t attr; /* 00 */
|
pascal@17124
|
212 uint8_t drive_letter; /* 01 */
|
pascal@17124
|
213 uint8_t template[11]; /* 02 */
|
pascal@17124
|
214 uint16_t entry_count; /* 0D */
|
pascal@17124
|
215 uint32_t dta_address; /* 0F */
|
pascal@17124
|
216 uint16_t cluster_parent_dir; /* 13 */
|
pascal@17124
|
217 /* output */
|
pascal@17124
|
218 uint8_t attr_found; /* 15 */
|
pascal@17124
|
219 uint16_t file_time; /* 16 */
|
pascal@17124
|
220 uint16_t file_date; /* 18 */
|
pascal@17124
|
221 uint32_t file_size; /* 1A */
|
pascal@17124
|
222 uint8_t filename[13]; /* 1E */
|
pascal@17124
|
223 } dirdta;
|
pascal@17124
|
224
|
pascal@11674
|
225 typedef struct MemBlock {
|
pascal@11674
|
226 struct MemBlock *next;
|
pascal@11674
|
227 uint16_t seg;
|
pascal@11674
|
228 uint16_t size; /* in paragraphs */
|
pascal@11674
|
229 } MemBlock;
|
pascal@11674
|
230
|
pascal@11674
|
231 /* first allocated paragraph */
|
pascal@11674
|
232 MemBlock *first_mem_block = NULL;
|
pascal@11674
|
233
|
pascal@11674
|
234 #define MEM_START 0x1000
|
pascal@11674
|
235 #define MEM_END 0xa000
|
pascal@11674
|
236
|
pascal@11674
|
237 /* return -1 if error */
|
pascal@11674
|
238 int mem_malloc(int size, int *pmax_size)
|
pascal@11674
|
239 {
|
pascal@11674
|
240 MemBlock *m, **pm;
|
pascal@11674
|
241 int seg_free, seg;
|
pascal@11674
|
242
|
pascal@11674
|
243 /* XXX: this is totally inefficient, but we have only 1 or 2
|
pascal@11674
|
244 blocks ! */
|
pascal@11674
|
245 seg_free = MEM_START;
|
pascal@11674
|
246 for(pm = &first_mem_block; *pm != NULL; pm = &(*pm)->next) {
|
pascal@11674
|
247 m = *pm;
|
pascal@11674
|
248 seg = m->seg + m->size;
|
pascal@11674
|
249 if (seg > seg_free)
|
pascal@11674
|
250 seg_free = seg;
|
pascal@11674
|
251 }
|
pascal@11674
|
252 if ((seg_free + size) > MEM_END)
|
pascal@11674
|
253 return -1;
|
pascal@11674
|
254 if (pmax_size)
|
pascal@11674
|
255 *pmax_size = MEM_END - seg_free;
|
pascal@11674
|
256 /* add at the end */
|
pascal@11674
|
257 m = malloc(sizeof(MemBlock));
|
pascal@11674
|
258 *pm = m;
|
pascal@11674
|
259 m->next = NULL;
|
pascal@11674
|
260 m->seg = seg_free;
|
pascal@11674
|
261 m->size = size;
|
pascal@11674
|
262 #ifdef DUMP_INT21
|
pascal@11674
|
263 printf("mem_malloc size=0x%04x: 0x%04x\n", size, seg_free);
|
pascal@11674
|
264 #endif
|
pascal@11674
|
265 return seg_free;
|
pascal@11674
|
266 }
|
pascal@11674
|
267
|
pascal@11674
|
268 /* return -1 if error */
|
pascal@11674
|
269 int mem_free(int seg)
|
pascal@11674
|
270 {
|
pascal@11674
|
271 MemBlock *m, **pm;
|
pascal@11674
|
272 for(pm = &first_mem_block; *pm != NULL; pm = &(*pm)->next) {
|
pascal@11674
|
273 m = *pm;
|
pascal@11674
|
274 if (m->seg == seg) {
|
pascal@11674
|
275 *pm = m->next;
|
pascal@11674
|
276 free(m);
|
pascal@11674
|
277 return 0;
|
pascal@11674
|
278 }
|
pascal@11674
|
279 }
|
pascal@11674
|
280 return -1;
|
pascal@11674
|
281 }
|
pascal@11674
|
282
|
pascal@11674
|
283 /* return -1 if error or the maxmium size */
|
pascal@11674
|
284 int mem_resize(int seg, int new_size)
|
pascal@11674
|
285 {
|
pascal@11674
|
286 MemBlock *m, **pm, *m1;
|
pascal@11674
|
287 int max_size;
|
pascal@11674
|
288
|
pascal@11674
|
289 for(pm = &first_mem_block; *pm != NULL; pm = &(*pm)->next) {
|
pascal@11674
|
290 m = *pm;
|
pascal@11674
|
291 if (m->seg == seg) {
|
pascal@11674
|
292 m1 = m->next;
|
pascal@11674
|
293 if (!m1)
|
pascal@11674
|
294 max_size = MEM_END - m->seg;
|
pascal@11674
|
295 else
|
pascal@11674
|
296 max_size = m1->seg - m->seg;
|
pascal@11674
|
297 if (new_size > max_size)
|
pascal@11674
|
298 return -1;
|
pascal@11674
|
299 m->size = new_size;
|
pascal@11674
|
300 return max_size;
|
pascal@11674
|
301 }
|
pascal@11674
|
302 }
|
pascal@11674
|
303 return -1;
|
pascal@11674
|
304 }
|
pascal@11674
|
305
|
pascal@11674
|
306 int load_boot(const char *filename, struct vm86_regs *r)
|
pascal@11674
|
307 {
|
pascal@11674
|
308 int fd, ret;
|
pascal@11674
|
309
|
pascal@11674
|
310 /* load the boot sector */
|
pascal@11674
|
311 fd = open(filename, O_RDONLY);
|
pascal@11674
|
312 if (fd >= 0) {
|
pascal@11674
|
313 *seg_to_linear(0x0, 0x7dff) = 0;
|
pascal@11674
|
314 r->eax = 0x200;
|
pascal@11674
|
315 r->ebx = r->esp = r->eip = 0x7c00;
|
pascal@11674
|
316 r->ecx = 1;
|
pascal@11674
|
317 r->esi = r->edi = r->ebp =
|
pascal@11674
|
318 r->edx = 0; /* floppy disk */
|
pascal@11674
|
319 r->cs = r->ss = r->ds = r->es = 0;
|
pascal@11674
|
320 r->eflags = VIF_MASK;
|
pascal@11674
|
321 ret = read(fd, seg_to_linear(0x0, 0x7c00), 0x200);
|
pascal@11674
|
322 if (lseek(fd, 0, SEEK_END) > 4*1024*1024)
|
pascal@11674
|
323 r->edx = 0x80; /* hard disk */
|
pascal@11674
|
324 close(fd);
|
pascal@11674
|
325 if (ret != 0x200 ||
|
pascal@11674
|
326 *seg_to_linear(0x0, 0x7dfe) != 0x55 ||
|
pascal@11674
|
327 *seg_to_linear(0x0, 0x7dff) != 0xaa) {
|
pascal@11674
|
328 fprintf(stderr,"No boot sector.\n");
|
pascal@11674
|
329 fd = -1;
|
pascal@11674
|
330 }
|
pascal@11674
|
331 }
|
pascal@11674
|
332 return fd;
|
pascal@11674
|
333 }
|
pascal@11674
|
334
|
pascal@11674
|
335 /* return the PSP or -1 if error */
|
pascal@11674
|
336 int load_exe(ExecParamBlock *blk, const char *filename,
|
pascal@11674
|
337 int psp, uint32_t *pfile_size)
|
pascal@11674
|
338 {
|
pascal@11674
|
339 int fd, size, base;
|
pascal@11674
|
340 struct {
|
pascal@11674
|
341 uint16_t signature; // 0x5A4D 'MZ'
|
pascal@11674
|
342 uint16_t bytes_in_last_block;
|
pascal@11674
|
343 uint16_t blocks_in_file;
|
pascal@11674
|
344 uint16_t num_relocs;
|
pascal@11674
|
345 uint16_t header_paragraphs; // Size of header
|
pascal@11674
|
346 uint16_t min_extra_paragraphs; // BSS size
|
pascal@11674
|
347 uint16_t max_extra_paragraphs;
|
pascal@11674
|
348 uint16_t ss; // Initial (relative) SS value
|
pascal@11674
|
349 uint16_t sp; // Initial SP value
|
pascal@11674
|
350 uint16_t checksum;
|
pascal@11674
|
351 uint16_t ip; // Initial IP value
|
pascal@11674
|
352 uint16_t cs; // Initial (relative) CS value
|
pascal@11674
|
353 uint16_t reloc_table_offset;
|
pascal@11674
|
354 uint16_t overlay_number;
|
pascal@11674
|
355 } header;
|
pascal@11674
|
356 struct {
|
pascal@11674
|
357 uint16_t offset;
|
pascal@11674
|
358 uint16_t segment;
|
pascal@11674
|
359 } rel;
|
pascal@11674
|
360
|
pascal@11674
|
361 /* load the MSDOS .exe executable */
|
pascal@11674
|
362 fd = open(filename, O_RDONLY);
|
pascal@11674
|
363 if (fd < 0) {
|
pascal@11674
|
364 return -1;
|
pascal@11674
|
365 }
|
pascal@11674
|
366 if (read(fd, &header, sizeof(header)) != sizeof(header)) {
|
pascal@11674
|
367 close(fd);
|
pascal@11674
|
368 return -1;
|
pascal@11674
|
369 }
|
pascal@11674
|
370
|
pascal@11674
|
371 memset(seg_to_linear(psp, 0x100), 0, 65536 - 0x100);
|
pascal@11674
|
372
|
pascal@11674
|
373 size = (header.blocks_in_file * 512) - (header.header_paragraphs * 16) +
|
pascal@11674
|
374 (header.bytes_in_last_block ? header.bytes_in_last_block - 512 : 0);
|
pascal@11674
|
375 header.min_extra_paragraphs += (size-1)/16;
|
pascal@11674
|
376
|
pascal@11674
|
377 /* address of last segment allocated */
|
pascal@17124
|
378 //*(uint16_t *)seg_to_linear(psp, 2) = psp + header.min_extra_paragraphs;
|
pascal@17124
|
379 *(uint16_t *)seg_to_linear(psp, 2) = 0x9fff;
|
pascal@11674
|
380
|
pascal@11674
|
381 if (pfile_size)
|
pascal@11674
|
382 *pfile_size = size;
|
pascal@11674
|
383
|
pascal@11674
|
384 if (mem_resize(psp, header.min_extra_paragraphs) < 0 ||
|
pascal@11674
|
385 lseek(fd, header.header_paragraphs * 16, SEEK_SET) < 0 ||
|
pascal@11674
|
386 read(fd, seg_to_linear(psp, 0x100), size) != size ||
|
pascal@11674
|
387 lseek(fd, header.reloc_table_offset, SEEK_SET) < 0) {
|
pascal@11674
|
388 close(fd);
|
pascal@11674
|
389 return -1;
|
pascal@11674
|
390 }
|
pascal@11674
|
391
|
pascal@11674
|
392 base = psp + 16;
|
pascal@11674
|
393 while (header.num_relocs-- && read(fd, &rel, sizeof(rel)) == sizeof(rel))
|
pascal@11674
|
394 if (rel.segment != 0 || rel.offset != 0)
|
pascal@11674
|
395 * (uint16_t *) seg_to_linear(base + rel.segment, rel.offset) += base;
|
pascal@11674
|
396 close(fd);
|
pascal@11674
|
397
|
pascal@11674
|
398 blk->cs = base + header.cs;
|
pascal@11674
|
399 blk->ip = header.ip;
|
pascal@11674
|
400 blk->ss = base + header.ss;
|
pascal@11674
|
401 blk->sp = header.sp - 6;
|
pascal@11674
|
402
|
pascal@11674
|
403 /* push return far address */
|
pascal@11674
|
404 *(uint16_t *)seg_to_linear(blk->ss, blk->sp + 4) = psp;
|
pascal@11674
|
405
|
pascal@11674
|
406 return psp;
|
pascal@11674
|
407 }
|
pascal@11674
|
408
|
pascal@11674
|
409 /* return the PSP or -1 if error */
|
pascal@11674
|
410 int load_com(ExecParamBlock *blk, const char *filename, uint32_t *pfile_size,
|
pascal@11674
|
411 int argc, char **argv)
|
pascal@11674
|
412 {
|
pascal@11674
|
413 int psp, fd, ret;
|
pascal@11674
|
414
|
pascal@11674
|
415 /* load the MSDOS .com executable */
|
pascal@11674
|
416 fd = open(filename, O_RDONLY);
|
pascal@17124
|
417 if (fd < 0)
|
pascal@17124
|
418 fd = open(upcase(filename), O_RDONLY);
|
pascal@11674
|
419 if (fd < 0) {
|
pascal@11674
|
420 return -1;
|
pascal@11674
|
421 }
|
pascal@11674
|
422 psp = mem_malloc(65536 / 16, NULL);
|
pascal@11674
|
423 ret = read(fd, seg_to_linear(psp, 0x100), 65536 - 0x100);
|
pascal@11674
|
424 close(fd);
|
pascal@11674
|
425 if (ret <= 0) {
|
pascal@11674
|
426 mem_free(psp);
|
pascal@11674
|
427 return -1;
|
pascal@11674
|
428 }
|
pascal@11674
|
429 if (pfile_size)
|
pascal@11674
|
430 *pfile_size = ret;
|
pascal@11674
|
431
|
pascal@11674
|
432 /* reset the PSP */
|
pascal@11674
|
433 memset(seg_to_linear(psp, 0), 0, 0x100);
|
pascal@11674
|
434
|
pascal@17124
|
435 * (uint16_t *) seg_to_linear(psp, 0) = 0x20CD; /* int $0x20 */
|
pascal@11674
|
436 /* address of last segment allocated */
|
pascal@17124
|
437 //*(uint16_t *)seg_to_linear(psp, 2) = psp + 0xfff;
|
pascal@17124
|
438 *(uint16_t *)seg_to_linear(psp, 2) = 0x9fff;
|
pascal@11674
|
439
|
pascal@11674
|
440 if (argc) {
|
pascal@11674
|
441 int i, p;
|
pascal@11674
|
442 char *s;
|
pascal@11674
|
443 /* set the command line */
|
pascal@11674
|
444 p = 0x81;
|
pascal@11674
|
445 for(i = 2; i < argc; i++) {
|
pascal@11674
|
446 if (p >= 0xff)
|
pascal@11674
|
447 break;
|
pascal@11674
|
448 *seg_to_linear(psp, p++) = ' ';
|
pascal@11674
|
449 s = argv[i];
|
pascal@11674
|
450 while (*s) {
|
pascal@11674
|
451 if (p >= 0xff)
|
pascal@11674
|
452 break;
|
pascal@11674
|
453 *seg_to_linear(psp, p++) = *s++;
|
pascal@11674
|
454 }
|
pascal@11674
|
455 }
|
pascal@11674
|
456 *seg_to_linear(psp, p) = '\r';
|
pascal@11674
|
457 *seg_to_linear(psp, 0x80) = p - 0x81;
|
pascal@11674
|
458 }
|
pascal@11674
|
459 else {
|
pascal@11674
|
460 int len;
|
pascal@11674
|
461 /* copy the command line */
|
pascal@11674
|
462 len = *seg_to_linear(blk->cmdtail_seg, blk->cmdtail_off);
|
pascal@11674
|
463 memcpy(seg_to_linear(psp, 0x80),
|
pascal@11674
|
464 seg_to_linear(blk->cmdtail_seg, blk->cmdtail_off), len + 2);
|
pascal@11674
|
465 }
|
pascal@11674
|
466
|
pascal@11674
|
467 blk->sp = 0xfffc;
|
pascal@11674
|
468 blk->ip = 0x100;
|
pascal@11674
|
469 blk->cs = blk->ss = psp;
|
pascal@11674
|
470
|
pascal@11674
|
471 if (*(uint16_t *)seg_to_linear(psp, 0x100) == 0x5A4D)
|
pascal@11674
|
472 psp = load_exe(blk, filename, psp, pfile_size);
|
pascal@11674
|
473
|
pascal@11674
|
474 /* push ax value */
|
pascal@11674
|
475 *(uint16_t *)seg_to_linear(blk->ss, blk->sp) = 0;
|
pascal@11674
|
476 /* push return address to 0 */
|
pascal@11674
|
477 *(uint16_t *)seg_to_linear(blk->ss, blk->sp + 2) = 0;
|
pascal@11674
|
478
|
pascal@11674
|
479 return psp;
|
pascal@11674
|
480 }
|
pascal@11674
|
481
|
pascal@11674
|
482
|
pascal@11674
|
483 void unsupported_function(struct vm86_regs *r, uint8_t num, uint8_t ah)
|
pascal@11674
|
484 {
|
pascal@11674
|
485 fprintf(stderr, "int 0x%02x: unsupported function 0x%02x\n", num, ah);
|
pascal@11674
|
486 dump_regs(r);
|
pascal@11674
|
487 set_error(r, 0x01); /* function number invalid */
|
pascal@11674
|
488 }
|
pascal@11674
|
489
|
pascal@11674
|
490 /* Open hard disk image ./hd[0-7] / floppy image ./fd[0-7] or /dev/fd[0-7] */
|
pascal@11674
|
491 int open_disk(struct vm86_regs *r)
|
pascal@11674
|
492 {
|
pascal@11674
|
493 int fd = -1, drive = r->edx & 0xff;
|
pascal@11674
|
494 char filename[9], n = '0' + (drive & 7);
|
pascal@11674
|
495 if (drive > 127) {
|
pascal@11674
|
496 strcpy(filename,"hd0");
|
pascal@11674
|
497 filename[2] = n;
|
pascal@11674
|
498 }
|
pascal@11674
|
499 else {
|
pascal@11674
|
500 strcpy(filename,"/dev/fd0");
|
pascal@11674
|
501 filename[7] = n;
|
pascal@11674
|
502 fd = open(filename+5, O_RDONLY);
|
pascal@11674
|
503 }
|
pascal@11674
|
504 if (fd < 0)
|
pascal@11674
|
505 fd = open(filename, O_RDONLY);
|
pascal@11674
|
506 return fd;
|
pascal@11674
|
507 }
|
pascal@11674
|
508
|
pascal@11674
|
509
|
pascal@11674
|
510 void read_sectors(int fd, struct vm86_regs *r, int first_sector,
|
pascal@11674
|
511 int sector_count, void *buffer)
|
pascal@11674
|
512 {
|
pascal@11674
|
513 int drive = r->edx & 0xff;
|
pascal@11674
|
514 r->eax &= ~0xff00;
|
pascal@11674
|
515 r->eax |= 0x0400; /* sector not found */
|
pascal@11674
|
516 r->eflags |= CF_MASK;
|
pascal@11674
|
517 if (fd >= 0) {
|
pascal@11674
|
518 static struct stat st;
|
pascal@11674
|
519 first_sector <<= 9;
|
pascal@11674
|
520 sector_count <<= 9;
|
pascal@11674
|
521 if (drive < 8 && fstat(fd, &st) == 0) {
|
pascal@11674
|
522 static ino_t inodes[8];
|
pascal@11674
|
523 ino_t last = inodes[drive];
|
pascal@11674
|
524 inodes[drive] = st.st_ino;
|
pascal@11674
|
525 if (last && last != st.st_ino) {
|
pascal@11674
|
526 set_error(r, 0x0600); /* floppy disk swap */
|
pascal@11674
|
527 goto failed;
|
pascal@11674
|
528 }
|
pascal@11674
|
529 }
|
pascal@12554
|
530 if (lseek(fd, first_sector, SEEK_SET) >= 0 &&
|
pascal@11674
|
531 read(fd, buffer, sector_count) == sector_count) {
|
pascal@11674
|
532 r->eax &= ~0xff00;
|
pascal@11674
|
533 r->eflags &= ~CF_MASK;
|
pascal@11674
|
534 }
|
pascal@11674
|
535 failed:
|
pascal@11674
|
536 close(fd);
|
pascal@11674
|
537 }
|
pascal@11674
|
538 }
|
pascal@11674
|
539
|
pascal@17124
|
540 #define ESC "\033"
|
pascal@11674
|
541 void do_int10(struct vm86_regs *r)
|
pascal@11674
|
542 {
|
pascal@11674
|
543 uint8_t ah;
|
pascal@17124
|
544 char buf[20];
|
pascal@17124
|
545 static unsigned cursorlines = 0x0607;
|
pascal@17124
|
546 static unsigned activepage = 0;
|
pascal@17124
|
547 static uint8_t cursrow, curscol;
|
pascal@11674
|
548
|
pascal@11674
|
549 ah = (r->eax >> 8);
|
pascal@11674
|
550 switch(ah) {
|
pascal@17124
|
551 case 0x02: /* set cursor position (BH == page number) */
|
pascal@17124
|
552 cursrow = r->edx >> 8;
|
pascal@17124
|
553 curscol = r->edx;
|
pascal@17124
|
554 * (uint16_t *) seg_to_linear(0x40, 0x50 + 2*((r->ebx >> 8) & 0xFF)) = r->edx;
|
pascal@17124
|
555 sprintf(buf,ESC"[%u;%uH",cursrow + 1, curscol + 1);
|
pascal@17124
|
556 write(1, buf, strlen(buf));
|
pascal@17124
|
557 break;
|
pascal@17124
|
558 case 0x03: /* get cursor position (BH == page number) */
|
pascal@17124
|
559 r->eax = 0;
|
pascal@17124
|
560 r->ecx = cursorlines;
|
pascal@17124
|
561 r->edx &= ~0xFFFF;
|
pascal@17124
|
562 r->edx |= * (uint16_t *) seg_to_linear(0x40, 0x50 + 2*((r->ebx >> 8) & 0xFF));
|
pascal@17124
|
563 sprintf(buf,ESC"[%u;%uH",cursrow + 1, curscol + 1);
|
pascal@17124
|
564 write(1, buf, strlen(buf));
|
pascal@17124
|
565 break;
|
pascal@17124
|
566 case 0x05: /* set active page */
|
pascal@17124
|
567 activepage = r->eax & 0xFF;
|
pascal@17124
|
568 break;
|
pascal@17124
|
569 case 0x06: /* scroll up */
|
pascal@17124
|
570 case 0x07: /* scroll down */
|
pascal@17124
|
571 {
|
pascal@17124
|
572 int i = r->eax & 0xFF;
|
pascal@17124
|
573 if (i == 0) i = 50;
|
pascal@17124
|
574 /* FIXME assume full row, ignore colums in CL, DL */
|
pascal@17124
|
575 sprintf(buf,ESC"[%u;%ur",1+(r->ecx >> 8) & 0xFF, 1+(r->edx >> 8) & 0xFF);
|
pascal@17124
|
576 write(1, buf, strlen(buf));
|
pascal@17124
|
577 buf[2] = (ah != 6) ? 'T' : 'S';
|
pascal@17124
|
578 while (i--) write(1,buf,3);
|
pascal@17124
|
579 }
|
pascal@17124
|
580 break;
|
pascal@17124
|
581 case 0x09: /* write char and attribute at cursor position (BH == page number) */
|
pascal@17124
|
582 {
|
pascal@17124
|
583 static char color[8] = "04261537";
|
pascal@17124
|
584 char extra[5], *s = extra;
|
pascal@17124
|
585 uint8_t c = r->eax;
|
pascal@17124
|
586 uint16_t n = r->ecx;
|
pascal@17124
|
587 int i;
|
pascal@17124
|
588
|
pascal@17124
|
589 if (r->ebx & 0x8) { *s++ = '1'; *s++ = ';'; } // bold
|
pascal@17124
|
590 if (r->ebx & 0x80) { *s++ = '5'; *s++ = ';'; } // blink
|
pascal@17124
|
591 *s = 0;
|
pascal@17124
|
592 sprintf(buf,ESC"[0;%s4%c;3%cm",extra,
|
pascal@17124
|
593 color[(r->ebx & 0x70) >> 4],color[r->ebx & 0x7]);
|
pascal@17124
|
594 write(1, buf, strlen(buf));
|
pascal@17124
|
595 for (i = 0; i < n; i++)
|
pascal@17124
|
596 write(1, &c, 1);
|
pascal@17124
|
597 write(1, ESC"[0m", 4); /* restore attributes */
|
pascal@17124
|
598 }
|
pascal@17124
|
599 break;
|
pascal@11674
|
600 case 0x0E: /* write char */
|
pascal@11674
|
601 {
|
pascal@11674
|
602 uint8_t c = r->eax;
|
pascal@11674
|
603 write(1, &c, 1);
|
pascal@11674
|
604 }
|
pascal@11674
|
605 break;
|
pascal@17124
|
606 case 0x0F: /* get current video mode */
|
pascal@17124
|
607 {
|
pascal@17124
|
608 r->eax &= ~0xFFFF;
|
pascal@17124
|
609 r->eax |= 0x5003; /* color or 5007 mono */
|
pascal@17124
|
610 r->ebx &= ~0xFF00;
|
pascal@17124
|
611 r->ebx |= activepage << 8;
|
pascal@17124
|
612 }
|
pascal@17124
|
613 break;
|
pascal@17124
|
614 case 0x11: /* get window coordonates */
|
pascal@17124
|
615 r->ecx &= ~0xFFFF;
|
pascal@17124
|
616 r->edx &= ~0xFFFF;
|
pascal@17124
|
617 r->edx |= ~0x1950; /* 80x25 */
|
pascal@17124
|
618 break;
|
pascal@17124
|
619 case 0x12: /* get blanking attribute (for scroll) */
|
pascal@17124
|
620 r->ebx &= ~0xFF00;
|
pascal@17124
|
621 break;
|
pascal@17124
|
622 case 0x1A: /* get display combination code */
|
pascal@17124
|
623 #if 0
|
pascal@17124
|
624 set_error(r, 1);
|
pascal@17124
|
625 #else
|
pascal@17124
|
626 r->eax &= ~0xFF;
|
pascal@17124
|
627 r->eax |= ~0x1A;
|
pascal@17124
|
628 r->ebx &= ~0xFFFF;
|
pascal@17124
|
629 r->ebx |= ~0x0202; // CGA + color display
|
pascal@17124
|
630 #endif
|
pascal@17124
|
631 break;
|
pascal@11674
|
632 default:
|
pascal@11674
|
633 unsupported_function(r, 0x10, ah);
|
pascal@11674
|
634 }
|
pascal@11674
|
635 }
|
pascal@11674
|
636
|
pascal@11674
|
637 void do_int13(struct vm86_regs *r)
|
pascal@11674
|
638 {
|
pascal@11674
|
639 uint8_t ah;
|
pascal@11674
|
640
|
pascal@11674
|
641 ah = (r->eax >> 8);
|
pascal@11674
|
642 switch(ah) {
|
pascal@11674
|
643 case 0x00: /* reset disk */
|
pascal@11674
|
644 {
|
pascal@11674
|
645 r->eax &= ~0xff00; /* success */
|
pascal@11674
|
646 r->eflags &= ~CF_MASK;
|
pascal@11674
|
647 }
|
pascal@11674
|
648 break;
|
pascal@11674
|
649 case 0x02: /* read disk CHS */
|
pascal@11674
|
650 {
|
pascal@11674
|
651 int fd, c, h, s, heads, sectors, cylinders;
|
pascal@11674
|
652 long size;
|
pascal@11674
|
653 fd = open_disk(r);
|
pascal@11674
|
654 if (fd >= 0) {
|
pascal@11674
|
655 size = lseek(fd, 0, SEEK_END) / 512;
|
pascal@11674
|
656 if ((r->edx & 0xff) > 127) {
|
pascal@11674
|
657 sectors = 63;
|
pascal@11674
|
658 if (size % sectors)
|
pascal@11674
|
659 sectors = 62;
|
pascal@11674
|
660 if (size % sectors)
|
pascal@11674
|
661 sectors = 32;
|
pascal@11674
|
662 if (size % sectors)
|
pascal@11674
|
663 sectors = 17;
|
pascal@11674
|
664 if (size % sectors)
|
pascal@11674
|
665 fd = -1;
|
pascal@11674
|
666 size /= sectors;
|
pascal@11674
|
667 for (heads = 256; size % heads; heads--);
|
pascal@11674
|
668 cylinders = size / heads;
|
pascal@11674
|
669 }
|
pascal@11674
|
670 else {
|
pascal@11674
|
671 int i;
|
pascal@11674
|
672 heads = 1 + (size > 256*2);
|
pascal@11674
|
673 cylinders = 40 * (1 + (size > 512*2));
|
pascal@11674
|
674 size /= heads;
|
pascal@11674
|
675 for (i = 0; i < 5; i++)
|
pascal@11674
|
676 if (size % (cylinders + i) == 0) break;
|
pascal@11674
|
677 if (i == 5)
|
pascal@11674
|
678 fd = -1;
|
pascal@11674
|
679 cylinders += i;
|
pascal@11674
|
680 sectors = size / cylinders;
|
pascal@11674
|
681 }
|
pascal@11674
|
682 }
|
pascal@11674
|
683 c = ((r->ecx & 0xC0) << 2) | ((r->ecx >> 8) & 0xff);
|
pascal@11674
|
684 h = (r->edx >> 8) & 0xff;
|
pascal@11674
|
685 s = (r->ecx & 0x3f) -1;
|
pascal@11674
|
686 if (fd < 0 || c >= cylinders || h >= heads || s >= sectors) {
|
pascal@11674
|
687 set_error(r, 0x0400); /* sector not found */
|
pascal@11674
|
688 break;
|
pascal@11674
|
689 }
|
pascal@11674
|
690 read_sectors(fd, r, (((c * heads) + h) * sectors) + s,
|
pascal@11674
|
691 r->eax & 0xff, seg_to_linear(r->es, r->ebx));
|
pascal@11674
|
692 }
|
pascal@11674
|
693 break;
|
pascal@11674
|
694 case 0x42: /* read disk LBA */
|
pascal@11674
|
695 {
|
pascal@11674
|
696 uint16_t *packet = (uint16_t *) seg_to_linear(r->ds, r-> esi);
|
pascal@11674
|
697 uint8_t *to = seg_to_linear(packet[3], packet[2]);
|
pascal@11674
|
698 if ((packet[3] & packet[2]) == 0xffff)
|
pascal@11674
|
699 to = * (uint8_t **) &packet[8];
|
pascal@11674
|
700 if (packet[0] != 0x0010 && packet[0] != 0x0018)
|
pascal@11674
|
701 goto unsupported;
|
pascal@11674
|
702 read_sectors(open_disk(r), r, * (uint32_t *) &packet[4], packet[1], to);
|
pascal@11674
|
703 }
|
pascal@11674
|
704 break;
|
pascal@11674
|
705 default:
|
pascal@11674
|
706 unsupported:
|
pascal@11674
|
707 unsupported_function(r, 0x13, ah);
|
pascal@11674
|
708 }
|
pascal@11674
|
709 }
|
pascal@11674
|
710
|
pascal@11674
|
711 void do_int15(struct vm86_regs *r)
|
pascal@11674
|
712 {
|
pascal@11674
|
713 uint8_t ah;
|
pascal@11674
|
714
|
pascal@11674
|
715 ah = (r->eax >> 8);
|
pascal@11674
|
716 switch(ah) {
|
pascal@11674
|
717 case 0x87: /* move memory */
|
pascal@11674
|
718 /* XXX */
|
pascal@11674
|
719 break;
|
pascal@11674
|
720 default:
|
pascal@11674
|
721 unsupported_function(r, 0x15, ah);
|
pascal@11674
|
722 }
|
pascal@11674
|
723 }
|
pascal@11674
|
724
|
pascal@11674
|
725 void do_int16(struct vm86_regs *r)
|
pascal@11674
|
726 {
|
pascal@11674
|
727 static uint16_t last_ax, hold_char;
|
pascal@11674
|
728 struct termios termios_def, termios_raw;
|
pascal@11674
|
729 uint8_t ah;
|
pascal@11674
|
730
|
pascal@11674
|
731 ah = (r->eax >> 8);
|
pascal@11674
|
732 tcgetattr(0, &termios_def);
|
pascal@11674
|
733 termios_raw = termios_def;
|
pascal@11674
|
734 cfmakeraw(&termios_raw);
|
pascal@11674
|
735 tcsetattr(0, TCSADRAIN, &termios_raw);
|
pascal@11674
|
736 switch(ah) {
|
pascal@11674
|
737 case 0x01: /* test keyboard */
|
pascal@11674
|
738 {
|
pascal@11674
|
739 int count;
|
pascal@11674
|
740 r->eflags &= ~ZF_MASK;
|
pascal@11674
|
741 if (hold_char) {
|
pascal@11674
|
742 r->eax &= ~0xffff;
|
pascal@11674
|
743 r->eax |= last_ax;
|
pascal@11674
|
744 break;
|
pascal@11674
|
745 }
|
pascal@11674
|
746 if (ioctl(0, FIONREAD, &count) < 0 || count == 0) {
|
pascal@11674
|
747 r->eflags |= ZF_MASK;
|
pascal@11674
|
748 break;
|
pascal@11674
|
749 }
|
pascal@11674
|
750 hold_char = 2;
|
pascal@11674
|
751 }
|
pascal@11674
|
752 case 0x00: /* read keyboard */
|
pascal@11674
|
753 {
|
pascal@11674
|
754 uint8_t c;
|
pascal@11674
|
755 if (hold_char)
|
pascal@11674
|
756 hold_char--;
|
pascal@11674
|
757 read(0, &c, 1);
|
pascal@11674
|
758 if (c == 3) {
|
pascal@11674
|
759 tcsetattr(0, TCSADRAIN, &termios_def);
|
pascal@11674
|
760 exit(0);
|
pascal@11674
|
761 }
|
pascal@11674
|
762 if (c == 10)
|
pascal@11674
|
763 c = 13;
|
pascal@11674
|
764 r->eax &= ~0xffff;
|
pascal@11674
|
765 r->eax |= last_ax = c;
|
pascal@11674
|
766 /* XXX ah = scan code */
|
pascal@11674
|
767 }
|
pascal@11674
|
768 break;
|
pascal@11674
|
769 default:
|
pascal@11674
|
770 unsupported_function(r, 0x16, ah);
|
pascal@11674
|
771 }
|
pascal@11674
|
772 tcsetattr(0, TCSADRAIN, &termios_def);
|
pascal@11674
|
773 }
|
pascal@11674
|
774
|
pascal@11674
|
775 void do_int1a(struct vm86_regs *r)
|
pascal@11674
|
776 {
|
pascal@11674
|
777 uint8_t ah;
|
pascal@11674
|
778
|
pascal@11674
|
779 ah = (r->eax >> 8);
|
pascal@11674
|
780 switch(ah) {
|
pascal@11674
|
781 case 0x00: /* GET SYSTEM TIME */
|
pascal@11674
|
782 {
|
pascal@11674
|
783 uint16_t *timer = (uint16_t *) seg_to_linear(0, 0x46C);
|
pascal@11674
|
784 r->ecx &= ~0xffff;
|
pascal@11674
|
785 r->ecx |= *timer++;
|
pascal@11674
|
786 r->edx &= ~0xffff;
|
pascal@11674
|
787 r->edx |= *timer;
|
pascal@11674
|
788 r->eax &= ~0xff;
|
pascal@11674
|
789 }
|
pascal@11674
|
790 break;
|
pascal@11674
|
791 default:
|
pascal@11674
|
792 unsupported_function(r, 0x1a, ah);
|
pascal@11674
|
793 }
|
pascal@11674
|
794 }
|
pascal@11674
|
795
|
pascal@11674
|
796 void do_int20(struct vm86_regs *r)
|
pascal@11674
|
797 {
|
pascal@11674
|
798 /* terminate program */
|
pascal@11674
|
799 exit(0);
|
pascal@11674
|
800 }
|
pascal@11674
|
801
|
pascal@11674
|
802 void do_int21(struct vm86_regs *r)
|
pascal@11674
|
803 {
|
pascal@11674
|
804 uint8_t ah;
|
pascal@17124
|
805 DIR *dirp;
|
pascal@17124
|
806 dirdta *dta;
|
pascal@11674
|
807
|
pascal@11674
|
808 ah = (r->eax >> 8);
|
pascal@11674
|
809 switch(ah) {
|
pascal@11674
|
810 case 0x00: /* exit */
|
pascal@11674
|
811 exit(0);
|
pascal@11674
|
812 case 0x02: /* write char */
|
pascal@11674
|
813 {
|
pascal@11674
|
814 uint8_t c = r->edx;
|
pascal@11674
|
815 write(1, &c, 1);
|
pascal@11674
|
816 }
|
pascal@11674
|
817 break;
|
pascal@17124
|
818 case 0x08: /* read stdin */
|
pascal@17124
|
819 {
|
pascal@17124
|
820 read(0,&r->eax,1);
|
pascal@17124
|
821 }
|
pascal@17124
|
822 break;
|
pascal@11674
|
823 case 0x09: /* write string */
|
pascal@11674
|
824 {
|
pascal@11674
|
825 uint8_t c;
|
pascal@11674
|
826 int offset;
|
pascal@11674
|
827 offset = r->edx;
|
pascal@11674
|
828 for(;;) {
|
pascal@11674
|
829 c = *seg_to_linear(r->ds, offset);
|
pascal@11674
|
830 if (c == '$')
|
pascal@11674
|
831 break;
|
pascal@11674
|
832 write(1, &c, 1);
|
pascal@11674
|
833 offset++;
|
pascal@11674
|
834 }
|
pascal@11674
|
835 r->eax = (r->eax & ~0xff) | '$';
|
pascal@11674
|
836 }
|
pascal@11674
|
837 break;
|
pascal@11674
|
838 case 0x0a: /* buffered input */
|
pascal@11674
|
839 {
|
pascal@11674
|
840 int max_len, cur_len, ret;
|
pascal@11674
|
841 uint8_t ch;
|
pascal@11674
|
842 uint16_t off;
|
pascal@11674
|
843
|
pascal@11674
|
844 /* XXX: should use raw mode to avoid sending the CRLF to
|
pascal@11674
|
845 the terminal */
|
pascal@11674
|
846 off = r->edx & 0xffff;
|
pascal@11674
|
847 max_len = *seg_to_linear(r->ds, off);
|
pascal@11674
|
848 cur_len = 0;
|
pascal@11674
|
849 while (cur_len < max_len) {
|
pascal@11674
|
850 ret = read(0, &ch, 1);
|
pascal@11674
|
851 if (ret < 0) {
|
pascal@11674
|
852 if (errno != EINTR && errno != EAGAIN)
|
pascal@11674
|
853 break;
|
pascal@11674
|
854 } else if (ret == 0) {
|
pascal@11674
|
855 break;
|
pascal@11674
|
856 } else {
|
pascal@11674
|
857 if (ch == '\n')
|
pascal@11674
|
858 break;
|
pascal@11674
|
859 }
|
pascal@11674
|
860 *seg_to_linear(r->ds, off + 2 + cur_len++) = ch;
|
pascal@11674
|
861 }
|
pascal@11674
|
862 *seg_to_linear(r->ds, off + 1) = cur_len;
|
pascal@11674
|
863 *seg_to_linear(r->ds, off + 2 + cur_len) = '\r';
|
pascal@11674
|
864 }
|
pascal@11674
|
865 break;
|
pascal@17124
|
866 case 0x0b: /* get stdin status */
|
pascal@17124
|
867 {
|
pascal@17124
|
868 r->eax &= ~0xFF; /* no character available */
|
pascal@17124
|
869 }
|
pascal@17124
|
870 break;
|
pascal@17124
|
871 case 0x0d: /* disk reset */
|
pascal@17124
|
872 {
|
pascal@17124
|
873 sync();
|
pascal@17124
|
874 }
|
pascal@17124
|
875 break;
|
pascal@17124
|
876 case 0x0e: /* select default disk */
|
pascal@17124
|
877 {
|
pascal@17124
|
878 r->eax &= ~0xFF;
|
pascal@17124
|
879 r->eax |= 3; /* A: B: & C: valid */
|
pascal@17124
|
880 }
|
pascal@17124
|
881 break;
|
pascal@17124
|
882 case 0x19: /* get current default drive */
|
pascal@17124
|
883 {
|
pascal@17124
|
884 r->eax &= ~0xFF;
|
pascal@17124
|
885 r->eax |= 2; /* C: */
|
pascal@17124
|
886 }
|
pascal@17124
|
887 break;
|
pascal@17124
|
888 case 0x1a: /* set DTA (disk transfert address) */
|
pascal@17124
|
889 {
|
pascal@17124
|
890 cur_dta_seg = r->ds;
|
pascal@17124
|
891 cur_dta_ofs = r->edx;
|
pascal@17124
|
892 }
|
pascal@17124
|
893 break;
|
pascal@11674
|
894 case 0x25: /* set interrupt vector */
|
pascal@11674
|
895 {
|
pascal@11674
|
896 uint16_t *ptr;
|
pascal@11674
|
897 ptr = (uint16_t *)seg_to_linear(0, (r->eax & 0xff) * 4);
|
pascal@11674
|
898 ptr[0] = r->edx;
|
pascal@11674
|
899 ptr[1] = r->ds;
|
pascal@11674
|
900 }
|
pascal@11674
|
901 break;
|
pascal@11674
|
902 case 0x29: /* parse filename into FCB */
|
pascal@11674
|
903 #if 0
|
pascal@11674
|
904 /* not really needed */
|
pascal@11674
|
905 {
|
pascal@11674
|
906 const uint8_t *p, *p_start;
|
pascal@11674
|
907 uint8_t file[8], ext[3];
|
pascal@11674
|
908 FCB *fcb;
|
pascal@11674
|
909 int file_len, ext_len, has_wildchars, c, drive_num;
|
pascal@11674
|
910
|
pascal@11674
|
911 /* XXX: not complete at all */
|
pascal@11674
|
912 fcb = (FCB *)seg_to_linear(r->es, r->edi);
|
pascal@11674
|
913 printf("ds=0x%x si=0x%lx\n", r->ds, r->esi);
|
pascal@11674
|
914 p_start = (const uint8_t *)seg_to_linear(r->ds, r->esi);
|
pascal@11674
|
915
|
pascal@11674
|
916 p = p_start;
|
pascal@11674
|
917 has_wildchars = 0;
|
pascal@11674
|
918
|
pascal@11674
|
919 /* drive */
|
pascal@11674
|
920 if (isalpha(p[0]) && p[1] == ':') {
|
pascal@11674
|
921 drive_num = toupper(p[0]) - 'A' + 1;
|
pascal@11674
|
922 p += 2;
|
pascal@11674
|
923 } else {
|
pascal@11674
|
924 drive_num = 0;
|
pascal@11674
|
925 }
|
pascal@11674
|
926
|
pascal@11674
|
927 /* filename */
|
pascal@11674
|
928 file_len = 0;
|
pascal@11674
|
929 for(;;) {
|
pascal@11674
|
930 c = *p;
|
pascal@11674
|
931 if (!(c >= 33 && c <= 126))
|
pascal@11674
|
932 break;
|
pascal@11674
|
933 if (c == '.')
|
pascal@11674
|
934 break;
|
pascal@11674
|
935 if (c == '*' || c == '?')
|
pascal@11674
|
936 has_wildchars = 1;
|
pascal@11674
|
937 if (file_len < 8)
|
pascal@11674
|
938 file[file_len++] = c;
|
pascal@11674
|
939 }
|
pascal@11674
|
940 memset(file + file_len, ' ', 8 - file_len);
|
pascal@11674
|
941
|
pascal@11674
|
942 /* extension */
|
pascal@11674
|
943 ext_len = 0;
|
pascal@11674
|
944 if (*p == '.') {
|
pascal@11674
|
945 for(;;) {
|
pascal@11674
|
946 c = *p;
|
pascal@11674
|
947 if (!(c >= 33 && c <= 126))
|
pascal@11674
|
948 break;
|
pascal@11674
|
949 if (c == '*' || c == '?')
|
pascal@11674
|
950 has_wildchars = 1;
|
pascal@11674
|
951 ext[ext_len++] = c;
|
pascal@11674
|
952 if (ext_len >= 3)
|
pascal@11674
|
953 break;
|
pascal@11674
|
954 }
|
pascal@11674
|
955 }
|
pascal@11674
|
956 memset(ext + ext_len, ' ', 3 - ext_len);
|
pascal@11674
|
957
|
pascal@11674
|
958 #if 0
|
pascal@11674
|
959 {
|
pascal@11674
|
960 printf("drive=%d file=%8s ext=%3s\n",
|
pascal@11674
|
961 drive_num, file, ext);
|
pascal@11674
|
962 }
|
pascal@11674
|
963 #endif
|
pascal@11674
|
964 if (drive_num == 0 && r->eax & (1 << 1)) {
|
pascal@11674
|
965 /* keep drive */
|
pascal@11674
|
966 } else {
|
pascal@11674
|
967 fcb->drive_num = drive_num; /* default drive */
|
pascal@11674
|
968 }
|
pascal@11674
|
969
|
pascal@11674
|
970 if (file_len == 0 && r->eax & (1 << 2)) {
|
pascal@11674
|
971 /* keep */
|
pascal@11674
|
972 } else {
|
pascal@11674
|
973 memcpy(fcb->file_name, file, 8);
|
pascal@11674
|
974 }
|
pascal@11674
|
975
|
pascal@11674
|
976 if (ext_len == 0 && r->eax & (1 << 3)) {
|
pascal@11674
|
977 /* keep */
|
pascal@11674
|
978 } else {
|
pascal@11674
|
979 memcpy(fcb->file_ext, ext, 3);
|
pascal@11674
|
980 }
|
pascal@11674
|
981 r->eax = (r->eax & ~0xff) | has_wildchars;
|
pascal@11674
|
982 r->esi = (r->esi & ~0xffff) | ((r->esi + (p - p_start)) & 0xffff);
|
pascal@11674
|
983 }
|
pascal@11674
|
984 #endif
|
pascal@11674
|
985 break;
|
pascal@11674
|
986 case 0x2A: /* get system date */
|
pascal@11674
|
987 {
|
pascal@11674
|
988 time_t t = time(NULL);
|
pascal@11674
|
989 struct tm *now=localtime(&t);
|
pascal@11674
|
990
|
pascal@11674
|
991 r->ecx = now->tm_year;
|
pascal@11674
|
992 r->edx = (now->tm_mon * 256) + now->tm_mday;
|
pascal@11674
|
993 r->eax = now->tm_wday;;
|
pascal@11674
|
994 }
|
pascal@11674
|
995 break;
|
pascal@11674
|
996 case 0x2C: /* get system time */
|
pascal@11674
|
997 {
|
pascal@11674
|
998 time_t t = time(NULL);
|
pascal@11674
|
999 struct tm *now=localtime(&t);
|
pascal@11674
|
1000 struct timeval tim;
|
pascal@11674
|
1001
|
pascal@11674
|
1002 gettimeofday(&tim, NULL);
|
pascal@11674
|
1003 r->edx = (now->tm_hour * 256) + now->tm_min;
|
pascal@11674
|
1004 r->edx = (tim.tv_sec * 256) + tim.tv_usec/10000;
|
pascal@11674
|
1005 }
|
pascal@11674
|
1006 break;
|
pascal@17124
|
1007 case 0x2f: /* get DTA (disk transfert address */
|
pascal@17124
|
1008 {
|
pascal@17124
|
1009 r->es = cur_dta_seg;
|
pascal@17124
|
1010 r->ebx = cur_dta_ofs;
|
pascal@17124
|
1011 }
|
pascal@17124
|
1012 break;
|
pascal@11674
|
1013 case 0x30: /* get dos version */
|
pascal@11674
|
1014 {
|
pascal@11674
|
1015 int major, minor, serial, oem;
|
pascal@11674
|
1016 /* XXX: return correct value for FreeDOS */
|
pascal@11674
|
1017 major = 0x03;
|
pascal@11674
|
1018 minor = 0x31;
|
pascal@11674
|
1019 serial = 0x123456;
|
pascal@11674
|
1020 oem = 0x66;
|
pascal@11674
|
1021 r->eax = (r->eax & ~0xffff) | major | (minor << 8);
|
pascal@11674
|
1022 r->ecx = (r->ecx & ~0xffff) | (serial & 0xffff);
|
pascal@11674
|
1023 r->ebx = (r->ebx & ~0xffff) | (serial & 0xff) | (0x66 << 8);
|
pascal@11674
|
1024 }
|
pascal@11674
|
1025 break;
|
pascal@17124
|
1026 case 0x33: /* extended break checking */
|
pascal@17124
|
1027 {
|
pascal@17124
|
1028 r->edx &= ~0xFFFF;
|
pascal@17124
|
1029 }
|
pascal@17124
|
1030 break;
|
pascal@11674
|
1031 case 0x35: /* get interrupt vector */
|
pascal@11674
|
1032 {
|
pascal@11674
|
1033 uint16_t *ptr;
|
pascal@11674
|
1034 ptr = (uint16_t *)seg_to_linear(0, (r->eax & 0xff) * 4);
|
pascal@11674
|
1035 r->ebx = (r->ebx & ~0xffff) | ptr[0];
|
pascal@11674
|
1036 r->es = ptr[1];
|
pascal@11674
|
1037 }
|
pascal@11674
|
1038 break;
|
pascal@17124
|
1039 case 0x36: /* get free disk space */
|
pascal@17124
|
1040 {
|
pascal@17124
|
1041 struct statfs buf;
|
pascal@17124
|
1042
|
pascal@17124
|
1043 if (statfs(".", &buf)) {
|
pascal@17124
|
1044 r->eax |= 0xFFFF;
|
pascal@17124
|
1045 }
|
pascal@17124
|
1046 else {
|
pascal@17124
|
1047 r->eax &= ~0xFFFF;
|
pascal@17124
|
1048 r->eax |= buf.f_bsize / 512; /* sectors per cluster */
|
pascal@17124
|
1049 r->ebx &= ~0xFFFF;
|
pascal@17124
|
1050 r->ebx |= buf.f_bavail;
|
pascal@17124
|
1051 r->ecx &= ~0xFFFF;
|
pascal@17124
|
1052 r->ecx |= 512; /* bytes per sector */
|
pascal@17124
|
1053 r->edx &= ~0xFFFF;
|
pascal@17124
|
1054 r->edx |= buf.f_blocks;
|
pascal@17124
|
1055 }
|
pascal@17124
|
1056 }
|
pascal@17124
|
1057 break;
|
pascal@11674
|
1058 case 0x37:
|
pascal@11674
|
1059 {
|
pascal@11674
|
1060 switch(r->eax & 0xff) {
|
pascal@11674
|
1061 case 0x00: /* get switch char */
|
pascal@11674
|
1062 r->eax = (r->eax & ~0xff) | 0x00;
|
pascal@11674
|
1063 r->edx = (r->edx & ~0xff) | '/';
|
pascal@11674
|
1064 break;
|
pascal@11674
|
1065 default:
|
pascal@11674
|
1066 goto unsupported;
|
pascal@11674
|
1067 }
|
pascal@11674
|
1068 }
|
pascal@11674
|
1069 break;
|
pascal@17124
|
1070 case 0x3B:
|
pascal@17124
|
1071 {
|
pascal@17124
|
1072 char filename[1024];
|
pascal@17124
|
1073
|
pascal@17124
|
1074 get_filename(r, filename, sizeof(filename));
|
pascal@17124
|
1075 if (chdir(filename))
|
pascal@17124
|
1076 set_error(r, 0x03); /* path not found */
|
pascal@17124
|
1077 }
|
pascal@17124
|
1078 break;
|
pascal@11674
|
1079 case 0x3c: /* create or truncate file */
|
pascal@11674
|
1080 {
|
pascal@11674
|
1081 char filename[1024];
|
pascal@11674
|
1082 int fd, h, flags;
|
pascal@11674
|
1083
|
pascal@11674
|
1084 h = get_new_handle();
|
pascal@11674
|
1085 if (h < 0) {
|
pascal@11674
|
1086 set_error(r, 0x04); /* too many open files */
|
pascal@11674
|
1087 } else {
|
pascal@11674
|
1088 get_filename(r, filename, sizeof(filename));
|
pascal@11674
|
1089 if (r->ecx & 1)
|
pascal@11674
|
1090 flags = 0444; /* read-only */
|
pascal@11674
|
1091 else
|
pascal@11674
|
1092 flags = 0777;
|
pascal@11674
|
1093 fd = open(filename, O_RDWR | O_TRUNC | O_CREAT, flags);
|
pascal@17124
|
1094 if (fd < 0)
|
pascal@17124
|
1095 fd = open(upcase(filename), O_RDWR | O_TRUNC | O_CREAT, flags);
|
pascal@11674
|
1096 #ifdef DUMP_INT21
|
pascal@11674
|
1097 printf("int21: create: file='%s' cx=0x%04x ret=%d\n",
|
pascal@11674
|
1098 filename, (int)(r->ecx & 0xffff), h);
|
pascal@11674
|
1099 #endif
|
pascal@11674
|
1100 if (fd < 0) {
|
pascal@11674
|
1101 set_error(r, 0x03); /* path not found */
|
pascal@11674
|
1102 } else {
|
pascal@11674
|
1103 dos_files[h].fd = fd;
|
pascal@11674
|
1104 set_error(r, 0);
|
pascal@11674
|
1105 r->eax = (r->eax & ~0xffff) | h;
|
pascal@11674
|
1106 }
|
pascal@11674
|
1107 }
|
pascal@11674
|
1108 }
|
pascal@11674
|
1109 break;
|
pascal@11674
|
1110 case 0x3d: /* open file */
|
pascal@11674
|
1111 {
|
pascal@11674
|
1112 char filename[1024];
|
pascal@11674
|
1113 int fd, h;
|
pascal@11674
|
1114
|
pascal@11674
|
1115 h = get_new_handle();
|
pascal@11674
|
1116 if (h < 0) {
|
pascal@11674
|
1117 set_error(r, 0x04); /* too many open files */
|
pascal@11674
|
1118 } else {
|
pascal@11674
|
1119 get_filename(r, filename, sizeof(filename));
|
pascal@11674
|
1120 fd = open(filename, r->eax & 3);
|
pascal@17124
|
1121 if (fd < 1)
|
pascal@17124
|
1122 fd = open(upcase(filename), r->eax & 3);
|
pascal@11674
|
1123 if (fd < 0) {
|
pascal@11674
|
1124 set_error(r, 0x02); /* file not found */
|
pascal@11674
|
1125 } else {
|
pascal@11674
|
1126 dos_files[h].fd = fd;
|
pascal@11674
|
1127 set_error(r, 0);
|
pascal@11674
|
1128 r->eax = (r->eax & ~0xffff) | h;
|
pascal@11674
|
1129 }
|
pascal@11674
|
1130 }
|
pascal@11674
|
1131 }
|
pascal@11674
|
1132 break;
|
pascal@11674
|
1133 case 0x3e: /* close file */
|
pascal@11674
|
1134 {
|
pascal@11674
|
1135 DOSFile *fh = get_file(r->ebx & 0xffff);
|
pascal@11674
|
1136 #ifdef DUMP_INT21
|
pascal@11674
|
1137 printf("int21: close fd=%d\n", (int)(r->ebx & 0xffff));
|
pascal@11674
|
1138 #endif
|
pascal@11674
|
1139 if (!fh) {
|
pascal@11674
|
1140 set_error(r, 0x06); /* invalid handle */
|
pascal@11674
|
1141 } else {
|
pascal@11674
|
1142 close(fh->fd);
|
pascal@11674
|
1143 fh->fd = -1;
|
pascal@11674
|
1144 set_error(r, 0);
|
pascal@11674
|
1145 }
|
pascal@11674
|
1146 }
|
pascal@11674
|
1147 break;
|
pascal@11674
|
1148 case 0x3f: /* read */
|
pascal@11674
|
1149 {
|
pascal@11674
|
1150 DOSFile *fh = get_file(r->ebx & 0xffff);
|
pascal@11674
|
1151 int n, ret;
|
pascal@11674
|
1152
|
pascal@11674
|
1153 if (!fh) {
|
pascal@11674
|
1154 set_error(r, 0x06); /* invalid handle */
|
pascal@11674
|
1155 } else {
|
pascal@11674
|
1156 n = r->ecx & 0xffff;
|
pascal@11674
|
1157 for(;;) {
|
pascal@11674
|
1158 ret = read(fh->fd,
|
pascal@11674
|
1159 seg_to_linear(r->ds, r->edx), n);
|
pascal@11674
|
1160 if (ret < 0) {
|
pascal@11674
|
1161 if (errno != EINTR && errno != EAGAIN)
|
pascal@11674
|
1162 break;
|
pascal@11674
|
1163 } else {
|
pascal@11674
|
1164 break;
|
pascal@11674
|
1165 }
|
pascal@11674
|
1166 }
|
pascal@11674
|
1167 #ifdef DUMP_INT21
|
pascal@11674
|
1168 printf("int21: read: fd=%d n=%d ret=%d\n",
|
pascal@11674
|
1169 (int)(r->ebx & 0xffff), n, ret);
|
pascal@11674
|
1170 #endif
|
pascal@11674
|
1171 if (ret < 0) {
|
pascal@11674
|
1172 set_error(r, 0x05); /* acces denied */
|
pascal@11674
|
1173 } else {
|
pascal@11674
|
1174 r->eax = (r->eax & ~0xffff) | ret;
|
pascal@11674
|
1175 set_error(r, 0);
|
pascal@11674
|
1176 }
|
pascal@11674
|
1177 }
|
pascal@11674
|
1178 }
|
pascal@11674
|
1179 break;
|
pascal@11674
|
1180 case 0x40: /* write */
|
pascal@11674
|
1181 {
|
pascal@11674
|
1182 DOSFile *fh = get_file(r->ebx & 0xffff);
|
pascal@11674
|
1183 int n, ret, pos;
|
pascal@11674
|
1184
|
pascal@11674
|
1185 if (!fh) {
|
pascal@11674
|
1186 set_error(r, 0x06); /* invalid handle */
|
pascal@11674
|
1187 } else {
|
pascal@11674
|
1188 n = r->ecx & 0xffff;
|
pascal@11674
|
1189 if (n == 0) {
|
pascal@11674
|
1190 /* truncate */
|
pascal@11674
|
1191 pos = lseek(fh->fd, 0, SEEK_CUR);
|
pascal@11674
|
1192 if (pos >= 0) {
|
pascal@11674
|
1193 ret = ftruncate(fh->fd, pos);
|
pascal@11674
|
1194 } else {
|
pascal@11674
|
1195 ret = -1;
|
pascal@11674
|
1196 }
|
pascal@11674
|
1197 } else {
|
pascal@11674
|
1198 for(;;) {
|
pascal@11674
|
1199 ret = write(fh->fd,
|
pascal@11674
|
1200 seg_to_linear(r->ds, r->edx), n);
|
pascal@11674
|
1201 if (ret < 0) {
|
pascal@11674
|
1202 if (errno != EINTR && errno != EAGAIN)
|
pascal@11674
|
1203 break;
|
pascal@11674
|
1204 } else {
|
pascal@11674
|
1205 break;
|
pascal@11674
|
1206 }
|
pascal@11674
|
1207 }
|
pascal@11674
|
1208 }
|
pascal@11674
|
1209 #ifdef DUMP_INT21
|
pascal@11674
|
1210 printf("int21: write: fd=%d n=%d ret=%d\n",
|
pascal@11674
|
1211 (int)(r->ebx & 0xffff), n, ret);
|
pascal@11674
|
1212 #endif
|
pascal@11674
|
1213 if (ret < 0) {
|
pascal@11674
|
1214 set_error(r, 0x05); /* acces denied */
|
pascal@11674
|
1215 } else {
|
pascal@11674
|
1216 r->eax = (r->eax & ~0xffff) | ret;
|
pascal@11674
|
1217 set_error(r, 0);
|
pascal@11674
|
1218 }
|
pascal@11674
|
1219 }
|
pascal@11674
|
1220 }
|
pascal@11674
|
1221 break;
|
pascal@11674
|
1222 case 0x41: /* unlink */
|
pascal@11674
|
1223 {
|
pascal@11674
|
1224 char filename[1024];
|
pascal@11674
|
1225 get_filename(r, filename, sizeof(filename));
|
pascal@17124
|
1226 if (unlink(filename) < 0 && unlink(upcase(filename))) {
|
pascal@11674
|
1227 set_error(r, 0x02); /* file not found */
|
pascal@11674
|
1228 } else {
|
pascal@11674
|
1229 set_error(r, 0);
|
pascal@11674
|
1230 }
|
pascal@11674
|
1231 }
|
pascal@11674
|
1232 break;
|
pascal@11674
|
1233 case 0x42: /* lseek */
|
pascal@11674
|
1234 {
|
pascal@11674
|
1235 DOSFile *fh = get_file(r->ebx & 0xffff);
|
pascal@11674
|
1236 int pos, ret;
|
pascal@11674
|
1237
|
pascal@11674
|
1238 if (!fh) {
|
pascal@11674
|
1239 set_error(r, 0x06); /* invalid handle */
|
pascal@11674
|
1240 } else {
|
pascal@11674
|
1241 pos = ((r->ecx & 0xffff) << 16) | (r->edx & 0xffff);
|
pascal@11674
|
1242 ret = lseek(fh->fd, pos, r->eax & 0xff);
|
pascal@11674
|
1243 #ifdef DUMP_INT21
|
pascal@11674
|
1244 printf("int21: lseek: fd=%d pos=%d whence=%d ret=%d\n",
|
pascal@11674
|
1245 (int)(r->ebx & 0xffff), pos, (uint8_t)r->eax, ret);
|
pascal@11674
|
1246 #endif
|
pascal@11674
|
1247 if (ret < 0) {
|
pascal@11674
|
1248 set_error(r, 0x01); /* function number invalid */
|
pascal@11674
|
1249 } else {
|
pascal@11674
|
1250 r->edx = (r->edx & ~0xffff) | ((unsigned)ret >> 16);
|
pascal@11674
|
1251 r->eax = (r->eax & ~0xffff) | (ret & 0xffff);
|
pascal@11674
|
1252 set_error(r, 0);
|
pascal@11674
|
1253 }
|
pascal@11674
|
1254 }
|
pascal@11674
|
1255 }
|
pascal@11674
|
1256 break;
|
pascal@17124
|
1257 case 0x43: /* get attribute */
|
pascal@17124
|
1258 {
|
pascal@17124
|
1259 struct stat statbuf;
|
pascal@17124
|
1260 char filename[1024];
|
pascal@17124
|
1261 get_filename(r, filename, sizeof(filename));
|
pascal@17124
|
1262 if (stat(filename, &statbuf) && stat(upcase(filename), &statbuf)) {
|
pascal@17124
|
1263 set_error(r, 5);
|
pascal@17124
|
1264 }
|
pascal@17124
|
1265 else {
|
pascal@17124
|
1266 r->ecx &= ~0xFFFF;
|
pascal@17124
|
1267 if (S_ISDIR(statbuf.st_mode)) r->ecx |= 0x10;
|
pascal@17124
|
1268 }
|
pascal@17124
|
1269 }
|
pascal@17124
|
1270 break;
|
pascal@11674
|
1271 case 0x44: /* ioctl */
|
pascal@11674
|
1272 switch(r->eax & 0xff) {
|
pascal@11674
|
1273 case 0x00: /* get device information */
|
pascal@11674
|
1274 {
|
pascal@11674
|
1275 DOSFile *fh = get_file(r->ebx & 0xffff);
|
pascal@11674
|
1276 int ret;
|
pascal@11674
|
1277
|
pascal@11674
|
1278 if (!fh) {
|
pascal@11674
|
1279 set_error(r, 0x06); /* invalid handle */
|
pascal@11674
|
1280 } else {
|
pascal@11674
|
1281 ret = 0;
|
pascal@11674
|
1282 if (isatty(fh->fd)) {
|
pascal@11674
|
1283 ret |= 0x80;
|
pascal@11674
|
1284 if (fh->fd == 0)
|
pascal@11674
|
1285 ret |= (1 << 0);
|
pascal@11674
|
1286 else
|
pascal@11674
|
1287 ret |= (1 << 1);
|
pascal@11674
|
1288 }
|
pascal@11674
|
1289 r->edx = (r->edx & ~0xffff) | ret;
|
pascal@11674
|
1290 set_error(r, 0);
|
pascal@11674
|
1291 }
|
pascal@11674
|
1292 }
|
pascal@17124
|
1293 case 0x01: /* set device information */
|
pascal@11674
|
1294 break;
|
pascal@11674
|
1295 default:
|
pascal@11674
|
1296 goto unsupported;
|
pascal@11674
|
1297 }
|
pascal@11674
|
1298 break;
|
pascal@17124
|
1299 case 0x47: /* get current directory (DL drive)*/
|
pascal@17124
|
1300 {
|
pascal@17124
|
1301 char *s = seg_to_linear(r->ds, r->esi);
|
pascal@17124
|
1302 getcwd(s,64);
|
pascal@17124
|
1303 strcpy(s,s+1);
|
pascal@17124
|
1304 while (*s)
|
pascal@17124
|
1305 if (*s++ == '/')
|
pascal@17124
|
1306 s[-1] = '\\';
|
pascal@17124
|
1307 r->eax = 0x100;
|
pascal@17124
|
1308 }
|
pascal@17124
|
1309 break;
|
pascal@11674
|
1310 case 0x48: /* allocate memory */
|
pascal@11674
|
1311 {
|
pascal@11674
|
1312 int ret, max_size;
|
pascal@11674
|
1313 #ifdef DUMP_INT21
|
pascal@11674
|
1314 printf("int21: allocate memory: size=0x%04x\n", (uint16_t)r->ebx);
|
pascal@11674
|
1315 #endif
|
pascal@11674
|
1316 ret = mem_malloc(r->ebx & 0xffff, &max_size);
|
pascal@11674
|
1317 if (ret < 0) {
|
pascal@11674
|
1318 set_error(r, 0x08); /* insufficient memory*/
|
pascal@11674
|
1319 } else {
|
pascal@11674
|
1320 r->eax = (r->eax & ~0xffff) | ret;
|
pascal@11674
|
1321 r->ebx = (r->ebx & ~0xffff) | max_size;
|
pascal@11674
|
1322 set_error(r, 0);
|
pascal@11674
|
1323 }
|
pascal@11674
|
1324 }
|
pascal@11674
|
1325 break;
|
pascal@11674
|
1326 case 0x49: /* free memory */
|
pascal@11674
|
1327 {
|
pascal@11674
|
1328 #ifdef DUMP_INT21
|
pascal@11674
|
1329 printf("int21: free memory: block=0x%04x\n", r->es);
|
pascal@11674
|
1330 #endif
|
pascal@11674
|
1331 if (mem_free(r->es) < 0) {
|
pascal@11674
|
1332 set_error(r, 0x09); /* memory block address invalid */
|
pascal@11674
|
1333 } else {
|
pascal@11674
|
1334 set_error(r, 0);
|
pascal@11674
|
1335 }
|
pascal@11674
|
1336 }
|
pascal@11674
|
1337 break;
|
pascal@11674
|
1338 case 0x4a: /* resize memory block */
|
pascal@11674
|
1339 {
|
pascal@11674
|
1340 int ret;
|
pascal@11674
|
1341 #ifdef DUMP_INT21
|
pascal@11674
|
1342 printf("int21: resize memory block: block=0x%04x size=0x%04x\n",
|
pascal@11674
|
1343 r->es, (uint16_t)r->ebx);
|
pascal@11674
|
1344 #endif
|
pascal@11674
|
1345 ret = mem_resize(r->es, r->ebx & 0xffff);
|
pascal@11674
|
1346 if (ret < 0) {
|
pascal@11674
|
1347 set_error(r, 0x08); /* insufficient memory*/
|
pascal@11674
|
1348 } else {
|
pascal@11674
|
1349 r->ebx = (r->ebx & ~0xffff) | ret;
|
pascal@11674
|
1350 set_error(r, 0);
|
pascal@11674
|
1351 }
|
pascal@11674
|
1352 }
|
pascal@11674
|
1353 break;
|
pascal@11674
|
1354 case 0x4b: /* load program */
|
pascal@11674
|
1355 {
|
pascal@11674
|
1356 char filename[1024];
|
pascal@11674
|
1357 ExecParamBlock *blk;
|
pascal@11674
|
1358 int ret;
|
pascal@11674
|
1359
|
pascal@11674
|
1360 if ((r->eax & 0xff) != 0x01) /* only load */
|
pascal@11674
|
1361 goto unsupported;
|
pascal@11674
|
1362 get_filename(r, filename, sizeof(filename));
|
pascal@11674
|
1363 blk = (ExecParamBlock *)seg_to_linear(r->es, r->ebx);
|
pascal@11674
|
1364 ret = load_com(blk, filename, NULL, 0, NULL);
|
pascal@17124
|
1365 if (ret < 0)
|
pascal@17124
|
1366 ret = load_com(blk, upcase(filename), NULL, 0, NULL);
|
pascal@11674
|
1367 if (ret < 0) {
|
pascal@11674
|
1368 set_error(r, 0x02); /* file not found */
|
pascal@11674
|
1369 } else {
|
pascal@17124
|
1370 cur_dta_seg = cur_psp = ret;
|
pascal@17124
|
1371 cur_dta_ofs = 0x80;
|
pascal@11674
|
1372 set_error(r, 0);
|
pascal@11674
|
1373 }
|
pascal@11674
|
1374 }
|
pascal@11674
|
1375 break;
|
pascal@11674
|
1376 case 0x4c: /* exit with return code */
|
pascal@11674
|
1377 exit(r->eax & 0xff);
|
pascal@11674
|
1378 break;
|
pascal@17124
|
1379 case 0x4e: /* find first matching file */
|
pascal@17124
|
1380 // TODO AL input support
|
pascal@17124
|
1381 dirp = opendir(".");
|
pascal@17124
|
1382 if (dirp == NULL) {
|
pascal@17124
|
1383 set_error(r, (errno == ENOTDIR) ? 0x03 /* path not found */
|
pascal@17124
|
1384 : 0x02 /* file not found */ );
|
pascal@17124
|
1385 goto pattern_found;
|
pascal@17124
|
1386 }
|
pascal@17124
|
1387 else {
|
pascal@17124
|
1388 struct dirent *dp;
|
pascal@17124
|
1389 char *s;
|
pascal@17124
|
1390
|
pascal@17124
|
1391 dta = (dirdta *) seg_to_linear(cur_dta_seg, cur_dta_ofs);
|
pascal@17124
|
1392 dta->attr = r->ecx;
|
pascal@17124
|
1393 * (DIR **) &dta->entry_count = dirp;
|
pascal@17124
|
1394 s = seg_to_linear(r->ds, r->edx);
|
pascal@17124
|
1395 if (s[1] == ':') s+= 2;
|
pascal@17124
|
1396 if (s[0] == '\\') s++;
|
pascal@17124
|
1397 strncpy(dta->template, s, 11);
|
pascal@17124
|
1398 // NO break;
|
pascal@17124
|
1399 case 0x4f: /* find next matching file */
|
pascal@17124
|
1400 dta = (dirdta *) seg_to_linear(cur_dta_seg, cur_dta_ofs);
|
pascal@17124
|
1401 dirp = * (DIR **) &dta->entry_count;
|
pascal@17124
|
1402 while ((dp = readdir(dirp)) != NULL) {
|
pascal@17124
|
1403 if (!fnmatch(dta->template, dp->d_name, 0)) {
|
pascal@17124
|
1404 struct stat statbuf;
|
pascal@17124
|
1405
|
pascal@17124
|
1406 r->eflags &= ~CF_MASK;
|
pascal@17124
|
1407 strncpy(dta->filename, dp->d_name, 13);
|
pascal@17124
|
1408 stat(dp->d_name, &statbuf);
|
pascal@17124
|
1409 dta->file_size = statbuf.st_size;
|
pascal@17124
|
1410 dta->file_date = 0; //DOSDATE(statbuf.st_mtime);
|
pascal@17124
|
1411 dta->file_time = 0; //DOSIME(statbuf.st_mtime);
|
pascal@17124
|
1412 dta->attr_found = S_ISDIR(statbuf.st_mode) ?
|
pascal@17124
|
1413 0x10 /*aDvshr*/ : 0x20 /*Advshr*/;
|
pascal@17124
|
1414 #if 0
|
pascal@17124
|
1415 if ((dta->attr_found ^ dta->attr) & 0x16)
|
pascal@17124
|
1416 continue;
|
pascal@17124
|
1417 #endif
|
pascal@17124
|
1418 goto pattern_found;
|
pascal@17124
|
1419 }
|
pascal@17124
|
1420 }
|
pascal@17124
|
1421 }
|
pascal@17124
|
1422 closedir(dirp);
|
pascal@17124
|
1423 set_error(r, 0x12 /* no more files */);
|
pascal@17124
|
1424 pattern_found:
|
pascal@17124
|
1425 break;
|
pascal@11674
|
1426 case 0x50: /* set PSP address */
|
pascal@11674
|
1427 #ifdef DUMP_INT21
|
pascal@11674
|
1428 printf("int21: set PSP: 0x%04x\n", (uint16_t)r->ebx);
|
pascal@11674
|
1429 #endif
|
pascal@11674
|
1430 cur_psp = r->ebx;
|
pascal@11674
|
1431 break;
|
pascal@11674
|
1432 case 0x51: /* get PSP address */
|
pascal@11674
|
1433 #ifdef DUMP_INT21
|
pascal@11674
|
1434 printf("int21: get PSP: ret=0x%04x\n", cur_psp);
|
pascal@11674
|
1435 #endif
|
pascal@11674
|
1436 r->ebx = (r->ebx & ~0xffff) | cur_psp;
|
pascal@11674
|
1437 break;
|
pascal@11674
|
1438 case 0x55: /* create child PSP */
|
pascal@11674
|
1439 {
|
pascal@11674
|
1440 uint8_t *psp_ptr;
|
pascal@11674
|
1441 #ifdef DUMP_INT21
|
pascal@11674
|
1442 printf("int21: create child PSP: psp=0x%04x last_seg=0x%04x\n",
|
pascal@11674
|
1443 (uint16_t)r->edx, (uint16_t)r->esi);
|
pascal@11674
|
1444 #endif
|
pascal@11674
|
1445 psp_ptr = seg_to_linear(r->edx & 0xffff, 0);
|
pascal@11674
|
1446 memset(psp_ptr, 0, 0x80);
|
pascal@11674
|
1447 psp_ptr[0] = 0xcd; /* int $0x20 */
|
pascal@11674
|
1448 psp_ptr[1] = 0x20;
|
pascal@11674
|
1449 *(uint16_t *)(psp_ptr + 2) = r->esi;
|
pascal@11674
|
1450 r->eax = (r->eax & ~0xff);
|
pascal@11674
|
1451 }
|
pascal@11674
|
1452 break;
|
pascal@17124
|
1453 case 0x56: /* rename file (CL attribute mask) */
|
pascal@17124
|
1454 if (rename((char *) seg_to_linear(r->ds, r->edx),
|
pascal@17124
|
1455 (char *) seg_to_linear(r->es, r->edi)))
|
pascal@17124
|
1456 set_error(r, 0x5 /* access denied or 2,3,0x11 */);
|
pascal@17124
|
1457 break;
|
pascal@11674
|
1458 default:
|
pascal@11674
|
1459 unsupported:
|
pascal@11674
|
1460 unsupported_function(r, 0x21, ah);
|
pascal@11674
|
1461 }
|
pascal@11674
|
1462 }
|
pascal@11674
|
1463
|
pascal@11674
|
1464 void do_int29(struct vm86_regs *r)
|
pascal@11674
|
1465 {
|
pascal@11674
|
1466 uint8_t c = r->eax;
|
pascal@11674
|
1467 write(1, &c, 1);
|
pascal@11674
|
1468 }
|
pascal@11674
|
1469
|
pascal@17124
|
1470 static int int8pending;
|
pascal@17124
|
1471
|
pascal@11674
|
1472 void raise_interrupt(int number)
|
pascal@11674
|
1473 {
|
pascal@11674
|
1474 if (* (uint32_t *) seg_to_linear(0, number * 4) == 0)
|
pascal@11674
|
1475 return;
|
pascal@17124
|
1476 int8pending++;
|
pascal@11674
|
1477 }
|
pascal@11674
|
1478
|
pascal@11674
|
1479 void biosclock()
|
pascal@11674
|
1480 {
|
pascal@17124
|
1481 //uint32_t *timer = (uint32_t *) seg_to_linear(0, 0x46C);
|
pascal@17124
|
1482 //++*timer;
|
pascal@11674
|
1483 raise_interrupt(8);
|
pascal@17124
|
1484 //raise_interrupt(0x1C);
|
pascal@17124
|
1485 }
|
pascal@17124
|
1486
|
pascal@17124
|
1487 static void exec_int(struct vm86_regs *r, unsigned num)
|
pascal@17124
|
1488 {
|
pascal@17124
|
1489 uint16_t *int_vector;
|
pascal@17124
|
1490 uint32_t eflags;
|
pascal@17124
|
1491
|
pascal@17124
|
1492 eflags = r->eflags & ~IF_MASK;
|
pascal@17124
|
1493 if (r->eflags & VIF_MASK)
|
pascal@17124
|
1494 eflags |= IF_MASK;
|
pascal@17124
|
1495 pushw(r, eflags);
|
pascal@17124
|
1496 pushw(r, r->cs);
|
pascal@17124
|
1497 pushw(r, r->eip);
|
pascal@17124
|
1498 int_vector = (uint16_t *)seg_to_linear(0, num * 4);
|
pascal@17124
|
1499 r->eip = int_vector[0];
|
pascal@17124
|
1500 r->cs = int_vector[1];
|
pascal@17124
|
1501 r->eflags &= ~(VIF_MASK | TF_MASK | AC_MASK);
|
pascal@11674
|
1502 }
|
pascal@11674
|
1503
|
pascal@11674
|
1504 int main(int argc, char **argv)
|
pascal@11674
|
1505 {
|
pascal@11674
|
1506 uint8_t *vm86_mem;
|
pascal@11674
|
1507 const char *filename;
|
pascal@17124
|
1508 int i, ret;
|
pascal@11674
|
1509 uint32_t file_size;
|
pascal@11674
|
1510 struct sigaction sa;
|
pascal@11674
|
1511 struct itimerval timerval;
|
pascal@11674
|
1512 struct vm86plus_struct ctx;
|
pascal@11674
|
1513 struct vm86_regs *r;
|
pascal@11674
|
1514 ExecParamBlock blk1, *blk = &blk1;
|
pascal@11674
|
1515
|
pascal@17124
|
1516 for (argflags = 0; *argv[1] == '-'; argv++) {
|
pascal@17124
|
1517 char *s = argv[1];
|
pascal@17124
|
1518
|
pascal@17124
|
1519 while (1)
|
pascal@17124
|
1520 switch (*++s) {
|
pascal@17124
|
1521 case 'd' : argflags |= DEBUG; break;
|
pascal@17124
|
1522 case 0 : goto nextargv;
|
pascal@17124
|
1523 }
|
pascal@17124
|
1524 nextargv:;
|
pascal@17124
|
1525 }
|
pascal@11674
|
1526 if (argc < 2)
|
pascal@11674
|
1527 usage();
|
pascal@11674
|
1528 filename = argv[1];
|
pascal@11674
|
1529
|
pascal@11674
|
1530 vm86_mem = mmap((void *)0x00000000, 0x110000,
|
pascal@11674
|
1531 PROT_WRITE | PROT_READ | PROT_EXEC,
|
pascal@11674
|
1532 MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
|
pascal@11674
|
1533 if (vm86_mem == MAP_FAILED) {
|
pascal@11674
|
1534 perror("mmap");
|
pascal@11674
|
1535 exit(1);
|
pascal@11674
|
1536 }
|
pascal@11674
|
1537
|
pascal@11674
|
1538 memset(&ctx, 0, sizeof(ctx));
|
pascal@11674
|
1539 r = &ctx.regs;
|
pascal@11674
|
1540 set_bit((uint8_t *)&ctx.int_revectored, 0x10);
|
pascal@11674
|
1541 set_bit((uint8_t *)&ctx.int_revectored, 0x13);
|
pascal@11674
|
1542 set_bit((uint8_t *)&ctx.int_revectored, 0x15);
|
pascal@11674
|
1543 set_bit((uint8_t *)&ctx.int_revectored, 0x16);
|
pascal@11674
|
1544 set_bit((uint8_t *)&ctx.int_revectored, 0x1a);
|
pascal@11674
|
1545 set_bit((uint8_t *)&ctx.int_revectored, 0x20);
|
pascal@11674
|
1546 set_bit((uint8_t *)&ctx.int_revectored, 0x21);
|
pascal@11674
|
1547 set_bit((uint8_t *)&ctx.int_revectored, 0x29);
|
pascal@11674
|
1548
|
pascal@11674
|
1549 dos_init();
|
pascal@11674
|
1550
|
pascal@11674
|
1551 if (strstr(filename,".com") || strstr(filename,".exe") ||
|
pascal@11674
|
1552 strstr(filename,".COM") || strstr(filename,".EXE")) {
|
pascal@11674
|
1553 ret = load_com(blk, filename, &file_size, argc, argv);
|
pascal@11674
|
1554 if (ret < 0) {
|
pascal@11674
|
1555 perror(filename);
|
pascal@11674
|
1556 exit(1);
|
pascal@11674
|
1557 }
|
pascal@17124
|
1558 cur_dta_seg = cur_psp = ret;
|
pascal@17124
|
1559 cur_dta_ofs = 0x80;
|
pascal@11674
|
1560
|
pascal@11674
|
1561 /* init basic registers */
|
pascal@11674
|
1562 r->eip = blk->ip;
|
pascal@11674
|
1563 r->esp = blk->sp + 2; /* pop ax value */
|
pascal@11674
|
1564 r->cs = blk->cs;
|
pascal@11674
|
1565 r->ss = blk->ss;
|
pascal@11674
|
1566 r->ds = cur_psp;
|
pascal@11674
|
1567 r->es = cur_psp;
|
pascal@11674
|
1568 r->eflags = VIF_MASK;
|
pascal@11674
|
1569
|
pascal@11674
|
1570 /* the value of these registers seem to be assumed by pi_10.com */
|
pascal@11674
|
1571 r->esi = 0x100;
|
pascal@11674
|
1572 #if 0
|
pascal@11674
|
1573 r->ebx = file_size >> 16;
|
pascal@11674
|
1574 r->ecx = file_size & 0xffff;
|
pascal@11674
|
1575 #else
|
pascal@11674
|
1576 r->ecx = 0xff;
|
pascal@11674
|
1577 #endif
|
pascal@11674
|
1578 r->ebp = 0x0900;
|
pascal@11674
|
1579 r->edi = 0xfffe;
|
pascal@11674
|
1580 }
|
pascal@11674
|
1581 else {
|
pascal@11674
|
1582 if (load_boot(filename, r) < 0) {
|
pascal@11674
|
1583 if (errno)
|
pascal@11674
|
1584 perror(filename);
|
pascal@11674
|
1585 exit(1);
|
pascal@11674
|
1586 }
|
pascal@11674
|
1587 }
|
pascal@11674
|
1588
|
pascal@11674
|
1589 sa.sa_handler = biosclock;
|
pascal@11674
|
1590 sigemptyset(&sa.sa_mask);
|
pascal@11674
|
1591 sa.sa_flags = SA_RESTART;
|
pascal@11674
|
1592 if (sigaction(SIGALRM, &sa, 0) == 0) {
|
pascal@11674
|
1593 timerval.it_interval.tv_sec = timerval.it_value.tv_sec = 0;
|
pascal@11674
|
1594 timerval.it_interval.tv_usec = timerval.it_value.tv_usec = 10000000 / 182;
|
pascal@11674
|
1595 setitimer (ITIMER_REAL, &timerval, NULL);
|
pascal@11674
|
1596 }
|
pascal@17124
|
1597 *(uint8_t *)seg_to_linear(0xF000, 0) = 0xCF;
|
pascal@17124
|
1598 for (i = 0; i < 16; i++)
|
pascal@17124
|
1599 *(uint32_t *)seg_to_linear(0, i * 4) = 0xF0000000;
|
pascal@17124
|
1600 *(uint32_t *)seg_to_linear(0, 0x18 * 4) = 0xF0000000; /* Basic */
|
pascal@17124
|
1601 *(uint32_t *)seg_to_linear(0, 0x1B * 4) = 0xF0000000; /* Keyboard Ctrl-Break */
|
pascal@17124
|
1602 *(uint32_t *)seg_to_linear(0, 0x23 * 4) = 0xF0000000; /* DOS Ctrl-Break */
|
pascal@17124
|
1603 *(uint32_t *)seg_to_linear(0, 0x24 * 4) = 0xF0000000; /* Critical error */
|
pascal@11674
|
1604
|
pascal@11674
|
1605 for(;;) {
|
pascal@11674
|
1606 ret = vm86(VM86_ENTER, &ctx);
|
pascal@11674
|
1607 switch(VM86_TYPE(ret)) {
|
pascal@11674
|
1608 case VM86_INTx:
|
pascal@11674
|
1609 {
|
pascal@11674
|
1610 int int_num;
|
pascal@11674
|
1611
|
pascal@11674
|
1612 int_num = VM86_ARG(ret);
|
pascal@17124
|
1613 if (argflags & 1)
|
pascal@17124
|
1614 fprintf(stderr,"Int%02X: CS:IP=%04X:%04X AX=%04X\n",
|
pascal@17124
|
1615 int_num, r->cs, r->eip, r->eax);
|
pascal@11674
|
1616 switch(int_num) {
|
pascal@11674
|
1617 case 0x10:
|
pascal@11674
|
1618 do_int10(r);
|
pascal@11674
|
1619 break;
|
pascal@11674
|
1620 case 0x13:
|
pascal@11674
|
1621 do_int13(r);
|
pascal@11674
|
1622 break;
|
pascal@11674
|
1623 case 0x15:
|
pascal@11674
|
1624 do_int15(r);
|
pascal@11674
|
1625 break;
|
pascal@11674
|
1626 case 0x16:
|
pascal@11674
|
1627 do_int16(r);
|
pascal@11674
|
1628 break;
|
pascal@11674
|
1629 case 0x1a:
|
pascal@11674
|
1630 do_int1a(r);
|
pascal@11674
|
1631 break;
|
pascal@11674
|
1632 case 0x20:
|
pascal@11674
|
1633 do_int20(r);
|
pascal@11674
|
1634 break;
|
pascal@11674
|
1635 case 0x21:
|
pascal@11674
|
1636 do_int21(r);
|
pascal@11674
|
1637 break;
|
pascal@11674
|
1638 case 0x29:
|
pascal@11674
|
1639 do_int29(r);
|
pascal@11674
|
1640 break;
|
pascal@11674
|
1641 default:
|
pascal@11674
|
1642 fprintf(stderr, "unsupported int 0x%02x\n", int_num);
|
pascal@11674
|
1643 dump_regs(&ctx.regs);
|
pascal@11674
|
1644 break;
|
pascal@11674
|
1645 }
|
pascal@11674
|
1646 }
|
pascal@11674
|
1647 break;
|
pascal@11674
|
1648 case VM86_SIGNAL:
|
pascal@11674
|
1649 /* a signal came, we just ignore that */
|
pascal@17124
|
1650 if (int8pending) {
|
pascal@17124
|
1651 int8pending--;
|
pascal@17124
|
1652 exec_int(r, 8);
|
pascal@17124
|
1653 }
|
pascal@11674
|
1654 break;
|
pascal@11674
|
1655 case VM86_STI:
|
pascal@11674
|
1656 break;
|
pascal@11674
|
1657 case VM86_TRAP:
|
pascal@11674
|
1658 /* just executes the interruption */
|
pascal@17124
|
1659 exec_int(r, VM86_ARG(ret));
|
pascal@17124
|
1660 break;
|
pascal@17124
|
1661 case VM86_UNKNOWN:
|
pascal@17124
|
1662 switch ( *(uint8_t *)seg_to_linear(r->cs, r->eip) ) {
|
pascal@17124
|
1663 case 0xE4: /* inx portb,al */
|
pascal@17124
|
1664 case 0xE5: /* in portb,ax */
|
pascal@17124
|
1665 case 0xE6: /* out al,portb */
|
pascal@17124
|
1666 case 0xE7: /* out ax,portb */
|
pascal@17124
|
1667 r->eip += 2;
|
pascal@17124
|
1668 continue;
|
pascal@17124
|
1669 case 0xEC: /* in dx,al */
|
pascal@17124
|
1670 case 0xED: /* in dx,ax */
|
pascal@17124
|
1671 case 0xEE: /* out al,dx */
|
pascal@17124
|
1672 case 0xEF: /* out ax,dx */
|
pascal@17124
|
1673 r->eip++;
|
pascal@17124
|
1674 continue;
|
pascal@11674
|
1675 }
|
pascal@11674
|
1676 default:
|
pascal@11674
|
1677 fprintf(stderr, "unhandled vm86 return code (0x%x)\n", ret);
|
pascal@11674
|
1678 dump_regs(&ctx.regs);
|
pascal@11674
|
1679 exit(1);
|
pascal@11674
|
1680 }
|
pascal@11674
|
1681 }
|
pascal@11674
|
1682 }
|