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@11674
|
16 #include <signal.h>
|
pascal@11674
|
17 #include <errno.h>
|
pascal@11674
|
18 #include <ctype.h>
|
pascal@11674
|
19 #include <termios.h>
|
pascal@11674
|
20
|
pascal@11674
|
21 #include <sys/syscall.h>
|
pascal@11674
|
22 #include <asm/vm86.h>
|
pascal@11674
|
23
|
pascal@11674
|
24 //#define DUMP_INT21
|
pascal@11674
|
25
|
pascal@11674
|
26 static inline int vm86(int func, struct vm86plus_struct *v86)
|
pascal@11674
|
27 {
|
pascal@11674
|
28 return syscall(__NR_vm86, func, v86);
|
pascal@11674
|
29 }
|
pascal@11674
|
30
|
pascal@11674
|
31 #define CF_MASK 0x00000001
|
pascal@11674
|
32 #define ZF_MASK 0x00000040
|
pascal@11674
|
33 #define TF_MASK 0x00000100
|
pascal@11674
|
34 #define IF_MASK 0x00000200
|
pascal@11674
|
35 #define DF_MASK 0x00000400
|
pascal@11674
|
36 #define IOPL_MASK 0x00003000
|
pascal@11674
|
37 #define NT_MASK 0x00004000
|
pascal@11674
|
38 #define RF_MASK 0x00010000
|
pascal@11674
|
39 #define VM_MASK 0x00020000
|
pascal@11674
|
40 #define AC_MASK 0x00040000
|
pascal@11674
|
41 #define VIF_MASK 0x00080000
|
pascal@11674
|
42 #define VIP_MASK 0x00100000
|
pascal@11674
|
43 #define ID_MASK 0x00200000
|
pascal@11674
|
44
|
pascal@11674
|
45 void usage(void)
|
pascal@11674
|
46 {
|
pascal@11674
|
47 printf("runcom version 0.2-slitaz (c) 2003-2011 Fabrice Bellard\n"
|
pascal@11674
|
48 "usage: runcom file.com [args...]\n"
|
pascal@11674
|
49 "Run simple .com DOS executables (linux vm86 test mode)\n");
|
pascal@11674
|
50 exit(1);
|
pascal@11674
|
51 }
|
pascal@11674
|
52
|
pascal@11674
|
53 static inline void set_bit(uint8_t *a, unsigned int bit)
|
pascal@11674
|
54 {
|
pascal@11674
|
55 a[bit / 8] |= (1 << (bit % 8));
|
pascal@11674
|
56 }
|
pascal@11674
|
57
|
pascal@11674
|
58 static inline uint8_t *seg_to_linear(unsigned int seg, unsigned int reg)
|
pascal@11674
|
59 {
|
pascal@11674
|
60 return (uint8_t *)((seg << 4) + (reg & 0xffff));
|
pascal@11674
|
61 }
|
pascal@11674
|
62
|
pascal@11674
|
63 static inline void pushw(struct vm86_regs *r, int val)
|
pascal@11674
|
64 {
|
pascal@11674
|
65 r->esp = (r->esp & ~0xffff) | ((r->esp - 2) & 0xffff);
|
pascal@11674
|
66 *(uint16_t *)seg_to_linear(r->ss, r->esp) = val;
|
pascal@11674
|
67 }
|
pascal@11674
|
68
|
pascal@11674
|
69 void dump_regs(struct vm86_regs *r)
|
pascal@11674
|
70 {
|
pascal@11674
|
71 int i;
|
pascal@11674
|
72 uint8_t *p8;
|
pascal@11674
|
73 uint16_t *p16;
|
pascal@11674
|
74 fprintf(stderr,
|
pascal@11674
|
75 "EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx\n"
|
pascal@11674
|
76 "ESI=%08lx EDI=%08lx EBP=%08lx ESP=%08lx\n"
|
pascal@11674
|
77 "EIP=%08lx EFL=%08lx "
|
pascal@11674
|
78 "CS=%04x DS=%04x ES=%04x SS=%04x FS=%04x GS=%04x\n[SP]",
|
pascal@11674
|
79 r->eax, r->ebx, r->ecx, r->edx, r->esi, r->edi, r->ebp, r->esp,
|
pascal@11674
|
80 r->eip, r->eflags,
|
pascal@11674
|
81 r->cs, r->ds, r->es, r->ss, r->fs, r->gs);
|
pascal@11674
|
82 for (p16 = (uint16_t *) seg_to_linear(r->ss, r->esp), i = 0; i < 15; i++)
|
pascal@11674
|
83 fprintf(stderr," %04x", *p16++);
|
pascal@11674
|
84 fprintf(stderr,"\n[IP]");
|
pascal@11674
|
85 for (p8 = seg_to_linear(r->cs, r->eip), i = 0; i < 25; i++)
|
pascal@11674
|
86 fprintf(stderr," %02x", *p8++);
|
pascal@11674
|
87 fprintf(stderr,"\n");
|
pascal@11674
|
88 }
|
pascal@11674
|
89
|
pascal@11674
|
90 #define DOS_FD_MAX 256
|
pascal@11674
|
91 typedef struct {
|
pascal@11674
|
92 int fd; /* -1 means closed */
|
pascal@11674
|
93 } DOSFile;
|
pascal@11674
|
94
|
pascal@11674
|
95 DOSFile dos_files[DOS_FD_MAX];
|
pascal@11674
|
96 uint16_t cur_psp;
|
pascal@11674
|
97
|
pascal@11674
|
98 void dos_init(void)
|
pascal@11674
|
99 {
|
pascal@11674
|
100 int i;
|
pascal@11674
|
101 for(i = 0; i < DOS_FD_MAX; i++)
|
pascal@11674
|
102 dos_files[i].fd = (i < 3) ? i : -1;
|
pascal@11674
|
103 }
|
pascal@11674
|
104
|
pascal@11674
|
105 static inline void set_error(struct vm86_regs *r, int val)
|
pascal@11674
|
106 {
|
pascal@11674
|
107 r->eflags &= ~CF_MASK;
|
pascal@11674
|
108 if (val) {
|
pascal@11674
|
109 r->eax = (r->eax & ~0xffff) | val;
|
pascal@11674
|
110 r->eflags |= CF_MASK;
|
pascal@11674
|
111 }
|
pascal@11674
|
112 }
|
pascal@11674
|
113 static DOSFile *get_file(int h)
|
pascal@11674
|
114 {
|
pascal@11674
|
115 DOSFile *fh;
|
pascal@11674
|
116
|
pascal@11674
|
117 if (h < DOS_FD_MAX) {
|
pascal@11674
|
118 fh = &dos_files[h];
|
pascal@11674
|
119 if (fh->fd != -1)
|
pascal@11674
|
120 return fh;
|
pascal@11674
|
121 }
|
pascal@11674
|
122 return NULL;
|
pascal@11674
|
123 }
|
pascal@11674
|
124
|
pascal@11674
|
125 /* return -1 if error */
|
pascal@11674
|
126 static int get_new_handle(void)
|
pascal@11674
|
127 {
|
pascal@11674
|
128 DOSFile *fh;
|
pascal@11674
|
129 int i;
|
pascal@11674
|
130
|
pascal@11674
|
131 for(i = 0; i < DOS_FD_MAX; i++) {
|
pascal@11674
|
132 fh = &dos_files[i];
|
pascal@11674
|
133 if (fh->fd == -1)
|
pascal@11674
|
134 return i;
|
pascal@11674
|
135 }
|
pascal@11674
|
136 return -1;
|
pascal@11674
|
137 }
|
pascal@11674
|
138
|
pascal@11674
|
139 static char *get_filename1(struct vm86_regs *r, char *buf, int buf_size,
|
pascal@11674
|
140 uint16_t seg, uint16_t offset)
|
pascal@11674
|
141 {
|
pascal@11674
|
142 char *q;
|
pascal@11674
|
143 int c;
|
pascal@11674
|
144 q = buf;
|
pascal@11674
|
145 for(;;) {
|
pascal@11674
|
146 c = *seg_to_linear(seg, offset);
|
pascal@11674
|
147 if (c == 0)
|
pascal@11674
|
148 break;
|
pascal@11674
|
149 if (q >= buf + buf_size - 1)
|
pascal@11674
|
150 break;
|
pascal@11674
|
151 c = tolower(c);
|
pascal@11674
|
152 if (c == '\\')
|
pascal@11674
|
153 c = '/';
|
pascal@11674
|
154 *q++ = c;
|
pascal@11674
|
155 offset++;
|
pascal@11674
|
156 }
|
pascal@11674
|
157 *q = '\0';
|
pascal@11674
|
158 return buf;
|
pascal@11674
|
159 }
|
pascal@11674
|
160
|
pascal@11674
|
161 static char *get_filename(struct vm86_regs *r, char *buf, int buf_size)
|
pascal@11674
|
162 {
|
pascal@11674
|
163 return get_filename1(r, buf, buf_size, r->ds, r->edx & 0xffff);
|
pascal@11674
|
164 }
|
pascal@11674
|
165
|
pascal@11674
|
166 typedef struct __attribute__((packed)) {
|
pascal@11674
|
167 uint8_t drive_num;
|
pascal@11674
|
168 uint8_t file_name[8];
|
pascal@11674
|
169 uint8_t file_ext[3];
|
pascal@11674
|
170 uint16_t current_block;
|
pascal@11674
|
171 uint16_t logical_record_size;
|
pascal@11674
|
172 uint32_t file_size;
|
pascal@11674
|
173 uint16_t date;
|
pascal@11674
|
174 uint16_t time;
|
pascal@11674
|
175 uint8_t reserved[8];
|
pascal@11674
|
176 uint8_t record_in_block;
|
pascal@11674
|
177 uint32_t record_num;
|
pascal@11674
|
178 } FCB;
|
pascal@11674
|
179
|
pascal@11674
|
180 typedef struct __attribute__((packed)) {
|
pascal@11674
|
181 uint16_t environ;
|
pascal@11674
|
182 uint16_t cmdtail_off;
|
pascal@11674
|
183 uint16_t cmdtail_seg;
|
pascal@11674
|
184 uint32_t fcb1;
|
pascal@11674
|
185 uint32_t fcb2;
|
pascal@11674
|
186 uint16_t sp, ss;
|
pascal@11674
|
187 uint16_t ip, cs;
|
pascal@11674
|
188 } ExecParamBlock;
|
pascal@11674
|
189
|
pascal@11674
|
190 typedef struct MemBlock {
|
pascal@11674
|
191 struct MemBlock *next;
|
pascal@11674
|
192 uint16_t seg;
|
pascal@11674
|
193 uint16_t size; /* in paragraphs */
|
pascal@11674
|
194 } MemBlock;
|
pascal@11674
|
195
|
pascal@11674
|
196 /* first allocated paragraph */
|
pascal@11674
|
197 MemBlock *first_mem_block = NULL;
|
pascal@11674
|
198
|
pascal@11674
|
199 #define MEM_START 0x1000
|
pascal@11674
|
200 #define MEM_END 0xa000
|
pascal@11674
|
201
|
pascal@11674
|
202 /* return -1 if error */
|
pascal@11674
|
203 int mem_malloc(int size, int *pmax_size)
|
pascal@11674
|
204 {
|
pascal@11674
|
205 MemBlock *m, **pm;
|
pascal@11674
|
206 int seg_free, seg;
|
pascal@11674
|
207
|
pascal@11674
|
208 /* XXX: this is totally inefficient, but we have only 1 or 2
|
pascal@11674
|
209 blocks ! */
|
pascal@11674
|
210 seg_free = MEM_START;
|
pascal@11674
|
211 for(pm = &first_mem_block; *pm != NULL; pm = &(*pm)->next) {
|
pascal@11674
|
212 m = *pm;
|
pascal@11674
|
213 seg = m->seg + m->size;
|
pascal@11674
|
214 if (seg > seg_free)
|
pascal@11674
|
215 seg_free = seg;
|
pascal@11674
|
216 }
|
pascal@11674
|
217 if ((seg_free + size) > MEM_END)
|
pascal@11674
|
218 return -1;
|
pascal@11674
|
219 if (pmax_size)
|
pascal@11674
|
220 *pmax_size = MEM_END - seg_free;
|
pascal@11674
|
221 /* add at the end */
|
pascal@11674
|
222 m = malloc(sizeof(MemBlock));
|
pascal@11674
|
223 *pm = m;
|
pascal@11674
|
224 m->next = NULL;
|
pascal@11674
|
225 m->seg = seg_free;
|
pascal@11674
|
226 m->size = size;
|
pascal@11674
|
227 #ifdef DUMP_INT21
|
pascal@11674
|
228 printf("mem_malloc size=0x%04x: 0x%04x\n", size, seg_free);
|
pascal@11674
|
229 #endif
|
pascal@11674
|
230 return seg_free;
|
pascal@11674
|
231 }
|
pascal@11674
|
232
|
pascal@11674
|
233 /* return -1 if error */
|
pascal@11674
|
234 int mem_free(int seg)
|
pascal@11674
|
235 {
|
pascal@11674
|
236 MemBlock *m, **pm;
|
pascal@11674
|
237 for(pm = &first_mem_block; *pm != NULL; pm = &(*pm)->next) {
|
pascal@11674
|
238 m = *pm;
|
pascal@11674
|
239 if (m->seg == seg) {
|
pascal@11674
|
240 *pm = m->next;
|
pascal@11674
|
241 free(m);
|
pascal@11674
|
242 return 0;
|
pascal@11674
|
243 }
|
pascal@11674
|
244 }
|
pascal@11674
|
245 return -1;
|
pascal@11674
|
246 }
|
pascal@11674
|
247
|
pascal@11674
|
248 /* return -1 if error or the maxmium size */
|
pascal@11674
|
249 int mem_resize(int seg, int new_size)
|
pascal@11674
|
250 {
|
pascal@11674
|
251 MemBlock *m, **pm, *m1;
|
pascal@11674
|
252 int max_size;
|
pascal@11674
|
253
|
pascal@11674
|
254 for(pm = &first_mem_block; *pm != NULL; pm = &(*pm)->next) {
|
pascal@11674
|
255 m = *pm;
|
pascal@11674
|
256 if (m->seg == seg) {
|
pascal@11674
|
257 m1 = m->next;
|
pascal@11674
|
258 if (!m1)
|
pascal@11674
|
259 max_size = MEM_END - m->seg;
|
pascal@11674
|
260 else
|
pascal@11674
|
261 max_size = m1->seg - m->seg;
|
pascal@11674
|
262 if (new_size > max_size)
|
pascal@11674
|
263 return -1;
|
pascal@11674
|
264 m->size = new_size;
|
pascal@11674
|
265 return max_size;
|
pascal@11674
|
266 }
|
pascal@11674
|
267 }
|
pascal@11674
|
268 return -1;
|
pascal@11674
|
269 }
|
pascal@11674
|
270
|
pascal@11674
|
271 int load_boot(const char *filename, struct vm86_regs *r)
|
pascal@11674
|
272 {
|
pascal@11674
|
273 int fd, ret;
|
pascal@11674
|
274
|
pascal@11674
|
275 /* load the boot sector */
|
pascal@11674
|
276 fd = open(filename, O_RDONLY);
|
pascal@11674
|
277 if (fd >= 0) {
|
pascal@11674
|
278 *seg_to_linear(0x0, 0x7dff) = 0;
|
pascal@11674
|
279 r->eax = 0x200;
|
pascal@11674
|
280 r->ebx = r->esp = r->eip = 0x7c00;
|
pascal@11674
|
281 r->ecx = 1;
|
pascal@11674
|
282 r->esi = r->edi = r->ebp =
|
pascal@11674
|
283 r->edx = 0; /* floppy disk */
|
pascal@11674
|
284 r->cs = r->ss = r->ds = r->es = 0;
|
pascal@11674
|
285 r->eflags = VIF_MASK;
|
pascal@11674
|
286 ret = read(fd, seg_to_linear(0x0, 0x7c00), 0x200);
|
pascal@11674
|
287 if (lseek(fd, 0, SEEK_END) > 4*1024*1024)
|
pascal@11674
|
288 r->edx = 0x80; /* hard disk */
|
pascal@11674
|
289 close(fd);
|
pascal@11674
|
290 if (ret != 0x200 ||
|
pascal@11674
|
291 *seg_to_linear(0x0, 0x7dfe) != 0x55 ||
|
pascal@11674
|
292 *seg_to_linear(0x0, 0x7dff) != 0xaa) {
|
pascal@11674
|
293 fprintf(stderr,"No boot sector.\n");
|
pascal@11674
|
294 fd = -1;
|
pascal@11674
|
295 }
|
pascal@11674
|
296 }
|
pascal@11674
|
297 return fd;
|
pascal@11674
|
298 }
|
pascal@11674
|
299
|
pascal@11674
|
300 /* return the PSP or -1 if error */
|
pascal@11674
|
301 int load_exe(ExecParamBlock *blk, const char *filename,
|
pascal@11674
|
302 int psp, uint32_t *pfile_size)
|
pascal@11674
|
303 {
|
pascal@11674
|
304 int fd, size, base;
|
pascal@11674
|
305 struct {
|
pascal@11674
|
306 uint16_t signature; // 0x5A4D 'MZ'
|
pascal@11674
|
307 uint16_t bytes_in_last_block;
|
pascal@11674
|
308 uint16_t blocks_in_file;
|
pascal@11674
|
309 uint16_t num_relocs;
|
pascal@11674
|
310 uint16_t header_paragraphs; // Size of header
|
pascal@11674
|
311 uint16_t min_extra_paragraphs; // BSS size
|
pascal@11674
|
312 uint16_t max_extra_paragraphs;
|
pascal@11674
|
313 uint16_t ss; // Initial (relative) SS value
|
pascal@11674
|
314 uint16_t sp; // Initial SP value
|
pascal@11674
|
315 uint16_t checksum;
|
pascal@11674
|
316 uint16_t ip; // Initial IP value
|
pascal@11674
|
317 uint16_t cs; // Initial (relative) CS value
|
pascal@11674
|
318 uint16_t reloc_table_offset;
|
pascal@11674
|
319 uint16_t overlay_number;
|
pascal@11674
|
320 } header;
|
pascal@11674
|
321 struct {
|
pascal@11674
|
322 uint16_t offset;
|
pascal@11674
|
323 uint16_t segment;
|
pascal@11674
|
324 } rel;
|
pascal@11674
|
325
|
pascal@11674
|
326 /* load the MSDOS .exe executable */
|
pascal@11674
|
327 fd = open(filename, O_RDONLY);
|
pascal@11674
|
328 if (fd < 0) {
|
pascal@11674
|
329 return -1;
|
pascal@11674
|
330 }
|
pascal@11674
|
331 if (read(fd, &header, sizeof(header)) != sizeof(header)) {
|
pascal@11674
|
332 close(fd);
|
pascal@11674
|
333 return -1;
|
pascal@11674
|
334 }
|
pascal@11674
|
335
|
pascal@11674
|
336 memset(seg_to_linear(psp, 0x100), 0, 65536 - 0x100);
|
pascal@11674
|
337
|
pascal@11674
|
338 size = (header.blocks_in_file * 512) - (header.header_paragraphs * 16) +
|
pascal@11674
|
339 (header.bytes_in_last_block ? header.bytes_in_last_block - 512 : 0);
|
pascal@11674
|
340 header.min_extra_paragraphs += (size-1)/16;
|
pascal@11674
|
341
|
pascal@11674
|
342 /* address of last segment allocated */
|
pascal@11674
|
343 *(uint16_t *)seg_to_linear(psp, 2) = psp + header.min_extra_paragraphs;
|
pascal@11674
|
344
|
pascal@11674
|
345 if (pfile_size)
|
pascal@11674
|
346 *pfile_size = size;
|
pascal@11674
|
347
|
pascal@11674
|
348 if (mem_resize(psp, header.min_extra_paragraphs) < 0 ||
|
pascal@11674
|
349 lseek(fd, header.header_paragraphs * 16, SEEK_SET) < 0 ||
|
pascal@11674
|
350 read(fd, seg_to_linear(psp, 0x100), size) != size ||
|
pascal@11674
|
351 lseek(fd, header.reloc_table_offset, SEEK_SET) < 0) {
|
pascal@11674
|
352 close(fd);
|
pascal@11674
|
353 return -1;
|
pascal@11674
|
354 }
|
pascal@11674
|
355
|
pascal@11674
|
356 base = psp + 16;
|
pascal@11674
|
357 while (header.num_relocs-- && read(fd, &rel, sizeof(rel)) == sizeof(rel))
|
pascal@11674
|
358 if (rel.segment != 0 || rel.offset != 0)
|
pascal@11674
|
359 * (uint16_t *) seg_to_linear(base + rel.segment, rel.offset) += base;
|
pascal@11674
|
360 close(fd);
|
pascal@11674
|
361
|
pascal@11674
|
362 blk->cs = base + header.cs;
|
pascal@11674
|
363 blk->ip = header.ip;
|
pascal@11674
|
364 blk->ss = base + header.ss;
|
pascal@11674
|
365 blk->sp = header.sp - 6;
|
pascal@11674
|
366
|
pascal@11674
|
367 /* push return far address */
|
pascal@11674
|
368 *(uint16_t *)seg_to_linear(blk->ss, blk->sp + 4) = psp;
|
pascal@11674
|
369
|
pascal@11674
|
370 return psp;
|
pascal@11674
|
371 }
|
pascal@11674
|
372
|
pascal@11674
|
373 /* return the PSP or -1 if error */
|
pascal@11674
|
374 int load_com(ExecParamBlock *blk, const char *filename, uint32_t *pfile_size,
|
pascal@11674
|
375 int argc, char **argv)
|
pascal@11674
|
376 {
|
pascal@11674
|
377 int psp, fd, ret;
|
pascal@11674
|
378
|
pascal@11674
|
379 /* load the MSDOS .com executable */
|
pascal@11674
|
380 fd = open(filename, O_RDONLY);
|
pascal@11674
|
381 if (fd < 0) {
|
pascal@11674
|
382 return -1;
|
pascal@11674
|
383 }
|
pascal@11674
|
384 psp = mem_malloc(65536 / 16, NULL);
|
pascal@11674
|
385 ret = read(fd, seg_to_linear(psp, 0x100), 65536 - 0x100);
|
pascal@11674
|
386 close(fd);
|
pascal@11674
|
387 if (ret <= 0) {
|
pascal@11674
|
388 mem_free(psp);
|
pascal@11674
|
389 return -1;
|
pascal@11674
|
390 }
|
pascal@11674
|
391 if (pfile_size)
|
pascal@11674
|
392 *pfile_size = ret;
|
pascal@11674
|
393
|
pascal@11674
|
394 /* reset the PSP */
|
pascal@11674
|
395 memset(seg_to_linear(psp, 0), 0, 0x100);
|
pascal@11674
|
396
|
pascal@11674
|
397 *seg_to_linear(psp, 0) = 0xcd; /* int $0x20 */
|
pascal@11674
|
398 *seg_to_linear(psp, 1) = 0x20;
|
pascal@11674
|
399 /* address of last segment allocated */
|
pascal@11674
|
400 *(uint16_t *)seg_to_linear(psp, 2) = psp + 0xfff;
|
pascal@11674
|
401
|
pascal@11674
|
402 if (argc) {
|
pascal@11674
|
403 int i, p;
|
pascal@11674
|
404 char *s;
|
pascal@11674
|
405 /* set the command line */
|
pascal@11674
|
406 p = 0x81;
|
pascal@11674
|
407 for(i = 2; i < argc; i++) {
|
pascal@11674
|
408 if (p >= 0xff)
|
pascal@11674
|
409 break;
|
pascal@11674
|
410 *seg_to_linear(psp, p++) = ' ';
|
pascal@11674
|
411 s = argv[i];
|
pascal@11674
|
412 while (*s) {
|
pascal@11674
|
413 if (p >= 0xff)
|
pascal@11674
|
414 break;
|
pascal@11674
|
415 *seg_to_linear(psp, p++) = *s++;
|
pascal@11674
|
416 }
|
pascal@11674
|
417 }
|
pascal@11674
|
418 *seg_to_linear(psp, p) = '\r';
|
pascal@11674
|
419 *seg_to_linear(psp, 0x80) = p - 0x81;
|
pascal@11674
|
420 }
|
pascal@11674
|
421 else {
|
pascal@11674
|
422 int len;
|
pascal@11674
|
423 /* copy the command line */
|
pascal@11674
|
424 len = *seg_to_linear(blk->cmdtail_seg, blk->cmdtail_off);
|
pascal@11674
|
425 memcpy(seg_to_linear(psp, 0x80),
|
pascal@11674
|
426 seg_to_linear(blk->cmdtail_seg, blk->cmdtail_off), len + 2);
|
pascal@11674
|
427 }
|
pascal@11674
|
428
|
pascal@11674
|
429 blk->sp = 0xfffc;
|
pascal@11674
|
430 blk->ip = 0x100;
|
pascal@11674
|
431 blk->cs = blk->ss = psp;
|
pascal@11674
|
432
|
pascal@11674
|
433 if (*(uint16_t *)seg_to_linear(psp, 0x100) == 0x5A4D)
|
pascal@11674
|
434 psp = load_exe(blk, filename, psp, pfile_size);
|
pascal@11674
|
435
|
pascal@11674
|
436 /* push ax value */
|
pascal@11674
|
437 *(uint16_t *)seg_to_linear(blk->ss, blk->sp) = 0;
|
pascal@11674
|
438 /* push return address to 0 */
|
pascal@11674
|
439 *(uint16_t *)seg_to_linear(blk->ss, blk->sp + 2) = 0;
|
pascal@11674
|
440
|
pascal@11674
|
441 return psp;
|
pascal@11674
|
442 }
|
pascal@11674
|
443
|
pascal@11674
|
444
|
pascal@11674
|
445 void unsupported_function(struct vm86_regs *r, uint8_t num, uint8_t ah)
|
pascal@11674
|
446 {
|
pascal@11674
|
447 fprintf(stderr, "int 0x%02x: unsupported function 0x%02x\n", num, ah);
|
pascal@11674
|
448 dump_regs(r);
|
pascal@11674
|
449 set_error(r, 0x01); /* function number invalid */
|
pascal@11674
|
450 }
|
pascal@11674
|
451
|
pascal@11674
|
452 /* Open hard disk image ./hd[0-7] / floppy image ./fd[0-7] or /dev/fd[0-7] */
|
pascal@11674
|
453 int open_disk(struct vm86_regs *r)
|
pascal@11674
|
454 {
|
pascal@11674
|
455 int fd = -1, drive = r->edx & 0xff;
|
pascal@11674
|
456 char filename[9], n = '0' + (drive & 7);
|
pascal@11674
|
457 if (drive > 127) {
|
pascal@11674
|
458 strcpy(filename,"hd0");
|
pascal@11674
|
459 filename[2] = n;
|
pascal@11674
|
460 }
|
pascal@11674
|
461 else {
|
pascal@11674
|
462 strcpy(filename,"/dev/fd0");
|
pascal@11674
|
463 filename[7] = n;
|
pascal@11674
|
464 fd = open(filename+5, O_RDONLY);
|
pascal@11674
|
465 }
|
pascal@11674
|
466 if (fd < 0)
|
pascal@11674
|
467 fd = open(filename, O_RDONLY);
|
pascal@11674
|
468 return fd;
|
pascal@11674
|
469 }
|
pascal@11674
|
470
|
pascal@11674
|
471
|
pascal@11674
|
472 void read_sectors(int fd, struct vm86_regs *r, int first_sector,
|
pascal@11674
|
473 int sector_count, void *buffer)
|
pascal@11674
|
474 {
|
pascal@11674
|
475 int drive = r->edx & 0xff;
|
pascal@11674
|
476 r->eax &= ~0xff00;
|
pascal@11674
|
477 r->eax |= 0x0400; /* sector not found */
|
pascal@11674
|
478 r->eflags |= CF_MASK;
|
pascal@11674
|
479 if (fd >= 0) {
|
pascal@11674
|
480 static struct stat st;
|
pascal@11674
|
481 first_sector <<= 9;
|
pascal@11674
|
482 sector_count <<= 9;
|
pascal@11674
|
483 if (drive < 8 && fstat(fd, &st) == 0) {
|
pascal@11674
|
484 static ino_t inodes[8];
|
pascal@11674
|
485 ino_t last = inodes[drive];
|
pascal@11674
|
486 inodes[drive] = st.st_ino;
|
pascal@11674
|
487 if (last && last != st.st_ino) {
|
pascal@11674
|
488 set_error(r, 0x0600); /* floppy disk swap */
|
pascal@11674
|
489 goto failed;
|
pascal@11674
|
490 }
|
pascal@11674
|
491 }
|
pascal@12554
|
492 if (lseek(fd, first_sector, SEEK_SET) >= 0 &&
|
pascal@11674
|
493 read(fd, buffer, sector_count) == sector_count) {
|
pascal@11674
|
494 r->eax &= ~0xff00;
|
pascal@11674
|
495 r->eflags &= ~CF_MASK;
|
pascal@11674
|
496 }
|
pascal@11674
|
497 failed:
|
pascal@11674
|
498 close(fd);
|
pascal@11674
|
499 }
|
pascal@11674
|
500 }
|
pascal@11674
|
501
|
pascal@11674
|
502 void do_int10(struct vm86_regs *r)
|
pascal@11674
|
503 {
|
pascal@11674
|
504 uint8_t ah;
|
pascal@11674
|
505
|
pascal@11674
|
506 ah = (r->eax >> 8);
|
pascal@11674
|
507 switch(ah) {
|
pascal@11674
|
508 case 0x0E: /* write char */
|
pascal@11674
|
509 {
|
pascal@11674
|
510 uint8_t c = r->eax;
|
pascal@11674
|
511 write(1, &c, 1);
|
pascal@11674
|
512 }
|
pascal@11674
|
513 break;
|
pascal@11674
|
514 default:
|
pascal@11674
|
515 unsupported_function(r, 0x10, ah);
|
pascal@11674
|
516 }
|
pascal@11674
|
517 }
|
pascal@11674
|
518
|
pascal@11674
|
519 void do_int13(struct vm86_regs *r)
|
pascal@11674
|
520 {
|
pascal@11674
|
521 uint8_t ah;
|
pascal@11674
|
522
|
pascal@11674
|
523 ah = (r->eax >> 8);
|
pascal@11674
|
524 switch(ah) {
|
pascal@11674
|
525 case 0x00: /* reset disk */
|
pascal@11674
|
526 {
|
pascal@11674
|
527 r->eax &= ~0xff00; /* success */
|
pascal@11674
|
528 r->eflags &= ~CF_MASK;
|
pascal@11674
|
529 }
|
pascal@11674
|
530 break;
|
pascal@11674
|
531 case 0x02: /* read disk CHS */
|
pascal@11674
|
532 {
|
pascal@11674
|
533 int fd, c, h, s, heads, sectors, cylinders;
|
pascal@11674
|
534 long size;
|
pascal@11674
|
535 fd = open_disk(r);
|
pascal@11674
|
536 if (fd >= 0) {
|
pascal@11674
|
537 size = lseek(fd, 0, SEEK_END) / 512;
|
pascal@11674
|
538 if ((r->edx & 0xff) > 127) {
|
pascal@11674
|
539 sectors = 63;
|
pascal@11674
|
540 if (size % sectors)
|
pascal@11674
|
541 sectors = 62;
|
pascal@11674
|
542 if (size % sectors)
|
pascal@11674
|
543 sectors = 32;
|
pascal@11674
|
544 if (size % sectors)
|
pascal@11674
|
545 sectors = 17;
|
pascal@11674
|
546 if (size % sectors)
|
pascal@11674
|
547 fd = -1;
|
pascal@11674
|
548 size /= sectors;
|
pascal@11674
|
549 for (heads = 256; size % heads; heads--);
|
pascal@11674
|
550 cylinders = size / heads;
|
pascal@11674
|
551 }
|
pascal@11674
|
552 else {
|
pascal@11674
|
553 int i;
|
pascal@11674
|
554 heads = 1 + (size > 256*2);
|
pascal@11674
|
555 cylinders = 40 * (1 + (size > 512*2));
|
pascal@11674
|
556 size /= heads;
|
pascal@11674
|
557 for (i = 0; i < 5; i++)
|
pascal@11674
|
558 if (size % (cylinders + i) == 0) break;
|
pascal@11674
|
559 if (i == 5)
|
pascal@11674
|
560 fd = -1;
|
pascal@11674
|
561 cylinders += i;
|
pascal@11674
|
562 sectors = size / cylinders;
|
pascal@11674
|
563 }
|
pascal@11674
|
564 }
|
pascal@11674
|
565 c = ((r->ecx & 0xC0) << 2) | ((r->ecx >> 8) & 0xff);
|
pascal@11674
|
566 h = (r->edx >> 8) & 0xff;
|
pascal@11674
|
567 s = (r->ecx & 0x3f) -1;
|
pascal@11674
|
568 if (fd < 0 || c >= cylinders || h >= heads || s >= sectors) {
|
pascal@11674
|
569 set_error(r, 0x0400); /* sector not found */
|
pascal@11674
|
570 break;
|
pascal@11674
|
571 }
|
pascal@11674
|
572 read_sectors(fd, r, (((c * heads) + h) * sectors) + s,
|
pascal@11674
|
573 r->eax & 0xff, seg_to_linear(r->es, r->ebx));
|
pascal@11674
|
574 }
|
pascal@11674
|
575 break;
|
pascal@11674
|
576 case 0x42: /* read disk LBA */
|
pascal@11674
|
577 {
|
pascal@11674
|
578 uint16_t *packet = (uint16_t *) seg_to_linear(r->ds, r-> esi);
|
pascal@11674
|
579 uint8_t *to = seg_to_linear(packet[3], packet[2]);
|
pascal@11674
|
580 if ((packet[3] & packet[2]) == 0xffff)
|
pascal@11674
|
581 to = * (uint8_t **) &packet[8];
|
pascal@11674
|
582 if (packet[0] != 0x0010 && packet[0] != 0x0018)
|
pascal@11674
|
583 goto unsupported;
|
pascal@11674
|
584 read_sectors(open_disk(r), r, * (uint32_t *) &packet[4], packet[1], to);
|
pascal@11674
|
585 }
|
pascal@11674
|
586 break;
|
pascal@11674
|
587 default:
|
pascal@11674
|
588 unsupported:
|
pascal@11674
|
589 unsupported_function(r, 0x13, ah);
|
pascal@11674
|
590 }
|
pascal@11674
|
591 }
|
pascal@11674
|
592
|
pascal@11674
|
593 void do_int15(struct vm86_regs *r)
|
pascal@11674
|
594 {
|
pascal@11674
|
595 uint8_t ah;
|
pascal@11674
|
596
|
pascal@11674
|
597 ah = (r->eax >> 8);
|
pascal@11674
|
598 switch(ah) {
|
pascal@11674
|
599 case 0x87: /* move memory */
|
pascal@11674
|
600 /* XXX */
|
pascal@11674
|
601 break;
|
pascal@11674
|
602 default:
|
pascal@11674
|
603 unsupported_function(r, 0x15, ah);
|
pascal@11674
|
604 }
|
pascal@11674
|
605 }
|
pascal@11674
|
606
|
pascal@11674
|
607 void do_int16(struct vm86_regs *r)
|
pascal@11674
|
608 {
|
pascal@11674
|
609 static uint16_t last_ax, hold_char;
|
pascal@11674
|
610 struct termios termios_def, termios_raw;
|
pascal@11674
|
611 uint8_t ah;
|
pascal@11674
|
612
|
pascal@11674
|
613 ah = (r->eax >> 8);
|
pascal@11674
|
614 tcgetattr(0, &termios_def);
|
pascal@11674
|
615 termios_raw = termios_def;
|
pascal@11674
|
616 cfmakeraw(&termios_raw);
|
pascal@11674
|
617 tcsetattr(0, TCSADRAIN, &termios_raw);
|
pascal@11674
|
618 switch(ah) {
|
pascal@11674
|
619 case 0x01: /* test keyboard */
|
pascal@11674
|
620 {
|
pascal@11674
|
621 int count;
|
pascal@11674
|
622 r->eflags &= ~ZF_MASK;
|
pascal@11674
|
623 if (hold_char) {
|
pascal@11674
|
624 r->eax &= ~0xffff;
|
pascal@11674
|
625 r->eax |= last_ax;
|
pascal@11674
|
626 break;
|
pascal@11674
|
627 }
|
pascal@11674
|
628 if (ioctl(0, FIONREAD, &count) < 0 || count == 0) {
|
pascal@11674
|
629 r->eflags |= ZF_MASK;
|
pascal@11674
|
630 break;
|
pascal@11674
|
631 }
|
pascal@11674
|
632 hold_char = 2;
|
pascal@11674
|
633 }
|
pascal@11674
|
634 case 0x00: /* read keyboard */
|
pascal@11674
|
635 {
|
pascal@11674
|
636 uint8_t c;
|
pascal@11674
|
637 if (hold_char)
|
pascal@11674
|
638 hold_char--;
|
pascal@11674
|
639 read(0, &c, 1);
|
pascal@11674
|
640 if (c == 3) {
|
pascal@11674
|
641 tcsetattr(0, TCSADRAIN, &termios_def);
|
pascal@11674
|
642 exit(0);
|
pascal@11674
|
643 }
|
pascal@11674
|
644 if (c == 10)
|
pascal@11674
|
645 c = 13;
|
pascal@11674
|
646 r->eax &= ~0xffff;
|
pascal@11674
|
647 r->eax |= last_ax = c;
|
pascal@11674
|
648 /* XXX ah = scan code */
|
pascal@11674
|
649 }
|
pascal@11674
|
650 break;
|
pascal@11674
|
651 default:
|
pascal@11674
|
652 unsupported_function(r, 0x16, ah);
|
pascal@11674
|
653 }
|
pascal@11674
|
654 tcsetattr(0, TCSADRAIN, &termios_def);
|
pascal@11674
|
655 }
|
pascal@11674
|
656
|
pascal@11674
|
657 void do_int1a(struct vm86_regs *r)
|
pascal@11674
|
658 {
|
pascal@11674
|
659 uint8_t ah;
|
pascal@11674
|
660
|
pascal@11674
|
661 ah = (r->eax >> 8);
|
pascal@11674
|
662 switch(ah) {
|
pascal@11674
|
663 case 0x00: /* GET SYSTEM TIME */
|
pascal@11674
|
664 {
|
pascal@11674
|
665 uint16_t *timer = (uint16_t *) seg_to_linear(0, 0x46C);
|
pascal@11674
|
666 r->ecx &= ~0xffff;
|
pascal@11674
|
667 r->ecx |= *timer++;
|
pascal@11674
|
668 r->edx &= ~0xffff;
|
pascal@11674
|
669 r->edx |= *timer;
|
pascal@11674
|
670 r->eax &= ~0xff;
|
pascal@11674
|
671 }
|
pascal@11674
|
672 break;
|
pascal@11674
|
673 default:
|
pascal@11674
|
674 unsupported_function(r, 0x1a, ah);
|
pascal@11674
|
675 }
|
pascal@11674
|
676 }
|
pascal@11674
|
677
|
pascal@11674
|
678 void do_int20(struct vm86_regs *r)
|
pascal@11674
|
679 {
|
pascal@11674
|
680 /* terminate program */
|
pascal@11674
|
681 exit(0);
|
pascal@11674
|
682 }
|
pascal@11674
|
683
|
pascal@11674
|
684 void do_int21(struct vm86_regs *r)
|
pascal@11674
|
685 {
|
pascal@11674
|
686 uint8_t ah;
|
pascal@11674
|
687
|
pascal@11674
|
688 ah = (r->eax >> 8);
|
pascal@11674
|
689 switch(ah) {
|
pascal@11674
|
690 case 0x00: /* exit */
|
pascal@11674
|
691 exit(0);
|
pascal@11674
|
692 case 0x02: /* write char */
|
pascal@11674
|
693 {
|
pascal@11674
|
694 uint8_t c = r->edx;
|
pascal@11674
|
695 write(1, &c, 1);
|
pascal@11674
|
696 }
|
pascal@11674
|
697 break;
|
pascal@11674
|
698 case 0x09: /* write string */
|
pascal@11674
|
699 {
|
pascal@11674
|
700 uint8_t c;
|
pascal@11674
|
701 int offset;
|
pascal@11674
|
702 offset = r->edx;
|
pascal@11674
|
703 for(;;) {
|
pascal@11674
|
704 c = *seg_to_linear(r->ds, offset);
|
pascal@11674
|
705 if (c == '$')
|
pascal@11674
|
706 break;
|
pascal@11674
|
707 write(1, &c, 1);
|
pascal@11674
|
708 offset++;
|
pascal@11674
|
709 }
|
pascal@11674
|
710 r->eax = (r->eax & ~0xff) | '$';
|
pascal@11674
|
711 }
|
pascal@11674
|
712 break;
|
pascal@11674
|
713 case 0x0a: /* buffered input */
|
pascal@11674
|
714 {
|
pascal@11674
|
715 int max_len, cur_len, ret;
|
pascal@11674
|
716 uint8_t ch;
|
pascal@11674
|
717 uint16_t off;
|
pascal@11674
|
718
|
pascal@11674
|
719 /* XXX: should use raw mode to avoid sending the CRLF to
|
pascal@11674
|
720 the terminal */
|
pascal@11674
|
721 off = r->edx & 0xffff;
|
pascal@11674
|
722 max_len = *seg_to_linear(r->ds, off);
|
pascal@11674
|
723 cur_len = 0;
|
pascal@11674
|
724 while (cur_len < max_len) {
|
pascal@11674
|
725 ret = read(0, &ch, 1);
|
pascal@11674
|
726 if (ret < 0) {
|
pascal@11674
|
727 if (errno != EINTR && errno != EAGAIN)
|
pascal@11674
|
728 break;
|
pascal@11674
|
729 } else if (ret == 0) {
|
pascal@11674
|
730 break;
|
pascal@11674
|
731 } else {
|
pascal@11674
|
732 if (ch == '\n')
|
pascal@11674
|
733 break;
|
pascal@11674
|
734 }
|
pascal@11674
|
735 *seg_to_linear(r->ds, off + 2 + cur_len++) = ch;
|
pascal@11674
|
736 }
|
pascal@11674
|
737 *seg_to_linear(r->ds, off + 1) = cur_len;
|
pascal@11674
|
738 *seg_to_linear(r->ds, off + 2 + cur_len) = '\r';
|
pascal@11674
|
739 }
|
pascal@11674
|
740 break;
|
pascal@11674
|
741 case 0x25: /* set interrupt vector */
|
pascal@11674
|
742 {
|
pascal@11674
|
743 uint16_t *ptr;
|
pascal@11674
|
744 ptr = (uint16_t *)seg_to_linear(0, (r->eax & 0xff) * 4);
|
pascal@11674
|
745 ptr[0] = r->edx;
|
pascal@11674
|
746 ptr[1] = r->ds;
|
pascal@11674
|
747 }
|
pascal@11674
|
748 break;
|
pascal@11674
|
749 case 0x29: /* parse filename into FCB */
|
pascal@11674
|
750 #if 0
|
pascal@11674
|
751 /* not really needed */
|
pascal@11674
|
752 {
|
pascal@11674
|
753 const uint8_t *p, *p_start;
|
pascal@11674
|
754 uint8_t file[8], ext[3];
|
pascal@11674
|
755 FCB *fcb;
|
pascal@11674
|
756 int file_len, ext_len, has_wildchars, c, drive_num;
|
pascal@11674
|
757
|
pascal@11674
|
758 /* XXX: not complete at all */
|
pascal@11674
|
759 fcb = (FCB *)seg_to_linear(r->es, r->edi);
|
pascal@11674
|
760 printf("ds=0x%x si=0x%lx\n", r->ds, r->esi);
|
pascal@11674
|
761 p_start = (const uint8_t *)seg_to_linear(r->ds, r->esi);
|
pascal@11674
|
762
|
pascal@11674
|
763 p = p_start;
|
pascal@11674
|
764 has_wildchars = 0;
|
pascal@11674
|
765
|
pascal@11674
|
766 /* drive */
|
pascal@11674
|
767 if (isalpha(p[0]) && p[1] == ':') {
|
pascal@11674
|
768 drive_num = toupper(p[0]) - 'A' + 1;
|
pascal@11674
|
769 p += 2;
|
pascal@11674
|
770 } else {
|
pascal@11674
|
771 drive_num = 0;
|
pascal@11674
|
772 }
|
pascal@11674
|
773
|
pascal@11674
|
774 /* filename */
|
pascal@11674
|
775 file_len = 0;
|
pascal@11674
|
776 for(;;) {
|
pascal@11674
|
777 c = *p;
|
pascal@11674
|
778 if (!(c >= 33 && c <= 126))
|
pascal@11674
|
779 break;
|
pascal@11674
|
780 if (c == '.')
|
pascal@11674
|
781 break;
|
pascal@11674
|
782 if (c == '*' || c == '?')
|
pascal@11674
|
783 has_wildchars = 1;
|
pascal@11674
|
784 if (file_len < 8)
|
pascal@11674
|
785 file[file_len++] = c;
|
pascal@11674
|
786 }
|
pascal@11674
|
787 memset(file + file_len, ' ', 8 - file_len);
|
pascal@11674
|
788
|
pascal@11674
|
789 /* extension */
|
pascal@11674
|
790 ext_len = 0;
|
pascal@11674
|
791 if (*p == '.') {
|
pascal@11674
|
792 for(;;) {
|
pascal@11674
|
793 c = *p;
|
pascal@11674
|
794 if (!(c >= 33 && c <= 126))
|
pascal@11674
|
795 break;
|
pascal@11674
|
796 if (c == '*' || c == '?')
|
pascal@11674
|
797 has_wildchars = 1;
|
pascal@11674
|
798 ext[ext_len++] = c;
|
pascal@11674
|
799 if (ext_len >= 3)
|
pascal@11674
|
800 break;
|
pascal@11674
|
801 }
|
pascal@11674
|
802 }
|
pascal@11674
|
803 memset(ext + ext_len, ' ', 3 - ext_len);
|
pascal@11674
|
804
|
pascal@11674
|
805 #if 0
|
pascal@11674
|
806 {
|
pascal@11674
|
807 printf("drive=%d file=%8s ext=%3s\n",
|
pascal@11674
|
808 drive_num, file, ext);
|
pascal@11674
|
809 }
|
pascal@11674
|
810 #endif
|
pascal@11674
|
811 if (drive_num == 0 && r->eax & (1 << 1)) {
|
pascal@11674
|
812 /* keep drive */
|
pascal@11674
|
813 } else {
|
pascal@11674
|
814 fcb->drive_num = drive_num; /* default drive */
|
pascal@11674
|
815 }
|
pascal@11674
|
816
|
pascal@11674
|
817 if (file_len == 0 && r->eax & (1 << 2)) {
|
pascal@11674
|
818 /* keep */
|
pascal@11674
|
819 } else {
|
pascal@11674
|
820 memcpy(fcb->file_name, file, 8);
|
pascal@11674
|
821 }
|
pascal@11674
|
822
|
pascal@11674
|
823 if (ext_len == 0 && r->eax & (1 << 3)) {
|
pascal@11674
|
824 /* keep */
|
pascal@11674
|
825 } else {
|
pascal@11674
|
826 memcpy(fcb->file_ext, ext, 3);
|
pascal@11674
|
827 }
|
pascal@11674
|
828 r->eax = (r->eax & ~0xff) | has_wildchars;
|
pascal@11674
|
829 r->esi = (r->esi & ~0xffff) | ((r->esi + (p - p_start)) & 0xffff);
|
pascal@11674
|
830 }
|
pascal@11674
|
831 #endif
|
pascal@11674
|
832 break;
|
pascal@11674
|
833 case 0x2A: /* get system date */
|
pascal@11674
|
834 {
|
pascal@11674
|
835 time_t t = time(NULL);
|
pascal@11674
|
836 struct tm *now=localtime(&t);
|
pascal@11674
|
837
|
pascal@11674
|
838 r->ecx = now->tm_year;
|
pascal@11674
|
839 r->edx = (now->tm_mon * 256) + now->tm_mday;
|
pascal@11674
|
840 r->eax = now->tm_wday;;
|
pascal@11674
|
841 }
|
pascal@11674
|
842 break;
|
pascal@11674
|
843 case 0x2C: /* get system time */
|
pascal@11674
|
844 {
|
pascal@11674
|
845 time_t t = time(NULL);
|
pascal@11674
|
846 struct tm *now=localtime(&t);
|
pascal@11674
|
847 struct timeval tim;
|
pascal@11674
|
848
|
pascal@11674
|
849 gettimeofday(&tim, NULL);
|
pascal@11674
|
850 r->edx = (now->tm_hour * 256) + now->tm_min;
|
pascal@11674
|
851 r->edx = (tim.tv_sec * 256) + tim.tv_usec/10000;
|
pascal@11674
|
852 }
|
pascal@11674
|
853 break;
|
pascal@11674
|
854 case 0x30: /* get dos version */
|
pascal@11674
|
855 {
|
pascal@11674
|
856 int major, minor, serial, oem;
|
pascal@11674
|
857 /* XXX: return correct value for FreeDOS */
|
pascal@11674
|
858 major = 0x03;
|
pascal@11674
|
859 minor = 0x31;
|
pascal@11674
|
860 serial = 0x123456;
|
pascal@11674
|
861 oem = 0x66;
|
pascal@11674
|
862 r->eax = (r->eax & ~0xffff) | major | (minor << 8);
|
pascal@11674
|
863 r->ecx = (r->ecx & ~0xffff) | (serial & 0xffff);
|
pascal@11674
|
864 r->ebx = (r->ebx & ~0xffff) | (serial & 0xff) | (0x66 << 8);
|
pascal@11674
|
865 }
|
pascal@11674
|
866 break;
|
pascal@11674
|
867 case 0x35: /* get interrupt vector */
|
pascal@11674
|
868 {
|
pascal@11674
|
869 uint16_t *ptr;
|
pascal@11674
|
870 ptr = (uint16_t *)seg_to_linear(0, (r->eax & 0xff) * 4);
|
pascal@11674
|
871 r->ebx = (r->ebx & ~0xffff) | ptr[0];
|
pascal@11674
|
872 r->es = ptr[1];
|
pascal@11674
|
873 }
|
pascal@11674
|
874 break;
|
pascal@11674
|
875 case 0x37:
|
pascal@11674
|
876 {
|
pascal@11674
|
877 switch(r->eax & 0xff) {
|
pascal@11674
|
878 case 0x00: /* get switch char */
|
pascal@11674
|
879 r->eax = (r->eax & ~0xff) | 0x00;
|
pascal@11674
|
880 r->edx = (r->edx & ~0xff) | '/';
|
pascal@11674
|
881 break;
|
pascal@11674
|
882 default:
|
pascal@11674
|
883 goto unsupported;
|
pascal@11674
|
884 }
|
pascal@11674
|
885 }
|
pascal@11674
|
886 break;
|
pascal@11674
|
887 case 0x3c: /* create or truncate file */
|
pascal@11674
|
888 {
|
pascal@11674
|
889 char filename[1024];
|
pascal@11674
|
890 int fd, h, flags;
|
pascal@11674
|
891
|
pascal@11674
|
892 h = get_new_handle();
|
pascal@11674
|
893 if (h < 0) {
|
pascal@11674
|
894 set_error(r, 0x04); /* too many open files */
|
pascal@11674
|
895 } else {
|
pascal@11674
|
896 get_filename(r, filename, sizeof(filename));
|
pascal@11674
|
897 if (r->ecx & 1)
|
pascal@11674
|
898 flags = 0444; /* read-only */
|
pascal@11674
|
899 else
|
pascal@11674
|
900 flags = 0777;
|
pascal@11674
|
901 fd = open(filename, O_RDWR | O_TRUNC | O_CREAT, flags);
|
pascal@11674
|
902 #ifdef DUMP_INT21
|
pascal@11674
|
903 printf("int21: create: file='%s' cx=0x%04x ret=%d\n",
|
pascal@11674
|
904 filename, (int)(r->ecx & 0xffff), h);
|
pascal@11674
|
905 #endif
|
pascal@11674
|
906 if (fd < 0) {
|
pascal@11674
|
907 set_error(r, 0x03); /* path not found */
|
pascal@11674
|
908 } else {
|
pascal@11674
|
909 dos_files[h].fd = fd;
|
pascal@11674
|
910 set_error(r, 0);
|
pascal@11674
|
911 r->eax = (r->eax & ~0xffff) | h;
|
pascal@11674
|
912 }
|
pascal@11674
|
913 }
|
pascal@11674
|
914 }
|
pascal@11674
|
915 break;
|
pascal@11674
|
916 case 0x3d: /* open file */
|
pascal@11674
|
917 {
|
pascal@11674
|
918 char filename[1024];
|
pascal@11674
|
919 int fd, h;
|
pascal@11674
|
920
|
pascal@11674
|
921 h = get_new_handle();
|
pascal@11674
|
922 if (h < 0) {
|
pascal@11674
|
923 set_error(r, 0x04); /* too many open files */
|
pascal@11674
|
924 } else {
|
pascal@11674
|
925 get_filename(r, filename, sizeof(filename));
|
pascal@11674
|
926 #ifdef DUMP_INT21
|
pascal@11674
|
927 printf("int21: open: file='%s' al=0x%02x ret=%d\n",
|
pascal@11674
|
928 filename, (int)(r->eax & 0xff), h);
|
pascal@11674
|
929 #endif
|
pascal@11674
|
930 fd = open(filename, r->eax & 3);
|
pascal@11674
|
931 if (fd < 0) {
|
pascal@11674
|
932 set_error(r, 0x02); /* file not found */
|
pascal@11674
|
933 } else {
|
pascal@11674
|
934 dos_files[h].fd = fd;
|
pascal@11674
|
935 set_error(r, 0);
|
pascal@11674
|
936 r->eax = (r->eax & ~0xffff) | h;
|
pascal@11674
|
937 }
|
pascal@11674
|
938 }
|
pascal@11674
|
939 }
|
pascal@11674
|
940 break;
|
pascal@11674
|
941 case 0x3e: /* close file */
|
pascal@11674
|
942 {
|
pascal@11674
|
943 DOSFile *fh = get_file(r->ebx & 0xffff);
|
pascal@11674
|
944 #ifdef DUMP_INT21
|
pascal@11674
|
945 printf("int21: close fd=%d\n", (int)(r->ebx & 0xffff));
|
pascal@11674
|
946 #endif
|
pascal@11674
|
947 if (!fh) {
|
pascal@11674
|
948 set_error(r, 0x06); /* invalid handle */
|
pascal@11674
|
949 } else {
|
pascal@11674
|
950 close(fh->fd);
|
pascal@11674
|
951 fh->fd = -1;
|
pascal@11674
|
952 set_error(r, 0);
|
pascal@11674
|
953 }
|
pascal@11674
|
954 }
|
pascal@11674
|
955 break;
|
pascal@11674
|
956 case 0x3f: /* read */
|
pascal@11674
|
957 {
|
pascal@11674
|
958 DOSFile *fh = get_file(r->ebx & 0xffff);
|
pascal@11674
|
959 int n, ret;
|
pascal@11674
|
960
|
pascal@11674
|
961 if (!fh) {
|
pascal@11674
|
962 set_error(r, 0x06); /* invalid handle */
|
pascal@11674
|
963 } else {
|
pascal@11674
|
964 n = r->ecx & 0xffff;
|
pascal@11674
|
965 for(;;) {
|
pascal@11674
|
966 ret = read(fh->fd,
|
pascal@11674
|
967 seg_to_linear(r->ds, r->edx), n);
|
pascal@11674
|
968 if (ret < 0) {
|
pascal@11674
|
969 if (errno != EINTR && errno != EAGAIN)
|
pascal@11674
|
970 break;
|
pascal@11674
|
971 } else {
|
pascal@11674
|
972 break;
|
pascal@11674
|
973 }
|
pascal@11674
|
974 }
|
pascal@11674
|
975 #ifdef DUMP_INT21
|
pascal@11674
|
976 printf("int21: read: fd=%d n=%d ret=%d\n",
|
pascal@11674
|
977 (int)(r->ebx & 0xffff), n, ret);
|
pascal@11674
|
978 #endif
|
pascal@11674
|
979 if (ret < 0) {
|
pascal@11674
|
980 set_error(r, 0x05); /* acces denied */
|
pascal@11674
|
981 } else {
|
pascal@11674
|
982 r->eax = (r->eax & ~0xffff) | ret;
|
pascal@11674
|
983 set_error(r, 0);
|
pascal@11674
|
984 }
|
pascal@11674
|
985 }
|
pascal@11674
|
986 }
|
pascal@11674
|
987 break;
|
pascal@11674
|
988 case 0x40: /* write */
|
pascal@11674
|
989 {
|
pascal@11674
|
990 DOSFile *fh = get_file(r->ebx & 0xffff);
|
pascal@11674
|
991 int n, ret, pos;
|
pascal@11674
|
992
|
pascal@11674
|
993 if (!fh) {
|
pascal@11674
|
994 set_error(r, 0x06); /* invalid handle */
|
pascal@11674
|
995 } else {
|
pascal@11674
|
996 n = r->ecx & 0xffff;
|
pascal@11674
|
997 if (n == 0) {
|
pascal@11674
|
998 /* truncate */
|
pascal@11674
|
999 pos = lseek(fh->fd, 0, SEEK_CUR);
|
pascal@11674
|
1000 if (pos >= 0) {
|
pascal@11674
|
1001 ret = ftruncate(fh->fd, pos);
|
pascal@11674
|
1002 } else {
|
pascal@11674
|
1003 ret = -1;
|
pascal@11674
|
1004 }
|
pascal@11674
|
1005 } else {
|
pascal@11674
|
1006 for(;;) {
|
pascal@11674
|
1007 ret = write(fh->fd,
|
pascal@11674
|
1008 seg_to_linear(r->ds, r->edx), n);
|
pascal@11674
|
1009 if (ret < 0) {
|
pascal@11674
|
1010 if (errno != EINTR && errno != EAGAIN)
|
pascal@11674
|
1011 break;
|
pascal@11674
|
1012 } else {
|
pascal@11674
|
1013 break;
|
pascal@11674
|
1014 }
|
pascal@11674
|
1015 }
|
pascal@11674
|
1016 }
|
pascal@11674
|
1017 #ifdef DUMP_INT21
|
pascal@11674
|
1018 printf("int21: write: fd=%d n=%d ret=%d\n",
|
pascal@11674
|
1019 (int)(r->ebx & 0xffff), n, ret);
|
pascal@11674
|
1020 #endif
|
pascal@11674
|
1021 if (ret < 0) {
|
pascal@11674
|
1022 set_error(r, 0x05); /* acces denied */
|
pascal@11674
|
1023 } else {
|
pascal@11674
|
1024 r->eax = (r->eax & ~0xffff) | ret;
|
pascal@11674
|
1025 set_error(r, 0);
|
pascal@11674
|
1026 }
|
pascal@11674
|
1027 }
|
pascal@11674
|
1028 }
|
pascal@11674
|
1029 break;
|
pascal@11674
|
1030 case 0x41: /* unlink */
|
pascal@11674
|
1031 {
|
pascal@11674
|
1032 char filename[1024];
|
pascal@11674
|
1033 get_filename(r, filename, sizeof(filename));
|
pascal@11674
|
1034 if (unlink(filename) < 0) {
|
pascal@11674
|
1035 set_error(r, 0x02); /* file not found */
|
pascal@11674
|
1036 } else {
|
pascal@11674
|
1037 set_error(r, 0);
|
pascal@11674
|
1038 }
|
pascal@11674
|
1039 }
|
pascal@11674
|
1040 break;
|
pascal@11674
|
1041 case 0x42: /* lseek */
|
pascal@11674
|
1042 {
|
pascal@11674
|
1043 DOSFile *fh = get_file(r->ebx & 0xffff);
|
pascal@11674
|
1044 int pos, ret;
|
pascal@11674
|
1045
|
pascal@11674
|
1046 if (!fh) {
|
pascal@11674
|
1047 set_error(r, 0x06); /* invalid handle */
|
pascal@11674
|
1048 } else {
|
pascal@11674
|
1049 pos = ((r->ecx & 0xffff) << 16) | (r->edx & 0xffff);
|
pascal@11674
|
1050 ret = lseek(fh->fd, pos, r->eax & 0xff);
|
pascal@11674
|
1051 #ifdef DUMP_INT21
|
pascal@11674
|
1052 printf("int21: lseek: fd=%d pos=%d whence=%d ret=%d\n",
|
pascal@11674
|
1053 (int)(r->ebx & 0xffff), pos, (uint8_t)r->eax, ret);
|
pascal@11674
|
1054 #endif
|
pascal@11674
|
1055 if (ret < 0) {
|
pascal@11674
|
1056 set_error(r, 0x01); /* function number invalid */
|
pascal@11674
|
1057 } else {
|
pascal@11674
|
1058 r->edx = (r->edx & ~0xffff) | ((unsigned)ret >> 16);
|
pascal@11674
|
1059 r->eax = (r->eax & ~0xffff) | (ret & 0xffff);
|
pascal@11674
|
1060 set_error(r, 0);
|
pascal@11674
|
1061 }
|
pascal@11674
|
1062 }
|
pascal@11674
|
1063 }
|
pascal@11674
|
1064 break;
|
pascal@11674
|
1065 case 0x44: /* ioctl */
|
pascal@11674
|
1066 switch(r->eax & 0xff) {
|
pascal@11674
|
1067 case 0x00: /* get device information */
|
pascal@11674
|
1068 {
|
pascal@11674
|
1069 DOSFile *fh = get_file(r->ebx & 0xffff);
|
pascal@11674
|
1070 int ret;
|
pascal@11674
|
1071
|
pascal@11674
|
1072 if (!fh) {
|
pascal@11674
|
1073 set_error(r, 0x06); /* invalid handle */
|
pascal@11674
|
1074 } else {
|
pascal@11674
|
1075 ret = 0;
|
pascal@11674
|
1076 if (isatty(fh->fd)) {
|
pascal@11674
|
1077 ret |= 0x80;
|
pascal@11674
|
1078 if (fh->fd == 0)
|
pascal@11674
|
1079 ret |= (1 << 0);
|
pascal@11674
|
1080 else
|
pascal@11674
|
1081 ret |= (1 << 1);
|
pascal@11674
|
1082 }
|
pascal@11674
|
1083 r->edx = (r->edx & ~0xffff) | ret;
|
pascal@11674
|
1084 set_error(r, 0);
|
pascal@11674
|
1085 }
|
pascal@11674
|
1086 }
|
pascal@11674
|
1087 break;
|
pascal@11674
|
1088 default:
|
pascal@11674
|
1089 goto unsupported;
|
pascal@11674
|
1090 }
|
pascal@11674
|
1091 break;
|
pascal@11674
|
1092 case 0x48: /* allocate memory */
|
pascal@11674
|
1093 {
|
pascal@11674
|
1094 int ret, max_size;
|
pascal@11674
|
1095 #ifdef DUMP_INT21
|
pascal@11674
|
1096 printf("int21: allocate memory: size=0x%04x\n", (uint16_t)r->ebx);
|
pascal@11674
|
1097 #endif
|
pascal@11674
|
1098 ret = mem_malloc(r->ebx & 0xffff, &max_size);
|
pascal@11674
|
1099 if (ret < 0) {
|
pascal@11674
|
1100 set_error(r, 0x08); /* insufficient memory*/
|
pascal@11674
|
1101 } else {
|
pascal@11674
|
1102 r->eax = (r->eax & ~0xffff) | ret;
|
pascal@11674
|
1103 r->ebx = (r->ebx & ~0xffff) | max_size;
|
pascal@11674
|
1104 set_error(r, 0);
|
pascal@11674
|
1105 }
|
pascal@11674
|
1106 }
|
pascal@11674
|
1107 break;
|
pascal@11674
|
1108 case 0x49: /* free memory */
|
pascal@11674
|
1109 {
|
pascal@11674
|
1110 #ifdef DUMP_INT21
|
pascal@11674
|
1111 printf("int21: free memory: block=0x%04x\n", r->es);
|
pascal@11674
|
1112 #endif
|
pascal@11674
|
1113 if (mem_free(r->es) < 0) {
|
pascal@11674
|
1114 set_error(r, 0x09); /* memory block address invalid */
|
pascal@11674
|
1115 } else {
|
pascal@11674
|
1116 set_error(r, 0);
|
pascal@11674
|
1117 }
|
pascal@11674
|
1118 }
|
pascal@11674
|
1119 break;
|
pascal@11674
|
1120 case 0x4a: /* resize memory block */
|
pascal@11674
|
1121 {
|
pascal@11674
|
1122 int ret;
|
pascal@11674
|
1123 #ifdef DUMP_INT21
|
pascal@11674
|
1124 printf("int21: resize memory block: block=0x%04x size=0x%04x\n",
|
pascal@11674
|
1125 r->es, (uint16_t)r->ebx);
|
pascal@11674
|
1126 #endif
|
pascal@11674
|
1127 ret = mem_resize(r->es, r->ebx & 0xffff);
|
pascal@11674
|
1128 if (ret < 0) {
|
pascal@11674
|
1129 set_error(r, 0x08); /* insufficient memory*/
|
pascal@11674
|
1130 } else {
|
pascal@11674
|
1131 r->ebx = (r->ebx & ~0xffff) | ret;
|
pascal@11674
|
1132 set_error(r, 0);
|
pascal@11674
|
1133 }
|
pascal@11674
|
1134 }
|
pascal@11674
|
1135 break;
|
pascal@11674
|
1136 case 0x4b: /* load program */
|
pascal@11674
|
1137 {
|
pascal@11674
|
1138 char filename[1024];
|
pascal@11674
|
1139 ExecParamBlock *blk;
|
pascal@11674
|
1140 int ret;
|
pascal@11674
|
1141
|
pascal@11674
|
1142 if ((r->eax & 0xff) != 0x01) /* only load */
|
pascal@11674
|
1143 goto unsupported;
|
pascal@11674
|
1144 get_filename(r, filename, sizeof(filename));
|
pascal@11674
|
1145 blk = (ExecParamBlock *)seg_to_linear(r->es, r->ebx);
|
pascal@11674
|
1146 ret = load_com(blk, filename, NULL, 0, NULL);
|
pascal@11674
|
1147 if (ret < 0) {
|
pascal@11674
|
1148 set_error(r, 0x02); /* file not found */
|
pascal@11674
|
1149 } else {
|
pascal@11674
|
1150 cur_psp = ret;
|
pascal@11674
|
1151 set_error(r, 0);
|
pascal@11674
|
1152 }
|
pascal@11674
|
1153 }
|
pascal@11674
|
1154 break;
|
pascal@11674
|
1155 case 0x4c: /* exit with return code */
|
pascal@11674
|
1156 exit(r->eax & 0xff);
|
pascal@11674
|
1157 break;
|
pascal@11674
|
1158 case 0x50: /* set PSP address */
|
pascal@11674
|
1159 #ifdef DUMP_INT21
|
pascal@11674
|
1160 printf("int21: set PSP: 0x%04x\n", (uint16_t)r->ebx);
|
pascal@11674
|
1161 #endif
|
pascal@11674
|
1162 cur_psp = r->ebx;
|
pascal@11674
|
1163 break;
|
pascal@11674
|
1164 case 0x51: /* get PSP address */
|
pascal@11674
|
1165 #ifdef DUMP_INT21
|
pascal@11674
|
1166 printf("int21: get PSP: ret=0x%04x\n", cur_psp);
|
pascal@11674
|
1167 #endif
|
pascal@11674
|
1168 r->ebx = (r->ebx & ~0xffff) | cur_psp;
|
pascal@11674
|
1169 break;
|
pascal@11674
|
1170 case 0x55: /* create child PSP */
|
pascal@11674
|
1171 {
|
pascal@11674
|
1172 uint8_t *psp_ptr;
|
pascal@11674
|
1173 #ifdef DUMP_INT21
|
pascal@11674
|
1174 printf("int21: create child PSP: psp=0x%04x last_seg=0x%04x\n",
|
pascal@11674
|
1175 (uint16_t)r->edx, (uint16_t)r->esi);
|
pascal@11674
|
1176 #endif
|
pascal@11674
|
1177 psp_ptr = seg_to_linear(r->edx & 0xffff, 0);
|
pascal@11674
|
1178 memset(psp_ptr, 0, 0x80);
|
pascal@11674
|
1179 psp_ptr[0] = 0xcd; /* int $0x20 */
|
pascal@11674
|
1180 psp_ptr[1] = 0x20;
|
pascal@11674
|
1181 *(uint16_t *)(psp_ptr + 2) = r->esi;
|
pascal@11674
|
1182 r->eax = (r->eax & ~0xff);
|
pascal@11674
|
1183 }
|
pascal@11674
|
1184 break;
|
pascal@11674
|
1185 default:
|
pascal@11674
|
1186 unsupported:
|
pascal@11674
|
1187 unsupported_function(r, 0x21, ah);
|
pascal@11674
|
1188 }
|
pascal@11674
|
1189 }
|
pascal@11674
|
1190
|
pascal@11674
|
1191 void do_int29(struct vm86_regs *r)
|
pascal@11674
|
1192 {
|
pascal@11674
|
1193 uint8_t c = r->eax;
|
pascal@11674
|
1194 write(1, &c, 1);
|
pascal@11674
|
1195 }
|
pascal@11674
|
1196
|
pascal@11674
|
1197 void raise_interrupt(int number)
|
pascal@11674
|
1198 {
|
pascal@11674
|
1199 if (* (uint32_t *) seg_to_linear(0, number * 4) == 0)
|
pascal@11674
|
1200 return;
|
pascal@11674
|
1201 // FIXME VM86_SIGNAL
|
pascal@11674
|
1202 }
|
pascal@11674
|
1203
|
pascal@11674
|
1204 void biosclock()
|
pascal@11674
|
1205 {
|
pascal@11674
|
1206 uint32_t *timer = (uint32_t *) seg_to_linear(0, 0x46C);
|
pascal@11674
|
1207 ++*timer;
|
pascal@11674
|
1208 raise_interrupt(8);
|
pascal@11674
|
1209 raise_interrupt(0x1C);
|
pascal@11674
|
1210 }
|
pascal@11674
|
1211
|
pascal@11674
|
1212 int main(int argc, char **argv)
|
pascal@11674
|
1213 {
|
pascal@11674
|
1214 uint8_t *vm86_mem;
|
pascal@11674
|
1215 const char *filename;
|
pascal@11674
|
1216 int ret;
|
pascal@11674
|
1217 uint32_t file_size;
|
pascal@11674
|
1218 struct sigaction sa;
|
pascal@11674
|
1219 struct itimerval timerval;
|
pascal@11674
|
1220 struct vm86plus_struct ctx;
|
pascal@11674
|
1221 struct vm86_regs *r;
|
pascal@11674
|
1222 ExecParamBlock blk1, *blk = &blk1;
|
pascal@11674
|
1223
|
pascal@11674
|
1224 if (argc < 2)
|
pascal@11674
|
1225 usage();
|
pascal@11674
|
1226 filename = argv[1];
|
pascal@11674
|
1227
|
pascal@11674
|
1228 vm86_mem = mmap((void *)0x00000000, 0x110000,
|
pascal@11674
|
1229 PROT_WRITE | PROT_READ | PROT_EXEC,
|
pascal@11674
|
1230 MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
|
pascal@11674
|
1231 if (vm86_mem == MAP_FAILED) {
|
pascal@11674
|
1232 perror("mmap");
|
pascal@11674
|
1233 exit(1);
|
pascal@11674
|
1234 }
|
pascal@11674
|
1235
|
pascal@11674
|
1236 memset(&ctx, 0, sizeof(ctx));
|
pascal@11674
|
1237 r = &ctx.regs;
|
pascal@11674
|
1238 set_bit((uint8_t *)&ctx.int_revectored, 0x10);
|
pascal@11674
|
1239 set_bit((uint8_t *)&ctx.int_revectored, 0x13);
|
pascal@11674
|
1240 set_bit((uint8_t *)&ctx.int_revectored, 0x15);
|
pascal@11674
|
1241 set_bit((uint8_t *)&ctx.int_revectored, 0x16);
|
pascal@11674
|
1242 set_bit((uint8_t *)&ctx.int_revectored, 0x1a);
|
pascal@11674
|
1243 set_bit((uint8_t *)&ctx.int_revectored, 0x20);
|
pascal@11674
|
1244 set_bit((uint8_t *)&ctx.int_revectored, 0x21);
|
pascal@11674
|
1245 set_bit((uint8_t *)&ctx.int_revectored, 0x29);
|
pascal@11674
|
1246
|
pascal@11674
|
1247 dos_init();
|
pascal@11674
|
1248
|
pascal@11674
|
1249 if (strstr(filename,".com") || strstr(filename,".exe") ||
|
pascal@11674
|
1250 strstr(filename,".COM") || strstr(filename,".EXE")) {
|
pascal@11674
|
1251 ret = load_com(blk, filename, &file_size, argc, argv);
|
pascal@11674
|
1252 if (ret < 0) {
|
pascal@11674
|
1253 perror(filename);
|
pascal@11674
|
1254 exit(1);
|
pascal@11674
|
1255 }
|
pascal@11674
|
1256 cur_psp = ret;
|
pascal@11674
|
1257
|
pascal@11674
|
1258 /* init basic registers */
|
pascal@11674
|
1259 r->eip = blk->ip;
|
pascal@11674
|
1260 r->esp = blk->sp + 2; /* pop ax value */
|
pascal@11674
|
1261 r->cs = blk->cs;
|
pascal@11674
|
1262 r->ss = blk->ss;
|
pascal@11674
|
1263 r->ds = cur_psp;
|
pascal@11674
|
1264 r->es = cur_psp;
|
pascal@11674
|
1265 r->eflags = VIF_MASK;
|
pascal@11674
|
1266
|
pascal@11674
|
1267 /* the value of these registers seem to be assumed by pi_10.com */
|
pascal@11674
|
1268 r->esi = 0x100;
|
pascal@11674
|
1269 #if 0
|
pascal@11674
|
1270 r->ebx = file_size >> 16;
|
pascal@11674
|
1271 r->ecx = file_size & 0xffff;
|
pascal@11674
|
1272 #else
|
pascal@11674
|
1273 r->ecx = 0xff;
|
pascal@11674
|
1274 #endif
|
pascal@11674
|
1275 r->ebp = 0x0900;
|
pascal@11674
|
1276 r->edi = 0xfffe;
|
pascal@11674
|
1277 }
|
pascal@11674
|
1278 else {
|
pascal@11674
|
1279 if (load_boot(filename, r) < 0) {
|
pascal@11674
|
1280 if (errno)
|
pascal@11674
|
1281 perror(filename);
|
pascal@11674
|
1282 exit(1);
|
pascal@11674
|
1283 }
|
pascal@11674
|
1284 }
|
pascal@11674
|
1285
|
pascal@11674
|
1286 sa.sa_handler = biosclock;
|
pascal@11674
|
1287 sigemptyset(&sa.sa_mask);
|
pascal@11674
|
1288 sa.sa_flags = SA_RESTART;
|
pascal@11674
|
1289 if (sigaction(SIGALRM, &sa, 0) == 0) {
|
pascal@11674
|
1290 timerval.it_interval.tv_sec = timerval.it_value.tv_sec = 0;
|
pascal@11674
|
1291 timerval.it_interval.tv_usec = timerval.it_value.tv_usec = 10000000 / 182;
|
pascal@11674
|
1292 setitimer (ITIMER_REAL, &timerval, NULL);
|
pascal@11674
|
1293 }
|
pascal@11674
|
1294
|
pascal@11674
|
1295 for(;;) {
|
pascal@11674
|
1296 ret = vm86(VM86_ENTER, &ctx);
|
pascal@11674
|
1297 switch(VM86_TYPE(ret)) {
|
pascal@11674
|
1298 case VM86_INTx:
|
pascal@11674
|
1299 {
|
pascal@11674
|
1300 int int_num;
|
pascal@11674
|
1301
|
pascal@11674
|
1302 int_num = VM86_ARG(ret);
|
pascal@11674
|
1303 switch(int_num) {
|
pascal@11674
|
1304 case 0x10:
|
pascal@11674
|
1305 do_int10(r);
|
pascal@11674
|
1306 break;
|
pascal@11674
|
1307 case 0x13:
|
pascal@11674
|
1308 do_int13(r);
|
pascal@11674
|
1309 break;
|
pascal@11674
|
1310 case 0x15:
|
pascal@11674
|
1311 do_int15(r);
|
pascal@11674
|
1312 break;
|
pascal@11674
|
1313 case 0x16:
|
pascal@11674
|
1314 do_int16(r);
|
pascal@11674
|
1315 break;
|
pascal@11674
|
1316 case 0x1a:
|
pascal@11674
|
1317 do_int1a(r);
|
pascal@11674
|
1318 break;
|
pascal@11674
|
1319 case 0x20:
|
pascal@11674
|
1320 do_int20(r);
|
pascal@11674
|
1321 break;
|
pascal@11674
|
1322 case 0x21:
|
pascal@11674
|
1323 do_int21(r);
|
pascal@11674
|
1324 break;
|
pascal@11674
|
1325 case 0x29:
|
pascal@11674
|
1326 do_int29(r);
|
pascal@11674
|
1327 break;
|
pascal@11674
|
1328 default:
|
pascal@11674
|
1329 fprintf(stderr, "unsupported int 0x%02x\n", int_num);
|
pascal@11674
|
1330 dump_regs(&ctx.regs);
|
pascal@11674
|
1331 break;
|
pascal@11674
|
1332 }
|
pascal@11674
|
1333 }
|
pascal@11674
|
1334 break;
|
pascal@11674
|
1335 case VM86_SIGNAL:
|
pascal@11674
|
1336 /* a signal came, we just ignore that */
|
pascal@11674
|
1337 break;
|
pascal@11674
|
1338 case VM86_STI:
|
pascal@11674
|
1339 break;
|
pascal@11674
|
1340 case VM86_TRAP:
|
pascal@11674
|
1341 /* just executes the interruption */
|
pascal@11674
|
1342 {
|
pascal@11674
|
1343 uint16_t *int_vector;
|
pascal@11674
|
1344 uint32_t eflags;
|
pascal@11674
|
1345
|
pascal@11674
|
1346 eflags = r->eflags & ~IF_MASK;
|
pascal@11674
|
1347 if (r->eflags & VIF_MASK)
|
pascal@11674
|
1348 eflags |= IF_MASK;
|
pascal@11674
|
1349 pushw(r, eflags);
|
pascal@11674
|
1350 pushw(r, r->cs);
|
pascal@11674
|
1351 pushw(r, r->eip);
|
pascal@11674
|
1352 int_vector = (uint16_t *)seg_to_linear(0, VM86_ARG(ret) * 4);
|
pascal@11674
|
1353 r->eip = int_vector[0];
|
pascal@11674
|
1354 r->cs = int_vector[1];
|
pascal@11674
|
1355 r->eflags &= ~(VIF_MASK | TF_MASK | AC_MASK);
|
pascal@11674
|
1356 }
|
pascal@11674
|
1357 break;
|
pascal@11674
|
1358 default:
|
pascal@11674
|
1359 fprintf(stderr, "unhandled vm86 return code (0x%x)\n", ret);
|
pascal@11674
|
1360 dump_regs(&ctx.regs);
|
pascal@11674
|
1361 exit(1);
|
pascal@11674
|
1362 }
|
pascal@11674
|
1363 }
|
pascal@11674
|
1364 }
|