Statistics
| Branch: | Revision:

root / tests / tcg / runcom.c @ c09015dd

History | View | Annotate | Download (4.9 kB)

1
/*
2
 * Simple example of use of vm86: launch a basic .com DOS executable
3
 */
4
#include <stdlib.h>
5
#include <stdio.h>
6
#include <string.h>
7
#include <inttypes.h>
8
#include <unistd.h>
9
#include <fcntl.h>
10
#include <sys/mman.h>
11
#include <signal.h>
12

    
13
#include <linux/unistd.h>
14
#include <asm/vm86.h>
15

    
16
extern int vm86 (unsigned long int subfunction,
17
                 struct vm86plus_struct *info);
18

    
19
#define VIF_MASK                0x00080000
20

    
21
//#define SIGTEST
22

    
23
#define COM_BASE_ADDR    0x10100
24

    
25
static void usage(void)
26
{
27
    printf("runcom version 0.1 (c) 2003 Fabrice Bellard\n"
28
           "usage: runcom file.com\n"
29
           "VM86 Run simple .com DOS executables (linux vm86 test mode)\n");
30
    exit(1);
31
}
32

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

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

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

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

    
61
#ifdef SIGTEST
62
void alarm_handler(int sig)
63
{
64
    fprintf(stderr, "alarm signal=%d\n", sig);
65
    alarm(1);
66
}
67
#endif
68

    
69
int main(int argc, char **argv)
70
{
71
    uint8_t *vm86_mem;
72
    const char *filename;
73
    int fd, ret, seg;
74
    struct vm86plus_struct ctx;
75
    struct vm86_regs *r;
76

    
77
    if (argc != 2)
78
        usage();
79
    filename = argv[1];
80

    
81
    vm86_mem = mmap((void *)0x00000000, 0x110000,
82
                    PROT_WRITE | PROT_READ | PROT_EXEC,
83
                    MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
84
    if (vm86_mem == MAP_FAILED) {
85
        perror("mmap");
86
        exit(1);
87
    }
88
#ifdef SIGTEST
89
    {
90
        struct sigaction act;
91

    
92
        act.sa_handler = alarm_handler;
93
        sigemptyset(&act.sa_mask);
94
        act.sa_flags = 0;
95
        sigaction(SIGALRM, &act, NULL);
96
        alarm(1);
97
    }
98
#endif
99

    
100
    /* load the MSDOS .com executable */
101
    fd = open(filename, O_RDONLY);
102
    if (fd < 0) {
103
        perror(filename);
104
        exit(1);
105
    }
106
    ret = read(fd, vm86_mem + COM_BASE_ADDR, 65536 - 256);
107
    if (ret < 0) {
108
        perror("read");
109
        exit(1);
110
    }
111
    close(fd);
112

    
113
    memset(&ctx, 0, sizeof(ctx));
114
    /* init basic registers */
115
    r = &ctx.regs;
116
    r->eip = 0x100;
117
    r->esp = 0xfffe;
118
    seg = (COM_BASE_ADDR - 0x100) >> 4;
119
    r->cs = seg;
120
    r->ss = seg;
121
    r->ds = seg;
122
    r->es = seg;
123
    r->fs = seg;
124
    r->gs = seg;
125
    r->eflags = VIF_MASK;
126

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

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

    
141
    for(;;) {
142
        ret = vm86(VM86_ENTER, &ctx);
143
        switch(VM86_TYPE(ret)) {
144
        case VM86_INTx:
145
            {
146
                int int_num, ah;
147

    
148
                int_num = VM86_ARG(ret);
149
                if (int_num != 0x21)
150
                    goto unknown_int;
151
                ah = (r->eax >> 8) & 0xff;
152
                switch(ah) {
153
                case 0x00: /* exit */
154
                    exit(0);
155
                case 0x02: /* write char */
156
                    {
157
                        uint8_t c = r->edx;
158
                        write(1, &c, 1);
159
                    }
160
                    break;
161
                case 0x09: /* write string */
162
                    {
163
                        uint8_t c;
164
                        for(;;) {
165
                            c = *seg_to_linear(r->ds, r->edx);
166
                            if (c == '$')
167
                                break;
168
                            write(1, &c, 1);
169
                        }
170
                        r->eax = (r->eax & ~0xff) | '$';
171
                    }
172
                    break;
173
                default:
174
                unknown_int:
175
                    fprintf(stderr, "unsupported int 0x%02x\n", int_num);
176
                    dump_regs(&ctx.regs);
177
                    //                    exit(1);
178
                }
179
            }
180
            break;
181
        case VM86_SIGNAL:
182
            /* a signal came, we just ignore that */
183
            break;
184
        case VM86_STI:
185
            break;
186
        default:
187
            fprintf(stderr, "unhandled vm86 return code (0x%x)\n", ret);
188
            dump_regs(&ctx.regs);
189
            exit(1);
190
        }
191
    }
192
}