symbian-qemu-0.9.1-12/qemu-symbian-svp/tests/runcom.c
author Gareth Stockwell <gareth.stockwell@accenture.com>
Mon, 06 Sep 2010 16:25:43 +0100
changeset 107 3bc1a978be44
parent 1 2fb8b9db1c86
permissions -rw-r--r--
Fix for Bug 3671 - QEMU GDB stub listens on IPv6-only port on Windows 7 The connection string used by the GDB stub does not specify which version of the Internet Protocol should be used by the port on which it listens. On host platforms with IPv6 support, such as Windows 7, this means that the stub listens on an IPv6-only port. Since the GDB client uses IPv4, this means that the client cannot connect to QEMU.

/*
 * Simple example of use of vm86: launch a basic .com DOS executable
 */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <signal.h>

#include <linux/unistd.h>
#include <asm/vm86.h>

//#define SIGTEST

#undef __syscall_return
#define __syscall_return(type, res) \
do { \
	return (type) (res); \
} while (0)

_syscall2(int, vm86, int, func, struct vm86plus_struct *, v86)

#define COM_BASE_ADDR    0x10100

void usage(void)
{
    printf("runcom version 0.1 (c) 2003 Fabrice Bellard\n"
           "usage: runcom file.com\n"
           "VM86 Run simple .com DOS executables (linux vm86 test mode)\n");
    exit(1);
}

static inline void set_bit(uint8_t *a, unsigned int bit)
{
    a[bit / 8] |= (1 << (bit % 8));
}

static inline uint8_t *seg_to_linear(unsigned int seg, unsigned int reg)
{
    return (uint8_t *)((seg << 4) + (reg & 0xffff));
}

static inline void pushw(struct vm86_regs *r, int val)
{
    r->esp = (r->esp & ~0xffff) | ((r->esp - 2) & 0xffff);
    *(uint16_t *)seg_to_linear(r->ss, r->esp) = val;
}

void dump_regs(struct vm86_regs *r)
{
    fprintf(stderr,
            "EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx\n"
            "ESI=%08lx EDI=%08lx EBP=%08lx ESP=%08lx\n"
            "EIP=%08lx EFL=%08lx\n"
            "CS=%04x DS=%04x ES=%04x SS=%04x FS=%04x GS=%04x\n",
            r->eax, r->ebx, r->ecx, r->edx, r->esi, r->edi, r->ebp, r->esp,
            r->eip, r->eflags,
            r->cs, r->ds, r->es, r->ss, r->fs, r->gs);
}

#ifdef SIGTEST
void alarm_handler(int sig)
{
    fprintf(stderr, "alarm signal=%d\n", sig);
    alarm(1);
}
#endif

int main(int argc, char **argv)
{
    uint8_t *vm86_mem;
    const char *filename;
    int fd, ret, seg;
    struct vm86plus_struct ctx;
    struct vm86_regs *r;

    if (argc != 2)
        usage();
    filename = argv[1];

    vm86_mem = mmap((void *)0x00000000, 0x110000,
                    PROT_WRITE | PROT_READ | PROT_EXEC,
                    MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
    if (vm86_mem == MAP_FAILED) {
        perror("mmap");
        exit(1);
    }
#ifdef SIGTEST
    {
        struct sigaction act;

        act.sa_handler = alarm_handler;
        sigemptyset(&act.sa_mask);
        act.sa_flags = 0;
        sigaction(SIGALRM, &act, NULL);
        alarm(1);
    }
#endif

    /* load the MSDOS .com executable */
    fd = open(filename, O_RDONLY);
    if (fd < 0) {
        perror(filename);
        exit(1);
    }
    ret = read(fd, vm86_mem + COM_BASE_ADDR, 65536 - 256);
    if (ret < 0) {
        perror("read");
        exit(1);
    }
    close(fd);

    memset(&ctx, 0, sizeof(ctx));
    /* init basic registers */
    r = &ctx.regs;
    r->eip = 0x100;
    r->esp = 0xfffe;
    seg = (COM_BASE_ADDR - 0x100) >> 4;
    r->cs = seg;
    r->ss = seg;
    r->ds = seg;
    r->es = seg;
    r->fs = seg;
    r->gs = seg;
    r->eflags = VIF_MASK;

    /* put return code */
    set_bit((uint8_t *)&ctx.int_revectored, 0x21);
    *seg_to_linear(r->cs, 0) = 0xb4; /* mov ah, $0 */
    *seg_to_linear(r->cs, 1) = 0x00;
    *seg_to_linear(r->cs, 2) = 0xcd; /* int $0x21 */
    *seg_to_linear(r->cs, 3) = 0x21;
    pushw(&ctx.regs, 0x0000);

    /* the value of these registers seem to be assumed by pi_10.com */
    r->esi = 0x100;
    r->ecx = 0xff;
    r->ebp = 0x0900;
    r->edi = 0xfffe;

    for(;;) {
        ret = vm86(VM86_ENTER, &ctx);
        switch(VM86_TYPE(ret)) {
        case VM86_INTx:
            {
                int int_num, ah;

                int_num = VM86_ARG(ret);
                if (int_num != 0x21)
                    goto unknown_int;
                ah = (r->eax >> 8) & 0xff;
                switch(ah) {
                case 0x00: /* exit */
                    exit(0);
                case 0x02: /* write char */
                    {
                        uint8_t c = r->edx;
                        write(1, &c, 1);
                    }
                    break;
                case 0x09: /* write string */
                    {
                        uint8_t c;
                        for(;;) {
                            c = *seg_to_linear(r->ds, r->edx);
                            if (c == '$')
                                break;
                            write(1, &c, 1);
                        }
                        r->eax = (r->eax & ~0xff) | '$';
                    }
                    break;
                default:
                unknown_int:
                    fprintf(stderr, "unsupported int 0x%02x\n", int_num);
                    dump_regs(&ctx.regs);
                    //                    exit(1);
                }
            }
            break;
        case VM86_SIGNAL:
            /* a signal came, we just ignore that */
            break;
        case VM86_STI:
            break;
        default:
            fprintf(stderr, "unhandled vm86 return code (0x%x)\n", ret);
            dump_regs(&ctx.regs);
            exit(1);
        }
    }
}