wok-next diff runcom/stuff/runcom.c @ rev 12514
Up: xorg-libXinerama (1.1.2)
author | Christophe Lincoln <pankso@slitaz.org> |
---|---|
date | Tue Apr 24 23:59:55 2012 +0200 (2012-04-24) |
parents | |
children | b6347c31b319 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/runcom/stuff/runcom.c Tue Apr 24 23:59:55 2012 +0200 1.3 @@ -0,0 +1,1364 @@ 1.4 +/* 1.5 + * Simple example of use of vm86: launch a basic .com DOS executable 1.6 + */ 1.7 +#include <stdlib.h> 1.8 +#include <stdio.h> 1.9 +#include <string.h> 1.10 +#include <inttypes.h> 1.11 +#include <unistd.h> 1.12 +#include <fcntl.h> 1.13 +#include <time.h> 1.14 +#include <sys/mman.h> 1.15 +#include <sys/ioctl.h> 1.16 +#include <sys/time.h> 1.17 +#include <sys/types.h> 1.18 +#include <sys/stat.h> 1.19 +#include <signal.h> 1.20 +#include <errno.h> 1.21 +#include <ctype.h> 1.22 +#include <termios.h> 1.23 + 1.24 +#include <sys/syscall.h> 1.25 +#include <asm/vm86.h> 1.26 + 1.27 +//#define DUMP_INT21 1.28 + 1.29 +static inline int vm86(int func, struct vm86plus_struct *v86) 1.30 +{ 1.31 + return syscall(__NR_vm86, func, v86); 1.32 +} 1.33 + 1.34 +#define CF_MASK 0x00000001 1.35 +#define ZF_MASK 0x00000040 1.36 +#define TF_MASK 0x00000100 1.37 +#define IF_MASK 0x00000200 1.38 +#define DF_MASK 0x00000400 1.39 +#define IOPL_MASK 0x00003000 1.40 +#define NT_MASK 0x00004000 1.41 +#define RF_MASK 0x00010000 1.42 +#define VM_MASK 0x00020000 1.43 +#define AC_MASK 0x00040000 1.44 +#define VIF_MASK 0x00080000 1.45 +#define VIP_MASK 0x00100000 1.46 +#define ID_MASK 0x00200000 1.47 + 1.48 +void usage(void) 1.49 +{ 1.50 + printf("runcom version 0.2-slitaz (c) 2003-2011 Fabrice Bellard\n" 1.51 + "usage: runcom file.com [args...]\n" 1.52 + "Run simple .com DOS executables (linux vm86 test mode)\n"); 1.53 + exit(1); 1.54 +} 1.55 + 1.56 +static inline void set_bit(uint8_t *a, unsigned int bit) 1.57 +{ 1.58 + a[bit / 8] |= (1 << (bit % 8)); 1.59 +} 1.60 + 1.61 +static inline uint8_t *seg_to_linear(unsigned int seg, unsigned int reg) 1.62 +{ 1.63 + return (uint8_t *)((seg << 4) + (reg & 0xffff)); 1.64 +} 1.65 + 1.66 +static inline void pushw(struct vm86_regs *r, int val) 1.67 +{ 1.68 + r->esp = (r->esp & ~0xffff) | ((r->esp - 2) & 0xffff); 1.69 + *(uint16_t *)seg_to_linear(r->ss, r->esp) = val; 1.70 +} 1.71 + 1.72 +void dump_regs(struct vm86_regs *r) 1.73 +{ 1.74 + int i; 1.75 + uint8_t *p8; 1.76 + uint16_t *p16; 1.77 + fprintf(stderr, 1.78 + "EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx\n" 1.79 + "ESI=%08lx EDI=%08lx EBP=%08lx ESP=%08lx\n" 1.80 + "EIP=%08lx EFL=%08lx " 1.81 + "CS=%04x DS=%04x ES=%04x SS=%04x FS=%04x GS=%04x\n[SP]", 1.82 + r->eax, r->ebx, r->ecx, r->edx, r->esi, r->edi, r->ebp, r->esp, 1.83 + r->eip, r->eflags, 1.84 + r->cs, r->ds, r->es, r->ss, r->fs, r->gs); 1.85 + for (p16 = (uint16_t *) seg_to_linear(r->ss, r->esp), i = 0; i < 15; i++) 1.86 + fprintf(stderr," %04x", *p16++); 1.87 + fprintf(stderr,"\n[IP]"); 1.88 + for (p8 = seg_to_linear(r->cs, r->eip), i = 0; i < 25; i++) 1.89 + fprintf(stderr," %02x", *p8++); 1.90 + fprintf(stderr,"\n"); 1.91 +} 1.92 + 1.93 +#define DOS_FD_MAX 256 1.94 +typedef struct { 1.95 + int fd; /* -1 means closed */ 1.96 +} DOSFile; 1.97 + 1.98 +DOSFile dos_files[DOS_FD_MAX]; 1.99 +uint16_t cur_psp; 1.100 + 1.101 +void dos_init(void) 1.102 +{ 1.103 + int i; 1.104 + for(i = 0; i < DOS_FD_MAX; i++) 1.105 + dos_files[i].fd = (i < 3) ? i : -1; 1.106 +} 1.107 + 1.108 +static inline void set_error(struct vm86_regs *r, int val) 1.109 +{ 1.110 + r->eflags &= ~CF_MASK; 1.111 + if (val) { 1.112 + r->eax = (r->eax & ~0xffff) | val; 1.113 + r->eflags |= CF_MASK; 1.114 + } 1.115 +} 1.116 +static DOSFile *get_file(int h) 1.117 +{ 1.118 + DOSFile *fh; 1.119 + 1.120 + if (h < DOS_FD_MAX) { 1.121 + fh = &dos_files[h]; 1.122 + if (fh->fd != -1) 1.123 + return fh; 1.124 + } 1.125 + return NULL; 1.126 +} 1.127 + 1.128 +/* return -1 if error */ 1.129 +static int get_new_handle(void) 1.130 +{ 1.131 + DOSFile *fh; 1.132 + int i; 1.133 + 1.134 + for(i = 0; i < DOS_FD_MAX; i++) { 1.135 + fh = &dos_files[i]; 1.136 + if (fh->fd == -1) 1.137 + return i; 1.138 + } 1.139 + return -1; 1.140 +} 1.141 + 1.142 +static char *get_filename1(struct vm86_regs *r, char *buf, int buf_size, 1.143 + uint16_t seg, uint16_t offset) 1.144 +{ 1.145 + char *q; 1.146 + int c; 1.147 + q = buf; 1.148 + for(;;) { 1.149 + c = *seg_to_linear(seg, offset); 1.150 + if (c == 0) 1.151 + break; 1.152 + if (q >= buf + buf_size - 1) 1.153 + break; 1.154 + c = tolower(c); 1.155 + if (c == '\\') 1.156 + c = '/'; 1.157 + *q++ = c; 1.158 + offset++; 1.159 + } 1.160 + *q = '\0'; 1.161 + return buf; 1.162 +} 1.163 + 1.164 +static char *get_filename(struct vm86_regs *r, char *buf, int buf_size) 1.165 +{ 1.166 + return get_filename1(r, buf, buf_size, r->ds, r->edx & 0xffff); 1.167 +} 1.168 + 1.169 +typedef struct __attribute__((packed)) { 1.170 + uint8_t drive_num; 1.171 + uint8_t file_name[8]; 1.172 + uint8_t file_ext[3]; 1.173 + uint16_t current_block; 1.174 + uint16_t logical_record_size; 1.175 + uint32_t file_size; 1.176 + uint16_t date; 1.177 + uint16_t time; 1.178 + uint8_t reserved[8]; 1.179 + uint8_t record_in_block; 1.180 + uint32_t record_num; 1.181 +} FCB; 1.182 + 1.183 +typedef struct __attribute__((packed)) { 1.184 + uint16_t environ; 1.185 + uint16_t cmdtail_off; 1.186 + uint16_t cmdtail_seg; 1.187 + uint32_t fcb1; 1.188 + uint32_t fcb2; 1.189 + uint16_t sp, ss; 1.190 + uint16_t ip, cs; 1.191 +} ExecParamBlock; 1.192 + 1.193 +typedef struct MemBlock { 1.194 + struct MemBlock *next; 1.195 + uint16_t seg; 1.196 + uint16_t size; /* in paragraphs */ 1.197 +} MemBlock; 1.198 + 1.199 +/* first allocated paragraph */ 1.200 +MemBlock *first_mem_block = NULL; 1.201 + 1.202 +#define MEM_START 0x1000 1.203 +#define MEM_END 0xa000 1.204 + 1.205 +/* return -1 if error */ 1.206 +int mem_malloc(int size, int *pmax_size) 1.207 +{ 1.208 + MemBlock *m, **pm; 1.209 + int seg_free, seg; 1.210 + 1.211 + /* XXX: this is totally inefficient, but we have only 1 or 2 1.212 + blocks ! */ 1.213 + seg_free = MEM_START; 1.214 + for(pm = &first_mem_block; *pm != NULL; pm = &(*pm)->next) { 1.215 + m = *pm; 1.216 + seg = m->seg + m->size; 1.217 + if (seg > seg_free) 1.218 + seg_free = seg; 1.219 + } 1.220 + if ((seg_free + size) > MEM_END) 1.221 + return -1; 1.222 + if (pmax_size) 1.223 + *pmax_size = MEM_END - seg_free; 1.224 + /* add at the end */ 1.225 + m = malloc(sizeof(MemBlock)); 1.226 + *pm = m; 1.227 + m->next = NULL; 1.228 + m->seg = seg_free; 1.229 + m->size = size; 1.230 +#ifdef DUMP_INT21 1.231 + printf("mem_malloc size=0x%04x: 0x%04x\n", size, seg_free); 1.232 +#endif 1.233 + return seg_free; 1.234 +} 1.235 + 1.236 +/* return -1 if error */ 1.237 +int mem_free(int seg) 1.238 +{ 1.239 + MemBlock *m, **pm; 1.240 + for(pm = &first_mem_block; *pm != NULL; pm = &(*pm)->next) { 1.241 + m = *pm; 1.242 + if (m->seg == seg) { 1.243 + *pm = m->next; 1.244 + free(m); 1.245 + return 0; 1.246 + } 1.247 + } 1.248 + return -1; 1.249 +} 1.250 + 1.251 +/* return -1 if error or the maxmium size */ 1.252 +int mem_resize(int seg, int new_size) 1.253 +{ 1.254 + MemBlock *m, **pm, *m1; 1.255 + int max_size; 1.256 + 1.257 + for(pm = &first_mem_block; *pm != NULL; pm = &(*pm)->next) { 1.258 + m = *pm; 1.259 + if (m->seg == seg) { 1.260 + m1 = m->next; 1.261 + if (!m1) 1.262 + max_size = MEM_END - m->seg; 1.263 + else 1.264 + max_size = m1->seg - m->seg; 1.265 + if (new_size > max_size) 1.266 + return -1; 1.267 + m->size = new_size; 1.268 + return max_size; 1.269 + } 1.270 + } 1.271 + return -1; 1.272 +} 1.273 + 1.274 +int load_boot(const char *filename, struct vm86_regs *r) 1.275 +{ 1.276 + int fd, ret; 1.277 + 1.278 + /* load the boot sector */ 1.279 + fd = open(filename, O_RDONLY); 1.280 + if (fd >= 0) { 1.281 + *seg_to_linear(0x0, 0x7dff) = 0; 1.282 + r->eax = 0x200; 1.283 + r->ebx = r->esp = r->eip = 0x7c00; 1.284 + r->ecx = 1; 1.285 + r->esi = r->edi = r->ebp = 1.286 + r->edx = 0; /* floppy disk */ 1.287 + r->cs = r->ss = r->ds = r->es = 0; 1.288 + r->eflags = VIF_MASK; 1.289 + ret = read(fd, seg_to_linear(0x0, 0x7c00), 0x200); 1.290 + if (lseek(fd, 0, SEEK_END) > 4*1024*1024) 1.291 + r->edx = 0x80; /* hard disk */ 1.292 + close(fd); 1.293 + if (ret != 0x200 || 1.294 + *seg_to_linear(0x0, 0x7dfe) != 0x55 || 1.295 + *seg_to_linear(0x0, 0x7dff) != 0xaa) { 1.296 + fprintf(stderr,"No boot sector.\n"); 1.297 + fd = -1; 1.298 + } 1.299 + } 1.300 + return fd; 1.301 +} 1.302 + 1.303 +/* return the PSP or -1 if error */ 1.304 +int load_exe(ExecParamBlock *blk, const char *filename, 1.305 + int psp, uint32_t *pfile_size) 1.306 +{ 1.307 + int fd, size, base; 1.308 + struct { 1.309 + uint16_t signature; // 0x5A4D 'MZ' 1.310 + uint16_t bytes_in_last_block; 1.311 + uint16_t blocks_in_file; 1.312 + uint16_t num_relocs; 1.313 + uint16_t header_paragraphs; // Size of header 1.314 + uint16_t min_extra_paragraphs; // BSS size 1.315 + uint16_t max_extra_paragraphs; 1.316 + uint16_t ss; // Initial (relative) SS value 1.317 + uint16_t sp; // Initial SP value 1.318 + uint16_t checksum; 1.319 + uint16_t ip; // Initial IP value 1.320 + uint16_t cs; // Initial (relative) CS value 1.321 + uint16_t reloc_table_offset; 1.322 + uint16_t overlay_number; 1.323 + } header; 1.324 + struct { 1.325 + uint16_t offset; 1.326 + uint16_t segment; 1.327 + } rel; 1.328 + 1.329 + /* load the MSDOS .exe executable */ 1.330 + fd = open(filename, O_RDONLY); 1.331 + if (fd < 0) { 1.332 + return -1; 1.333 + } 1.334 + if (read(fd, &header, sizeof(header)) != sizeof(header)) { 1.335 + close(fd); 1.336 + return -1; 1.337 + } 1.338 + 1.339 + memset(seg_to_linear(psp, 0x100), 0, 65536 - 0x100); 1.340 + 1.341 + size = (header.blocks_in_file * 512) - (header.header_paragraphs * 16) + 1.342 + (header.bytes_in_last_block ? header.bytes_in_last_block - 512 : 0); 1.343 + header.min_extra_paragraphs += (size-1)/16; 1.344 + 1.345 + /* address of last segment allocated */ 1.346 + *(uint16_t *)seg_to_linear(psp, 2) = psp + header.min_extra_paragraphs; 1.347 + 1.348 + if (pfile_size) 1.349 + *pfile_size = size; 1.350 + 1.351 + if (mem_resize(psp, header.min_extra_paragraphs) < 0 || 1.352 + lseek(fd, header.header_paragraphs * 16, SEEK_SET) < 0 || 1.353 + read(fd, seg_to_linear(psp, 0x100), size) != size || 1.354 + lseek(fd, header.reloc_table_offset, SEEK_SET) < 0) { 1.355 + close(fd); 1.356 + return -1; 1.357 + } 1.358 + 1.359 + base = psp + 16; 1.360 + while (header.num_relocs-- && read(fd, &rel, sizeof(rel)) == sizeof(rel)) 1.361 + if (rel.segment != 0 || rel.offset != 0) 1.362 + * (uint16_t *) seg_to_linear(base + rel.segment, rel.offset) += base; 1.363 + close(fd); 1.364 + 1.365 + blk->cs = base + header.cs; 1.366 + blk->ip = header.ip; 1.367 + blk->ss = base + header.ss; 1.368 + blk->sp = header.sp - 6; 1.369 + 1.370 + /* push return far address */ 1.371 + *(uint16_t *)seg_to_linear(blk->ss, blk->sp + 4) = psp; 1.372 + 1.373 + return psp; 1.374 +} 1.375 + 1.376 +/* return the PSP or -1 if error */ 1.377 +int load_com(ExecParamBlock *blk, const char *filename, uint32_t *pfile_size, 1.378 + int argc, char **argv) 1.379 +{ 1.380 + int psp, fd, ret; 1.381 + 1.382 + /* load the MSDOS .com executable */ 1.383 + fd = open(filename, O_RDONLY); 1.384 + if (fd < 0) { 1.385 + return -1; 1.386 + } 1.387 + psp = mem_malloc(65536 / 16, NULL); 1.388 + ret = read(fd, seg_to_linear(psp, 0x100), 65536 - 0x100); 1.389 + close(fd); 1.390 + if (ret <= 0) { 1.391 + mem_free(psp); 1.392 + return -1; 1.393 + } 1.394 + if (pfile_size) 1.395 + *pfile_size = ret; 1.396 + 1.397 + /* reset the PSP */ 1.398 + memset(seg_to_linear(psp, 0), 0, 0x100); 1.399 + 1.400 + *seg_to_linear(psp, 0) = 0xcd; /* int $0x20 */ 1.401 + *seg_to_linear(psp, 1) = 0x20; 1.402 + /* address of last segment allocated */ 1.403 + *(uint16_t *)seg_to_linear(psp, 2) = psp + 0xfff; 1.404 + 1.405 + if (argc) { 1.406 + int i, p; 1.407 + char *s; 1.408 + /* set the command line */ 1.409 + p = 0x81; 1.410 + for(i = 2; i < argc; i++) { 1.411 + if (p >= 0xff) 1.412 + break; 1.413 + *seg_to_linear(psp, p++) = ' '; 1.414 + s = argv[i]; 1.415 + while (*s) { 1.416 + if (p >= 0xff) 1.417 + break; 1.418 + *seg_to_linear(psp, p++) = *s++; 1.419 + } 1.420 + } 1.421 + *seg_to_linear(psp, p) = '\r'; 1.422 + *seg_to_linear(psp, 0x80) = p - 0x81; 1.423 + } 1.424 + else { 1.425 + int len; 1.426 + /* copy the command line */ 1.427 + len = *seg_to_linear(blk->cmdtail_seg, blk->cmdtail_off); 1.428 + memcpy(seg_to_linear(psp, 0x80), 1.429 + seg_to_linear(blk->cmdtail_seg, blk->cmdtail_off), len + 2); 1.430 + } 1.431 + 1.432 + blk->sp = 0xfffc; 1.433 + blk->ip = 0x100; 1.434 + blk->cs = blk->ss = psp; 1.435 + 1.436 + if (*(uint16_t *)seg_to_linear(psp, 0x100) == 0x5A4D) 1.437 + psp = load_exe(blk, filename, psp, pfile_size); 1.438 + 1.439 + /* push ax value */ 1.440 + *(uint16_t *)seg_to_linear(blk->ss, blk->sp) = 0; 1.441 + /* push return address to 0 */ 1.442 + *(uint16_t *)seg_to_linear(blk->ss, blk->sp + 2) = 0; 1.443 + 1.444 + return psp; 1.445 +} 1.446 + 1.447 + 1.448 +void unsupported_function(struct vm86_regs *r, uint8_t num, uint8_t ah) 1.449 +{ 1.450 + fprintf(stderr, "int 0x%02x: unsupported function 0x%02x\n", num, ah); 1.451 + dump_regs(r); 1.452 + set_error(r, 0x01); /* function number invalid */ 1.453 +} 1.454 + 1.455 +/* Open hard disk image ./hd[0-7] / floppy image ./fd[0-7] or /dev/fd[0-7] */ 1.456 +int open_disk(struct vm86_regs *r) 1.457 +{ 1.458 + int fd = -1, drive = r->edx & 0xff; 1.459 + char filename[9], n = '0' + (drive & 7); 1.460 + if (drive > 127) { 1.461 + strcpy(filename,"hd0"); 1.462 + filename[2] = n; 1.463 + } 1.464 + else { 1.465 + strcpy(filename,"/dev/fd0"); 1.466 + filename[7] = n; 1.467 + fd = open(filename+5, O_RDONLY); 1.468 + } 1.469 + if (fd < 0) 1.470 + fd = open(filename, O_RDONLY); 1.471 + return fd; 1.472 +} 1.473 + 1.474 + 1.475 +void read_sectors(int fd, struct vm86_regs *r, int first_sector, 1.476 + int sector_count, void *buffer) 1.477 +{ 1.478 + int drive = r->edx & 0xff; 1.479 + r->eax &= ~0xff00; 1.480 + r->eax |= 0x0400; /* sector not found */ 1.481 + r->eflags |= CF_MASK; 1.482 + if (fd >= 0) { 1.483 + static struct stat st; 1.484 + first_sector <<= 9; 1.485 + sector_count <<= 9; 1.486 + if (drive < 8 && fstat(fd, &st) == 0) { 1.487 + static ino_t inodes[8]; 1.488 + ino_t last = inodes[drive]; 1.489 + inodes[drive] = st.st_ino; 1.490 + if (last && last != st.st_ino) { 1.491 + set_error(r, 0x0600); /* floppy disk swap */ 1.492 + goto failed; 1.493 + } 1.494 + } 1.495 + if (lseek(fd, first_sector, SEEK_CUR) >= 0 && 1.496 + read(fd, buffer, sector_count) == sector_count) { 1.497 + r->eax &= ~0xff00; 1.498 + r->eflags &= ~CF_MASK; 1.499 + } 1.500 + failed: 1.501 + close(fd); 1.502 + } 1.503 +} 1.504 + 1.505 +void do_int10(struct vm86_regs *r) 1.506 +{ 1.507 + uint8_t ah; 1.508 + 1.509 + ah = (r->eax >> 8); 1.510 + switch(ah) { 1.511 + case 0x0E: /* write char */ 1.512 + { 1.513 + uint8_t c = r->eax; 1.514 + write(1, &c, 1); 1.515 + } 1.516 + break; 1.517 + default: 1.518 + unsupported_function(r, 0x10, ah); 1.519 + } 1.520 +} 1.521 + 1.522 +void do_int13(struct vm86_regs *r) 1.523 +{ 1.524 + uint8_t ah; 1.525 + 1.526 + ah = (r->eax >> 8); 1.527 + switch(ah) { 1.528 + case 0x00: /* reset disk */ 1.529 + { 1.530 + r->eax &= ~0xff00; /* success */ 1.531 + r->eflags &= ~CF_MASK; 1.532 + } 1.533 + break; 1.534 + case 0x02: /* read disk CHS */ 1.535 + { 1.536 + int fd, c, h, s, heads, sectors, cylinders; 1.537 + long size; 1.538 + fd = open_disk(r); 1.539 + if (fd >= 0) { 1.540 + size = lseek(fd, 0, SEEK_END) / 512; 1.541 + if ((r->edx & 0xff) > 127) { 1.542 + sectors = 63; 1.543 + if (size % sectors) 1.544 + sectors = 62; 1.545 + if (size % sectors) 1.546 + sectors = 32; 1.547 + if (size % sectors) 1.548 + sectors = 17; 1.549 + if (size % sectors) 1.550 + fd = -1; 1.551 + size /= sectors; 1.552 + for (heads = 256; size % heads; heads--); 1.553 + cylinders = size / heads; 1.554 + } 1.555 + else { 1.556 + int i; 1.557 + heads = 1 + (size > 256*2); 1.558 + cylinders = 40 * (1 + (size > 512*2)); 1.559 + size /= heads; 1.560 + for (i = 0; i < 5; i++) 1.561 + if (size % (cylinders + i) == 0) break; 1.562 + if (i == 5) 1.563 + fd = -1; 1.564 + cylinders += i; 1.565 + sectors = size / cylinders; 1.566 + } 1.567 + } 1.568 + c = ((r->ecx & 0xC0) << 2) | ((r->ecx >> 8) & 0xff); 1.569 + h = (r->edx >> 8) & 0xff; 1.570 + s = (r->ecx & 0x3f) -1; 1.571 + if (fd < 0 || c >= cylinders || h >= heads || s >= sectors) { 1.572 + set_error(r, 0x0400); /* sector not found */ 1.573 + break; 1.574 + } 1.575 + read_sectors(fd, r, (((c * heads) + h) * sectors) + s, 1.576 + r->eax & 0xff, seg_to_linear(r->es, r->ebx)); 1.577 + } 1.578 + break; 1.579 + case 0x42: /* read disk LBA */ 1.580 + { 1.581 + uint16_t *packet = (uint16_t *) seg_to_linear(r->ds, r-> esi); 1.582 + uint8_t *to = seg_to_linear(packet[3], packet[2]); 1.583 + if ((packet[3] & packet[2]) == 0xffff) 1.584 + to = * (uint8_t **) &packet[8]; 1.585 + if (packet[0] != 0x0010 && packet[0] != 0x0018) 1.586 + goto unsupported; 1.587 + read_sectors(open_disk(r), r, * (uint32_t *) &packet[4], packet[1], to); 1.588 + } 1.589 + break; 1.590 + default: 1.591 + unsupported: 1.592 + unsupported_function(r, 0x13, ah); 1.593 + } 1.594 +} 1.595 + 1.596 +void do_int15(struct vm86_regs *r) 1.597 +{ 1.598 + uint8_t ah; 1.599 + 1.600 + ah = (r->eax >> 8); 1.601 + switch(ah) { 1.602 + case 0x87: /* move memory */ 1.603 + /* XXX */ 1.604 + break; 1.605 + default: 1.606 + unsupported_function(r, 0x15, ah); 1.607 + } 1.608 +} 1.609 + 1.610 +void do_int16(struct vm86_regs *r) 1.611 +{ 1.612 + static uint16_t last_ax, hold_char; 1.613 + struct termios termios_def, termios_raw; 1.614 + uint8_t ah; 1.615 + 1.616 + ah = (r->eax >> 8); 1.617 + tcgetattr(0, &termios_def); 1.618 + termios_raw = termios_def; 1.619 + cfmakeraw(&termios_raw); 1.620 + tcsetattr(0, TCSADRAIN, &termios_raw); 1.621 + switch(ah) { 1.622 + case 0x01: /* test keyboard */ 1.623 + { 1.624 + int count; 1.625 + r->eflags &= ~ZF_MASK; 1.626 + if (hold_char) { 1.627 + r->eax &= ~0xffff; 1.628 + r->eax |= last_ax; 1.629 + break; 1.630 + } 1.631 + if (ioctl(0, FIONREAD, &count) < 0 || count == 0) { 1.632 + r->eflags |= ZF_MASK; 1.633 + break; 1.634 + } 1.635 + hold_char = 2; 1.636 + } 1.637 + case 0x00: /* read keyboard */ 1.638 + { 1.639 + uint8_t c; 1.640 + if (hold_char) 1.641 + hold_char--; 1.642 + read(0, &c, 1); 1.643 + if (c == 3) { 1.644 + tcsetattr(0, TCSADRAIN, &termios_def); 1.645 + exit(0); 1.646 + } 1.647 + if (c == 10) 1.648 + c = 13; 1.649 + r->eax &= ~0xffff; 1.650 + r->eax |= last_ax = c; 1.651 + /* XXX ah = scan code */ 1.652 + } 1.653 + break; 1.654 + default: 1.655 + unsupported_function(r, 0x16, ah); 1.656 + } 1.657 + tcsetattr(0, TCSADRAIN, &termios_def); 1.658 +} 1.659 + 1.660 +void do_int1a(struct vm86_regs *r) 1.661 +{ 1.662 + uint8_t ah; 1.663 + 1.664 + ah = (r->eax >> 8); 1.665 + switch(ah) { 1.666 + case 0x00: /* GET SYSTEM TIME */ 1.667 + { 1.668 + uint16_t *timer = (uint16_t *) seg_to_linear(0, 0x46C); 1.669 + r->ecx &= ~0xffff; 1.670 + r->ecx |= *timer++; 1.671 + r->edx &= ~0xffff; 1.672 + r->edx |= *timer; 1.673 + r->eax &= ~0xff; 1.674 + } 1.675 + break; 1.676 + default: 1.677 + unsupported_function(r, 0x1a, ah); 1.678 + } 1.679 +} 1.680 + 1.681 +void do_int20(struct vm86_regs *r) 1.682 +{ 1.683 + /* terminate program */ 1.684 + exit(0); 1.685 +} 1.686 + 1.687 +void do_int21(struct vm86_regs *r) 1.688 +{ 1.689 + uint8_t ah; 1.690 + 1.691 + ah = (r->eax >> 8); 1.692 + switch(ah) { 1.693 + case 0x00: /* exit */ 1.694 + exit(0); 1.695 + case 0x02: /* write char */ 1.696 + { 1.697 + uint8_t c = r->edx; 1.698 + write(1, &c, 1); 1.699 + } 1.700 + break; 1.701 + case 0x09: /* write string */ 1.702 + { 1.703 + uint8_t c; 1.704 + int offset; 1.705 + offset = r->edx; 1.706 + for(;;) { 1.707 + c = *seg_to_linear(r->ds, offset); 1.708 + if (c == '$') 1.709 + break; 1.710 + write(1, &c, 1); 1.711 + offset++; 1.712 + } 1.713 + r->eax = (r->eax & ~0xff) | '$'; 1.714 + } 1.715 + break; 1.716 + case 0x0a: /* buffered input */ 1.717 + { 1.718 + int max_len, cur_len, ret; 1.719 + uint8_t ch; 1.720 + uint16_t off; 1.721 + 1.722 + /* XXX: should use raw mode to avoid sending the CRLF to 1.723 + the terminal */ 1.724 + off = r->edx & 0xffff; 1.725 + max_len = *seg_to_linear(r->ds, off); 1.726 + cur_len = 0; 1.727 + while (cur_len < max_len) { 1.728 + ret = read(0, &ch, 1); 1.729 + if (ret < 0) { 1.730 + if (errno != EINTR && errno != EAGAIN) 1.731 + break; 1.732 + } else if (ret == 0) { 1.733 + break; 1.734 + } else { 1.735 + if (ch == '\n') 1.736 + break; 1.737 + } 1.738 + *seg_to_linear(r->ds, off + 2 + cur_len++) = ch; 1.739 + } 1.740 + *seg_to_linear(r->ds, off + 1) = cur_len; 1.741 + *seg_to_linear(r->ds, off + 2 + cur_len) = '\r'; 1.742 + } 1.743 + break; 1.744 + case 0x25: /* set interrupt vector */ 1.745 + { 1.746 + uint16_t *ptr; 1.747 + ptr = (uint16_t *)seg_to_linear(0, (r->eax & 0xff) * 4); 1.748 + ptr[0] = r->edx; 1.749 + ptr[1] = r->ds; 1.750 + } 1.751 + break; 1.752 + case 0x29: /* parse filename into FCB */ 1.753 +#if 0 1.754 + /* not really needed */ 1.755 + { 1.756 + const uint8_t *p, *p_start; 1.757 + uint8_t file[8], ext[3]; 1.758 + FCB *fcb; 1.759 + int file_len, ext_len, has_wildchars, c, drive_num; 1.760 + 1.761 + /* XXX: not complete at all */ 1.762 + fcb = (FCB *)seg_to_linear(r->es, r->edi); 1.763 + printf("ds=0x%x si=0x%lx\n", r->ds, r->esi); 1.764 + p_start = (const uint8_t *)seg_to_linear(r->ds, r->esi); 1.765 + 1.766 + p = p_start; 1.767 + has_wildchars = 0; 1.768 + 1.769 + /* drive */ 1.770 + if (isalpha(p[0]) && p[1] == ':') { 1.771 + drive_num = toupper(p[0]) - 'A' + 1; 1.772 + p += 2; 1.773 + } else { 1.774 + drive_num = 0; 1.775 + } 1.776 + 1.777 + /* filename */ 1.778 + file_len = 0; 1.779 + for(;;) { 1.780 + c = *p; 1.781 + if (!(c >= 33 && c <= 126)) 1.782 + break; 1.783 + if (c == '.') 1.784 + break; 1.785 + if (c == '*' || c == '?') 1.786 + has_wildchars = 1; 1.787 + if (file_len < 8) 1.788 + file[file_len++] = c; 1.789 + } 1.790 + memset(file + file_len, ' ', 8 - file_len); 1.791 + 1.792 + /* extension */ 1.793 + ext_len = 0; 1.794 + if (*p == '.') { 1.795 + for(;;) { 1.796 + c = *p; 1.797 + if (!(c >= 33 && c <= 126)) 1.798 + break; 1.799 + if (c == '*' || c == '?') 1.800 + has_wildchars = 1; 1.801 + ext[ext_len++] = c; 1.802 + if (ext_len >= 3) 1.803 + break; 1.804 + } 1.805 + } 1.806 + memset(ext + ext_len, ' ', 3 - ext_len); 1.807 + 1.808 +#if 0 1.809 + { 1.810 + printf("drive=%d file=%8s ext=%3s\n", 1.811 + drive_num, file, ext); 1.812 + } 1.813 +#endif 1.814 + if (drive_num == 0 && r->eax & (1 << 1)) { 1.815 + /* keep drive */ 1.816 + } else { 1.817 + fcb->drive_num = drive_num; /* default drive */ 1.818 + } 1.819 + 1.820 + if (file_len == 0 && r->eax & (1 << 2)) { 1.821 + /* keep */ 1.822 + } else { 1.823 + memcpy(fcb->file_name, file, 8); 1.824 + } 1.825 + 1.826 + if (ext_len == 0 && r->eax & (1 << 3)) { 1.827 + /* keep */ 1.828 + } else { 1.829 + memcpy(fcb->file_ext, ext, 3); 1.830 + } 1.831 + r->eax = (r->eax & ~0xff) | has_wildchars; 1.832 + r->esi = (r->esi & ~0xffff) | ((r->esi + (p - p_start)) & 0xffff); 1.833 + } 1.834 +#endif 1.835 + break; 1.836 + case 0x2A: /* get system date */ 1.837 + { 1.838 + time_t t = time(NULL); 1.839 + struct tm *now=localtime(&t); 1.840 + 1.841 + r->ecx = now->tm_year; 1.842 + r->edx = (now->tm_mon * 256) + now->tm_mday; 1.843 + r->eax = now->tm_wday;; 1.844 + } 1.845 + break; 1.846 + case 0x2C: /* get system time */ 1.847 + { 1.848 + time_t t = time(NULL); 1.849 + struct tm *now=localtime(&t); 1.850 + struct timeval tim; 1.851 + 1.852 + gettimeofday(&tim, NULL); 1.853 + r->edx = (now->tm_hour * 256) + now->tm_min; 1.854 + r->edx = (tim.tv_sec * 256) + tim.tv_usec/10000; 1.855 + } 1.856 + break; 1.857 + case 0x30: /* get dos version */ 1.858 + { 1.859 + int major, minor, serial, oem; 1.860 + /* XXX: return correct value for FreeDOS */ 1.861 + major = 0x03; 1.862 + minor = 0x31; 1.863 + serial = 0x123456; 1.864 + oem = 0x66; 1.865 + r->eax = (r->eax & ~0xffff) | major | (minor << 8); 1.866 + r->ecx = (r->ecx & ~0xffff) | (serial & 0xffff); 1.867 + r->ebx = (r->ebx & ~0xffff) | (serial & 0xff) | (0x66 << 8); 1.868 + } 1.869 + break; 1.870 + case 0x35: /* get interrupt vector */ 1.871 + { 1.872 + uint16_t *ptr; 1.873 + ptr = (uint16_t *)seg_to_linear(0, (r->eax & 0xff) * 4); 1.874 + r->ebx = (r->ebx & ~0xffff) | ptr[0]; 1.875 + r->es = ptr[1]; 1.876 + } 1.877 + break; 1.878 + case 0x37: 1.879 + { 1.880 + switch(r->eax & 0xff) { 1.881 + case 0x00: /* get switch char */ 1.882 + r->eax = (r->eax & ~0xff) | 0x00; 1.883 + r->edx = (r->edx & ~0xff) | '/'; 1.884 + break; 1.885 + default: 1.886 + goto unsupported; 1.887 + } 1.888 + } 1.889 + break; 1.890 + case 0x3c: /* create or truncate file */ 1.891 + { 1.892 + char filename[1024]; 1.893 + int fd, h, flags; 1.894 + 1.895 + h = get_new_handle(); 1.896 + if (h < 0) { 1.897 + set_error(r, 0x04); /* too many open files */ 1.898 + } else { 1.899 + get_filename(r, filename, sizeof(filename)); 1.900 + if (r->ecx & 1) 1.901 + flags = 0444; /* read-only */ 1.902 + else 1.903 + flags = 0777; 1.904 + fd = open(filename, O_RDWR | O_TRUNC | O_CREAT, flags); 1.905 +#ifdef DUMP_INT21 1.906 + printf("int21: create: file='%s' cx=0x%04x ret=%d\n", 1.907 + filename, (int)(r->ecx & 0xffff), h); 1.908 +#endif 1.909 + if (fd < 0) { 1.910 + set_error(r, 0x03); /* path not found */ 1.911 + } else { 1.912 + dos_files[h].fd = fd; 1.913 + set_error(r, 0); 1.914 + r->eax = (r->eax & ~0xffff) | h; 1.915 + } 1.916 + } 1.917 + } 1.918 + break; 1.919 + case 0x3d: /* open file */ 1.920 + { 1.921 + char filename[1024]; 1.922 + int fd, h; 1.923 + 1.924 + h = get_new_handle(); 1.925 + if (h < 0) { 1.926 + set_error(r, 0x04); /* too many open files */ 1.927 + } else { 1.928 + get_filename(r, filename, sizeof(filename)); 1.929 +#ifdef DUMP_INT21 1.930 + printf("int21: open: file='%s' al=0x%02x ret=%d\n", 1.931 + filename, (int)(r->eax & 0xff), h); 1.932 +#endif 1.933 + fd = open(filename, r->eax & 3); 1.934 + if (fd < 0) { 1.935 + set_error(r, 0x02); /* file not found */ 1.936 + } else { 1.937 + dos_files[h].fd = fd; 1.938 + set_error(r, 0); 1.939 + r->eax = (r->eax & ~0xffff) | h; 1.940 + } 1.941 + } 1.942 + } 1.943 + break; 1.944 + case 0x3e: /* close file */ 1.945 + { 1.946 + DOSFile *fh = get_file(r->ebx & 0xffff); 1.947 +#ifdef DUMP_INT21 1.948 + printf("int21: close fd=%d\n", (int)(r->ebx & 0xffff)); 1.949 +#endif 1.950 + if (!fh) { 1.951 + set_error(r, 0x06); /* invalid handle */ 1.952 + } else { 1.953 + close(fh->fd); 1.954 + fh->fd = -1; 1.955 + set_error(r, 0); 1.956 + } 1.957 + } 1.958 + break; 1.959 + case 0x3f: /* read */ 1.960 + { 1.961 + DOSFile *fh = get_file(r->ebx & 0xffff); 1.962 + int n, ret; 1.963 + 1.964 + if (!fh) { 1.965 + set_error(r, 0x06); /* invalid handle */ 1.966 + } else { 1.967 + n = r->ecx & 0xffff; 1.968 + for(;;) { 1.969 + ret = read(fh->fd, 1.970 + seg_to_linear(r->ds, r->edx), n); 1.971 + if (ret < 0) { 1.972 + if (errno != EINTR && errno != EAGAIN) 1.973 + break; 1.974 + } else { 1.975 + break; 1.976 + } 1.977 + } 1.978 +#ifdef DUMP_INT21 1.979 + printf("int21: read: fd=%d n=%d ret=%d\n", 1.980 + (int)(r->ebx & 0xffff), n, ret); 1.981 +#endif 1.982 + if (ret < 0) { 1.983 + set_error(r, 0x05); /* acces denied */ 1.984 + } else { 1.985 + r->eax = (r->eax & ~0xffff) | ret; 1.986 + set_error(r, 0); 1.987 + } 1.988 + } 1.989 + } 1.990 + break; 1.991 + case 0x40: /* write */ 1.992 + { 1.993 + DOSFile *fh = get_file(r->ebx & 0xffff); 1.994 + int n, ret, pos; 1.995 + 1.996 + if (!fh) { 1.997 + set_error(r, 0x06); /* invalid handle */ 1.998 + } else { 1.999 + n = r->ecx & 0xffff; 1.1000 + if (n == 0) { 1.1001 + /* truncate */ 1.1002 + pos = lseek(fh->fd, 0, SEEK_CUR); 1.1003 + if (pos >= 0) { 1.1004 + ret = ftruncate(fh->fd, pos); 1.1005 + } else { 1.1006 + ret = -1; 1.1007 + } 1.1008 + } else { 1.1009 + for(;;) { 1.1010 + ret = write(fh->fd, 1.1011 + seg_to_linear(r->ds, r->edx), n); 1.1012 + if (ret < 0) { 1.1013 + if (errno != EINTR && errno != EAGAIN) 1.1014 + break; 1.1015 + } else { 1.1016 + break; 1.1017 + } 1.1018 + } 1.1019 + } 1.1020 +#ifdef DUMP_INT21 1.1021 + printf("int21: write: fd=%d n=%d ret=%d\n", 1.1022 + (int)(r->ebx & 0xffff), n, ret); 1.1023 +#endif 1.1024 + if (ret < 0) { 1.1025 + set_error(r, 0x05); /* acces denied */ 1.1026 + } else { 1.1027 + r->eax = (r->eax & ~0xffff) | ret; 1.1028 + set_error(r, 0); 1.1029 + } 1.1030 + } 1.1031 + } 1.1032 + break; 1.1033 + case 0x41: /* unlink */ 1.1034 + { 1.1035 + char filename[1024]; 1.1036 + get_filename(r, filename, sizeof(filename)); 1.1037 + if (unlink(filename) < 0) { 1.1038 + set_error(r, 0x02); /* file not found */ 1.1039 + } else { 1.1040 + set_error(r, 0); 1.1041 + } 1.1042 + } 1.1043 + break; 1.1044 + case 0x42: /* lseek */ 1.1045 + { 1.1046 + DOSFile *fh = get_file(r->ebx & 0xffff); 1.1047 + int pos, ret; 1.1048 + 1.1049 + if (!fh) { 1.1050 + set_error(r, 0x06); /* invalid handle */ 1.1051 + } else { 1.1052 + pos = ((r->ecx & 0xffff) << 16) | (r->edx & 0xffff); 1.1053 + ret = lseek(fh->fd, pos, r->eax & 0xff); 1.1054 +#ifdef DUMP_INT21 1.1055 + printf("int21: lseek: fd=%d pos=%d whence=%d ret=%d\n", 1.1056 + (int)(r->ebx & 0xffff), pos, (uint8_t)r->eax, ret); 1.1057 +#endif 1.1058 + if (ret < 0) { 1.1059 + set_error(r, 0x01); /* function number invalid */ 1.1060 + } else { 1.1061 + r->edx = (r->edx & ~0xffff) | ((unsigned)ret >> 16); 1.1062 + r->eax = (r->eax & ~0xffff) | (ret & 0xffff); 1.1063 + set_error(r, 0); 1.1064 + } 1.1065 + } 1.1066 + } 1.1067 + break; 1.1068 + case 0x44: /* ioctl */ 1.1069 + switch(r->eax & 0xff) { 1.1070 + case 0x00: /* get device information */ 1.1071 + { 1.1072 + DOSFile *fh = get_file(r->ebx & 0xffff); 1.1073 + int ret; 1.1074 + 1.1075 + if (!fh) { 1.1076 + set_error(r, 0x06); /* invalid handle */ 1.1077 + } else { 1.1078 + ret = 0; 1.1079 + if (isatty(fh->fd)) { 1.1080 + ret |= 0x80; 1.1081 + if (fh->fd == 0) 1.1082 + ret |= (1 << 0); 1.1083 + else 1.1084 + ret |= (1 << 1); 1.1085 + } 1.1086 + r->edx = (r->edx & ~0xffff) | ret; 1.1087 + set_error(r, 0); 1.1088 + } 1.1089 + } 1.1090 + break; 1.1091 + default: 1.1092 + goto unsupported; 1.1093 + } 1.1094 + break; 1.1095 + case 0x48: /* allocate memory */ 1.1096 + { 1.1097 + int ret, max_size; 1.1098 +#ifdef DUMP_INT21 1.1099 + printf("int21: allocate memory: size=0x%04x\n", (uint16_t)r->ebx); 1.1100 +#endif 1.1101 + ret = mem_malloc(r->ebx & 0xffff, &max_size); 1.1102 + if (ret < 0) { 1.1103 + set_error(r, 0x08); /* insufficient memory*/ 1.1104 + } else { 1.1105 + r->eax = (r->eax & ~0xffff) | ret; 1.1106 + r->ebx = (r->ebx & ~0xffff) | max_size; 1.1107 + set_error(r, 0); 1.1108 + } 1.1109 + } 1.1110 + break; 1.1111 + case 0x49: /* free memory */ 1.1112 + { 1.1113 +#ifdef DUMP_INT21 1.1114 + printf("int21: free memory: block=0x%04x\n", r->es); 1.1115 +#endif 1.1116 + if (mem_free(r->es) < 0) { 1.1117 + set_error(r, 0x09); /* memory block address invalid */ 1.1118 + } else { 1.1119 + set_error(r, 0); 1.1120 + } 1.1121 + } 1.1122 + break; 1.1123 + case 0x4a: /* resize memory block */ 1.1124 + { 1.1125 + int ret; 1.1126 +#ifdef DUMP_INT21 1.1127 + printf("int21: resize memory block: block=0x%04x size=0x%04x\n", 1.1128 + r->es, (uint16_t)r->ebx); 1.1129 +#endif 1.1130 + ret = mem_resize(r->es, r->ebx & 0xffff); 1.1131 + if (ret < 0) { 1.1132 + set_error(r, 0x08); /* insufficient memory*/ 1.1133 + } else { 1.1134 + r->ebx = (r->ebx & ~0xffff) | ret; 1.1135 + set_error(r, 0); 1.1136 + } 1.1137 + } 1.1138 + break; 1.1139 + case 0x4b: /* load program */ 1.1140 + { 1.1141 + char filename[1024]; 1.1142 + ExecParamBlock *blk; 1.1143 + int ret; 1.1144 + 1.1145 + if ((r->eax & 0xff) != 0x01) /* only load */ 1.1146 + goto unsupported; 1.1147 + get_filename(r, filename, sizeof(filename)); 1.1148 + blk = (ExecParamBlock *)seg_to_linear(r->es, r->ebx); 1.1149 + ret = load_com(blk, filename, NULL, 0, NULL); 1.1150 + if (ret < 0) { 1.1151 + set_error(r, 0x02); /* file not found */ 1.1152 + } else { 1.1153 + cur_psp = ret; 1.1154 + set_error(r, 0); 1.1155 + } 1.1156 + } 1.1157 + break; 1.1158 + case 0x4c: /* exit with return code */ 1.1159 + exit(r->eax & 0xff); 1.1160 + break; 1.1161 + case 0x50: /* set PSP address */ 1.1162 +#ifdef DUMP_INT21 1.1163 + printf("int21: set PSP: 0x%04x\n", (uint16_t)r->ebx); 1.1164 +#endif 1.1165 + cur_psp = r->ebx; 1.1166 + break; 1.1167 + case 0x51: /* get PSP address */ 1.1168 +#ifdef DUMP_INT21 1.1169 + printf("int21: get PSP: ret=0x%04x\n", cur_psp); 1.1170 +#endif 1.1171 + r->ebx = (r->ebx & ~0xffff) | cur_psp; 1.1172 + break; 1.1173 + case 0x55: /* create child PSP */ 1.1174 + { 1.1175 + uint8_t *psp_ptr; 1.1176 +#ifdef DUMP_INT21 1.1177 + printf("int21: create child PSP: psp=0x%04x last_seg=0x%04x\n", 1.1178 + (uint16_t)r->edx, (uint16_t)r->esi); 1.1179 +#endif 1.1180 + psp_ptr = seg_to_linear(r->edx & 0xffff, 0); 1.1181 + memset(psp_ptr, 0, 0x80); 1.1182 + psp_ptr[0] = 0xcd; /* int $0x20 */ 1.1183 + psp_ptr[1] = 0x20; 1.1184 + *(uint16_t *)(psp_ptr + 2) = r->esi; 1.1185 + r->eax = (r->eax & ~0xff); 1.1186 + } 1.1187 + break; 1.1188 + default: 1.1189 + unsupported: 1.1190 + unsupported_function(r, 0x21, ah); 1.1191 + } 1.1192 +} 1.1193 + 1.1194 +void do_int29(struct vm86_regs *r) 1.1195 +{ 1.1196 + uint8_t c = r->eax; 1.1197 + write(1, &c, 1); 1.1198 +} 1.1199 + 1.1200 +void raise_interrupt(int number) 1.1201 +{ 1.1202 + if (* (uint32_t *) seg_to_linear(0, number * 4) == 0) 1.1203 + return; 1.1204 + // FIXME VM86_SIGNAL 1.1205 +} 1.1206 + 1.1207 +void biosclock() 1.1208 +{ 1.1209 + uint32_t *timer = (uint32_t *) seg_to_linear(0, 0x46C); 1.1210 + ++*timer; 1.1211 + raise_interrupt(8); 1.1212 + raise_interrupt(0x1C); 1.1213 +} 1.1214 + 1.1215 +int main(int argc, char **argv) 1.1216 +{ 1.1217 + uint8_t *vm86_mem; 1.1218 + const char *filename; 1.1219 + int ret; 1.1220 + uint32_t file_size; 1.1221 + struct sigaction sa; 1.1222 + struct itimerval timerval; 1.1223 + struct vm86plus_struct ctx; 1.1224 + struct vm86_regs *r; 1.1225 + ExecParamBlock blk1, *blk = &blk1; 1.1226 + 1.1227 + if (argc < 2) 1.1228 + usage(); 1.1229 + filename = argv[1]; 1.1230 + 1.1231 + vm86_mem = mmap((void *)0x00000000, 0x110000, 1.1232 + PROT_WRITE | PROT_READ | PROT_EXEC, 1.1233 + MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0); 1.1234 + if (vm86_mem == MAP_FAILED) { 1.1235 + perror("mmap"); 1.1236 + exit(1); 1.1237 + } 1.1238 + 1.1239 + memset(&ctx, 0, sizeof(ctx)); 1.1240 + r = &ctx.regs; 1.1241 + set_bit((uint8_t *)&ctx.int_revectored, 0x10); 1.1242 + set_bit((uint8_t *)&ctx.int_revectored, 0x13); 1.1243 + set_bit((uint8_t *)&ctx.int_revectored, 0x15); 1.1244 + set_bit((uint8_t *)&ctx.int_revectored, 0x16); 1.1245 + set_bit((uint8_t *)&ctx.int_revectored, 0x1a); 1.1246 + set_bit((uint8_t *)&ctx.int_revectored, 0x20); 1.1247 + set_bit((uint8_t *)&ctx.int_revectored, 0x21); 1.1248 + set_bit((uint8_t *)&ctx.int_revectored, 0x29); 1.1249 + 1.1250 + dos_init(); 1.1251 + 1.1252 + if (strstr(filename,".com") || strstr(filename,".exe") || 1.1253 + strstr(filename,".COM") || strstr(filename,".EXE")) { 1.1254 + ret = load_com(blk, filename, &file_size, argc, argv); 1.1255 + if (ret < 0) { 1.1256 + perror(filename); 1.1257 + exit(1); 1.1258 + } 1.1259 + cur_psp = ret; 1.1260 + 1.1261 + /* init basic registers */ 1.1262 + r->eip = blk->ip; 1.1263 + r->esp = blk->sp + 2; /* pop ax value */ 1.1264 + r->cs = blk->cs; 1.1265 + r->ss = blk->ss; 1.1266 + r->ds = cur_psp; 1.1267 + r->es = cur_psp; 1.1268 + r->eflags = VIF_MASK; 1.1269 + 1.1270 + /* the value of these registers seem to be assumed by pi_10.com */ 1.1271 + r->esi = 0x100; 1.1272 +#if 0 1.1273 + r->ebx = file_size >> 16; 1.1274 + r->ecx = file_size & 0xffff; 1.1275 +#else 1.1276 + r->ecx = 0xff; 1.1277 +#endif 1.1278 + r->ebp = 0x0900; 1.1279 + r->edi = 0xfffe; 1.1280 + } 1.1281 + else { 1.1282 + if (load_boot(filename, r) < 0) { 1.1283 + if (errno) 1.1284 + perror(filename); 1.1285 + exit(1); 1.1286 + } 1.1287 + } 1.1288 + 1.1289 + sa.sa_handler = biosclock; 1.1290 + sigemptyset(&sa.sa_mask); 1.1291 + sa.sa_flags = SA_RESTART; 1.1292 + if (sigaction(SIGALRM, &sa, 0) == 0) { 1.1293 + timerval.it_interval.tv_sec = timerval.it_value.tv_sec = 0; 1.1294 + timerval.it_interval.tv_usec = timerval.it_value.tv_usec = 10000000 / 182; 1.1295 + setitimer (ITIMER_REAL, &timerval, NULL); 1.1296 + } 1.1297 + 1.1298 + for(;;) { 1.1299 + ret = vm86(VM86_ENTER, &ctx); 1.1300 + switch(VM86_TYPE(ret)) { 1.1301 + case VM86_INTx: 1.1302 + { 1.1303 + int int_num; 1.1304 + 1.1305 + int_num = VM86_ARG(ret); 1.1306 + switch(int_num) { 1.1307 + case 0x10: 1.1308 + do_int10(r); 1.1309 + break; 1.1310 + case 0x13: 1.1311 + do_int13(r); 1.1312 + break; 1.1313 + case 0x15: 1.1314 + do_int15(r); 1.1315 + break; 1.1316 + case 0x16: 1.1317 + do_int16(r); 1.1318 + break; 1.1319 + case 0x1a: 1.1320 + do_int1a(r); 1.1321 + break; 1.1322 + case 0x20: 1.1323 + do_int20(r); 1.1324 + break; 1.1325 + case 0x21: 1.1326 + do_int21(r); 1.1327 + break; 1.1328 + case 0x29: 1.1329 + do_int29(r); 1.1330 + break; 1.1331 + default: 1.1332 + fprintf(stderr, "unsupported int 0x%02x\n", int_num); 1.1333 + dump_regs(&ctx.regs); 1.1334 + break; 1.1335 + } 1.1336 + } 1.1337 + break; 1.1338 + case VM86_SIGNAL: 1.1339 + /* a signal came, we just ignore that */ 1.1340 + break; 1.1341 + case VM86_STI: 1.1342 + break; 1.1343 + case VM86_TRAP: 1.1344 + /* just executes the interruption */ 1.1345 + { 1.1346 + uint16_t *int_vector; 1.1347 + uint32_t eflags; 1.1348 + 1.1349 + eflags = r->eflags & ~IF_MASK; 1.1350 + if (r->eflags & VIF_MASK) 1.1351 + eflags |= IF_MASK; 1.1352 + pushw(r, eflags); 1.1353 + pushw(r, r->cs); 1.1354 + pushw(r, r->eip); 1.1355 + int_vector = (uint16_t *)seg_to_linear(0, VM86_ARG(ret) * 4); 1.1356 + r->eip = int_vector[0]; 1.1357 + r->cs = int_vector[1]; 1.1358 + r->eflags &= ~(VIF_MASK | TF_MASK | AC_MASK); 1.1359 + } 1.1360 + break; 1.1361 + default: 1.1362 + fprintf(stderr, "unhandled vm86 return code (0x%x)\n", ret); 1.1363 + dump_regs(&ctx.regs); 1.1364 + exit(1); 1.1365 + } 1.1366 + } 1.1367 +}