wok-current annotate runcom/stuff/runcom.c @ rev 13585

sbxkb: add LDFLAGS
author Pascal Bellard <pascal.bellard@slitaz.org>
date Tue Nov 06 12:55:04 2012 +0100 (2012-11-06)
parents 289a2f495cd6
children fd625ee963af
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 }