wok annotate runcom/stuff/runcom.c @ rev 17602

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