Revision bc8a22cc

b/Changelog
1
version 0.1.4:
2

  
3
 - more accurate VM86 emulation (can launch small DOS 16 bit
4
   executables in wine).
5
 - fixed push/pop fs/gs
6
 - added iret instruction.
7

  
8
version 0.1.3:
9

  
10
 - S390 support (Ulrich Weigand)
11
 - glibc 2.3.x compile fix (Ulrich Weigand)
12
 - socketcall endian fix (Ulrich Weigand)
13
 - struct sockaddr endian fix (Ulrich Weigand)
14
 - sendmsg/recvmsg endian fix (Ulrich Weigand)
15
 - execve endian fix (Ulrich Weigand)
16
 - fdset endian fix (Ulrich Weigand)
17
 - partial setsockopt syscall support (Ulrich Weigand)
18
 - more accurate pushf/popf emulation
19
 - first partial vm86() syscall support (can be used with runcom example).
20
 - added bound, cmpxchg8b, cpuid instructions
21
 - added 16 bit addressing support/override for string operations
22
 - poll() fix
23
 
24
version 0.1.2:
25

  
26
 - compile fixes
27
 - xlat instruction
28
 - xchg instruction memory lock
29
 - added simple vm86 example (not working with QEMU yet). The 54 byte
30
   DOS executable 'pi_10.com' program was released by Bertram
31
   Felgenhauer (more information at http://www.boo.net/~jasonp/pipage.html).
32

  
1 33
version 0.1.1:
2 34

  
3 35
 - glibc 2.2 compilation fixes
4 36
 - added -s and -L options
5 37
 - binary distribution of x86 glibc and wine
38
 - big endian fixes in ELF loader and getdents.
6 39

  
7 40
version 0.1:
8 41

  
b/TODO
1
- fix thread locks
2
- fix thread stack liberation
3
- fix x86 stack allocation
1 4
- optimize translated cache chaining (DLL PLT-like system)
2 5
- more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit
3 6
  issues, fix 16 bit uid issues)
4 7
- finish signal handing (fp87 state, more siginfo conversions)
5 8
- verify thread support (clone() and various locks)
6
- vm86 syscall support
7 9
- overrides/16bit for string ops
8 10
- make it self runnable (use same trick as ld.so : include its own relocator and libc)
9
- improved 16 bit support 
10 11
- fix FPU exceptions (in particular: gen_op_fpush not before mem load)
b/cpu-i386.h
68 68
#define VIP_MASK                0x00100000
69 69
#define ID_MASK                 0x00200000
70 70

  
71
#define EXCP00_DIVZ	1
72
#define EXCP01_SSTP	2
73
#define EXCP02_NMI	3
74
#define EXCP03_INT3	4
75
#define EXCP04_INTO	5
76
#define EXCP05_BOUND	6
77
#define EXCP06_ILLOP	7
78
#define EXCP07_PREX	8
79
#define EXCP08_DBLE	9
80
#define EXCP09_XERR	10
81
#define EXCP0A_TSS	11
82
#define EXCP0B_NOSEG	12
83
#define EXCP0C_STACK	13
84
#define EXCP0D_GPF	14
85
#define EXCP0E_PAGE	15
86
#define EXCP10_COPR	17
87
#define EXCP11_ALGN	18
88
#define EXCP12_MCHK	19
71
#define EXCP00_DIVZ	0
72
#define EXCP01_SSTP	1
73
#define EXCP02_NMI	2
74
#define EXCP03_INT3	3
75
#define EXCP04_INTO	4
76
#define EXCP05_BOUND	5
77
#define EXCP06_ILLOP	6
78
#define EXCP07_PREX	7
79
#define EXCP08_DBLE	8
80
#define EXCP09_XERR	9
81
#define EXCP0A_TSS	10
82
#define EXCP0B_NOSEG	11
83
#define EXCP0C_STACK	12
84
#define EXCP0D_GPF	13
85
#define EXCP0E_PAGE	14
86
#define EXCP10_COPR	16
87
#define EXCP11_ALGN	17
88
#define EXCP12_MCHK	18
89 89

  
90 90
#define EXCP_INTERRUPT 	256 /* async interruption */
91 91

  
b/linux-user/main.c
106 106

  
107 107
//#define DEBUG_VM86
108 108

  
109
static inline int is_revectored(int nr, struct target_revectored_struct *bitmap)
110
{
111
    return (tswap32(bitmap->__map[nr >> 5]) >> (nr & 0x1f)) & 1;
112
}
113

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

  
119
static inline void pushw(CPUX86State *env, int val)
120
{
121
    env->regs[R_ESP] = (env->regs[R_ESP] & ~0xffff) | 
122
        ((env->regs[R_ESP] - 2) & 0xffff);
123
    *(uint16_t *)seg_to_linear(env->segs[R_SS], env->regs[R_ESP]) = val;
124
}
125

  
126
static inline unsigned int get_vflags(CPUX86State *env)
127
{
128
    unsigned int eflags;
129
    eflags = env->eflags & ~(VM_MASK | RF_MASK | IF_MASK);
130
    if (eflags & VIF_MASK)
131
        eflags |= IF_MASK;
132
    return eflags;
133
}
134

  
135
void save_v86_state(CPUX86State *env)
136
{
137
    TaskState *ts = env->opaque;
138
#ifdef DEBUG_VM86
139
    printf("save_v86_state\n");
140
#endif
141

  
142
    /* put the VM86 registers in the userspace register structure */
143
    ts->target_v86->regs.eax = tswap32(env->regs[R_EAX]);
144
    ts->target_v86->regs.ebx = tswap32(env->regs[R_EBX]);
145
    ts->target_v86->regs.ecx = tswap32(env->regs[R_ECX]);
146
    ts->target_v86->regs.edx = tswap32(env->regs[R_EDX]);
147
    ts->target_v86->regs.esi = tswap32(env->regs[R_ESI]);
148
    ts->target_v86->regs.edi = tswap32(env->regs[R_EDI]);
149
    ts->target_v86->regs.ebp = tswap32(env->regs[R_EBP]);
150
    ts->target_v86->regs.esp = tswap32(env->regs[R_ESP]);
151
    ts->target_v86->regs.eip = tswap32(env->eip);
152
    ts->target_v86->regs.cs = tswap16(env->segs[R_CS]);
153
    ts->target_v86->regs.ss = tswap16(env->segs[R_SS]);
154
    ts->target_v86->regs.ds = tswap16(env->segs[R_DS]);
155
    ts->target_v86->regs.es = tswap16(env->segs[R_ES]);
156
    ts->target_v86->regs.fs = tswap16(env->segs[R_FS]);
157
    ts->target_v86->regs.gs = tswap16(env->segs[R_GS]);
158
    ts->target_v86->regs.eflags = tswap32(env->eflags);
159

  
160
    /* restore 32 bit registers */
161
    env->regs[R_EAX] = ts->vm86_saved_regs.eax;
162
    env->regs[R_EBX] = ts->vm86_saved_regs.ebx;
163
    env->regs[R_ECX] = ts->vm86_saved_regs.ecx;
164
    env->regs[R_EDX] = ts->vm86_saved_regs.edx;
165
    env->regs[R_ESI] = ts->vm86_saved_regs.esi;
166
    env->regs[R_EDI] = ts->vm86_saved_regs.edi;
167
    env->regs[R_EBP] = ts->vm86_saved_regs.ebp;
168
    env->regs[R_ESP] = ts->vm86_saved_regs.esp;
169
    env->eflags = ts->vm86_saved_regs.eflags;
170
    env->eip = ts->vm86_saved_regs.eip;
171
    
172
    cpu_x86_load_seg(env, R_CS, ts->vm86_saved_regs.cs);
173
    cpu_x86_load_seg(env, R_SS, ts->vm86_saved_regs.ss);
174
    cpu_x86_load_seg(env, R_DS, ts->vm86_saved_regs.ds);
175
    cpu_x86_load_seg(env, R_ES, ts->vm86_saved_regs.es);
176
    cpu_x86_load_seg(env, R_FS, ts->vm86_saved_regs.fs);
177
    cpu_x86_load_seg(env, R_GS, ts->vm86_saved_regs.gs);
178
}
179

  
180
/* return from vm86 mode to 32 bit. The vm86() syscall will return
181
   'retval' */
182
static inline void return_to_32bit(CPUX86State *env, int retval)
183
{
184
#ifdef DEBUG_VM86
185
    printf("return_to_32bit: ret=0x%x\n", retval);
186
#endif
187
    save_v86_state(env);
188
    env->regs[R_EAX] = retval;
189
}
190

  
191
/* handle VM86 interrupt (NOTE: the CPU core currently does not
192
   support TSS interrupt revectoring, so this code is always executed) */
193
static void do_int(CPUX86State *env, int intno)
194
{
195
    TaskState *ts = env->opaque;
196
    uint32_t *int_ptr, segoffs;
197
    
198
    if (env->segs[R_CS] == TARGET_BIOSSEG)
199
        goto cannot_handle; /* XXX: I am not sure this is really useful */
200
    if (is_revectored(intno, &ts->target_v86->int_revectored))
201
        goto cannot_handle;
202
    if (intno == 0x21 && is_revectored((env->regs[R_EAX] >> 8) & 0xff, 
203
                                       &ts->target_v86->int21_revectored))
204
        goto cannot_handle;
205
    int_ptr = (uint32_t *)(intno << 2);
206
    segoffs = tswap32(*int_ptr);
207
    if ((segoffs >> 16) == TARGET_BIOSSEG)
208
        goto cannot_handle;
209
#ifdef DEBUG_VM86
210
    printf("VM86: emulating int 0x%x. CS:IP=%04x:%04x\n", 
211
           intno, segoffs >> 16, segoffs & 0xffff);
212
#endif
213
    /* save old state */
214
    pushw(env, get_vflags(env));
215
    pushw(env, env->segs[R_CS]);
216
    pushw(env, env->eip);
217
    /* goto interrupt handler */
218
    env->eip = segoffs & 0xffff;
219
    cpu_x86_load_seg(env, R_CS, segoffs >> 16);
220
    env->eflags &= ~(VIF_MASK | TF_MASK);
221
    return;
222
 cannot_handle:
223
#ifdef DEBUG_VM86
224
    printf("VM86: return to 32 bits int 0x%x\n", intno);
225
#endif
226
    return_to_32bit(env, TARGET_VM86_INTx | (intno << 8));
227
}
228

  
109 229
void cpu_loop(struct CPUX86State *env)
110 230
{
111
    int err;
231
    int trapnr;
112 232
    uint8_t *pc;
113 233
    target_siginfo_t info;
114 234

  
115 235
    for(;;) {
116
        err = cpu_x86_exec(env);
236
        trapnr = cpu_x86_exec(env);
117 237
        pc = env->seg_cache[R_CS].base + env->eip;
118
        switch(err) {
238
        switch(trapnr) {
119 239
        case EXCP0D_GPF:
120 240
            if (env->eflags & VM_MASK) {
121
                TaskState *ts;
122
                int ret;
123 241
#ifdef DEBUG_VM86
124
                printf("VM86 exception %04x:%08x %02x\n",
125
                       env->segs[R_CS], env->eip, pc[0]);
242
                printf("VM86 exception %04x:%08x %02x %02x\n",
243
                       env->segs[R_CS], env->eip, pc[0], pc[1]);
126 244
#endif
127 245
                /* VM86 mode */
128
                ts = env->opaque;
129

  
130
                /* XXX: add all cases */
131 246
                switch(pc[0]) {
132 247
                case 0xcd: /* int */
133 248
                    env->eip += 2;
134
                    ret = TARGET_VM86_INTx | (pc[1] << 8);
249
                    do_int(env, pc[1]);
250
                    break;
251
                case 0x66:
252
                    switch(pc[1]) {
253
                    case 0xfb: /* sti */
254
                    case 0x9d: /* popf */
255
                    case 0xcf: /* iret */
256
                        env->eip += 2;
257
                        return_to_32bit(env, TARGET_VM86_STI);
258
                        break;
259
                    default:
260
                        goto vm86_gpf;
261
                    }
262
                    break;
263
                case 0xfb: /* sti */
264
                case 0x9d: /* popf */
265
                case 0xcf: /* iret */
266
                    env->eip++;
267
                    return_to_32bit(env, TARGET_VM86_STI);
135 268
                    break;
136 269
                default:
270
                vm86_gpf:
137 271
                    /* real VM86 GPF exception */
138
                    ret = TARGET_VM86_UNKNOWN;
272
                    return_to_32bit(env, TARGET_VM86_UNKNOWN);
139 273
                    break;
140 274
                }
141
#ifdef DEBUG_VM86
142
                printf("ret=0x%x\n", ret);
143
#endif
144
                /* put the VM86 registers in the userspace register structure */
145
                ts->target_v86->regs.eax = tswap32(env->regs[R_EAX]);
146
                ts->target_v86->regs.ebx = tswap32(env->regs[R_EBX]);
147
                ts->target_v86->regs.ecx = tswap32(env->regs[R_ECX]);
148
                ts->target_v86->regs.edx = tswap32(env->regs[R_EDX]);
149
                ts->target_v86->regs.esi = tswap32(env->regs[R_ESI]);
150
                ts->target_v86->regs.edi = tswap32(env->regs[R_EDI]);
151
                ts->target_v86->regs.ebp = tswap32(env->regs[R_EBP]);
152
                ts->target_v86->regs.esp = tswap32(env->regs[R_ESP]);
153
                ts->target_v86->regs.eip = tswap32(env->eip);
154
                ts->target_v86->regs.cs = tswap16(env->segs[R_CS]);
155
                ts->target_v86->regs.ss = tswap16(env->segs[R_SS]);
156
                ts->target_v86->regs.ds = tswap16(env->segs[R_DS]);
157
                ts->target_v86->regs.es = tswap16(env->segs[R_ES]);
158
                ts->target_v86->regs.fs = tswap16(env->segs[R_FS]);
159
                ts->target_v86->regs.gs = tswap16(env->segs[R_GS]);
160

  
161
                /* restore 32 bit registers */
162
                env->regs[R_EBX] = ts->vm86_saved_regs.ebx;
163
                env->regs[R_ECX] = ts->vm86_saved_regs.ecx;
164
                env->regs[R_EDX] = ts->vm86_saved_regs.edx;
165
                env->regs[R_ESI] = ts->vm86_saved_regs.esi;
166
                env->regs[R_EDI] = ts->vm86_saved_regs.edi;
167
                env->regs[R_EBP] = ts->vm86_saved_regs.ebp;
168
                env->regs[R_ESP] = ts->vm86_saved_regs.esp;
169
                env->eflags = ts->vm86_saved_regs.eflags;
170
                env->eip = ts->vm86_saved_regs.eip;
171

  
172
                cpu_x86_load_seg(env, R_CS, ts->vm86_saved_regs.cs);
173
                cpu_x86_load_seg(env, R_SS, ts->vm86_saved_regs.ss);
174
                cpu_x86_load_seg(env, R_DS, ts->vm86_saved_regs.ds);
175
                cpu_x86_load_seg(env, R_ES, ts->vm86_saved_regs.es);
176
                cpu_x86_load_seg(env, R_FS, ts->vm86_saved_regs.fs);
177
                cpu_x86_load_seg(env, R_GS, ts->vm86_saved_regs.gs);
178

  
179
                env->regs[R_EAX] = ret;
180 275
            } else {
181 276
                if (pc[0] == 0xcd && pc[1] == 0x80) {
182 277
                    /* syscall */
......
200 295
            }
201 296
            break;
202 297
        case EXCP00_DIVZ:
203
            /* division by zero */
204
            info.si_signo = SIGFPE;
205
            info.si_errno = 0;
206
            info.si_code = TARGET_FPE_INTDIV;
207
            info._sifields._sigfault._addr = env->eip;
208
            queue_signal(info.si_signo, &info);
298
            if (env->eflags & VM_MASK) {
299
                do_int(env, trapnr);
300
            } else {
301
                /* division by zero */
302
                info.si_signo = SIGFPE;
303
                info.si_errno = 0;
304
                info.si_code = TARGET_FPE_INTDIV;
305
                info._sifields._sigfault._addr = env->eip;
306
                queue_signal(info.si_signo, &info);
307
            }
209 308
            break;
210 309
        case EXCP04_INTO:
211 310
        case EXCP05_BOUND:
212
            info.si_signo = SIGSEGV;
213
            info.si_errno = 0;
214
            info.si_code = 0;
215
            info._sifields._sigfault._addr = 0;
216
            queue_signal(info.si_signo, &info);
311
            if (env->eflags & VM_MASK) {
312
                do_int(env, trapnr);
313
            } else {
314
                info.si_signo = SIGSEGV;
315
                info.si_errno = 0;
316
                info.si_code = 0;
317
                info._sifields._sigfault._addr = 0;
318
                queue_signal(info.si_signo, &info);
319
            }
217 320
            break;
218 321
        case EXCP06_ILLOP:
219 322
            info.si_signo = SIGILL;
......
226 329
            /* just indicate that signals should be handled asap */
227 330
            break;
228 331
        default:
229
            fprintf(stderr, "0x%08lx: Unknown exception CPU %d, aborting\n", 
230
                    (long)pc, err);
332
            fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n", 
333
                    (long)pc, trapnr);
231 334
            abort();
232 335
        }
233 336
        process_pending_signals(env);
b/linux-user/qemu.h
74 74
void process_pending_signals(void *cpu_env);
75 75
void signal_init(void);
76 76
int queue_signal(int sig, target_siginfo_t *info);
77
void save_v86_state(CPUX86State *env);
77 78

  
78 79
#endif
b/linux-user/signal.c
198 198
{
199 199
    int host_sig;
200 200
    host_sig = target_to_host_signal(sig);
201
    fprintf(stderr, "gemu: uncaught target signal %d (%s) - exiting\n", 
201
    fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n", 
202 202
            sig, strsignal(host_sig));
203 203
#if 1
204 204
    _exit(-host_sig);
......
223 223
    target_ulong handler;
224 224

  
225 225
#if defined(DEBUG_SIGNAL)
226
    fprintf(stderr, "queue_sigal: sig=%d\n", 
226
    fprintf(stderr, "queue_signal: sig=%d\n", 
227 227
            sig);
228 228
#endif
229 229
    k = &sigact_table[sig - 1];
......
317 317
    if (sig < 1 || sig > TARGET_NSIG)
318 318
        return;
319 319
#if defined(DEBUG_SIGNAL)
320
    fprintf(stderr, "gemu: got signal %d\n", sig);
320
    fprintf(stderr, "qemu: got signal %d\n", sig);
321 321
    dump_regs(puc);
322 322
#endif
323 323
    host_to_target_siginfo_noswap(&tinfo, info);
......
538 538
	/* non-iBCS2 extensions.. */
539 539
	err |= __put_user(mask, &sc->oldmask);
540 540
	err |= __put_user(/*current->thread.cr2*/ 0, &sc->cr2);
541

  
542 541
	return err;
543 542
}
544 543

  
......
859 858

  
860 859
 handle_signal:
861 860
#ifdef DEBUG_SIGNAL
862
    fprintf(stderr, "gemu: process signal %d\n", sig);
861
    fprintf(stderr, "qemu: process signal %d\n", sig);
863 862
#endif
864 863
    /* dequeue signal */
865 864
    q = k->first;
......
893 892
           end of the signal execution (see do_sigreturn) */
894 893
        host_to_target_sigset(&target_old_set, &old_set);
895 894

  
895
        /* if the CPU is in VM86 mode, we restore the 32 bit values */
896
#ifdef TARGET_I386
897
        {
898
            CPUX86State *env = cpu_env;
899
            if (env->eflags & VM_MASK)
900
                save_v86_state(env);
901
        }
902
#endif
896 903
        /* prepare the stack frame of the virtual CPU */
897 904
        if (k->sa.sa_flags & TARGET_SA_SIGINFO)
898 905
            setup_rt_frame(sig, k, &q->info, &target_old_set, cpu_env);
b/syscall-i386.h
755 755
    unsigned int flags;
756 756
};
757 757

  
758

  
759
/* vm86 defines */
760

  
761
#define TARGET_BIOSSEG		0x0f000
762

  
758 763
#define TARGET_VM86_SIGNAL	0	/* return due to signal */
759 764
#define TARGET_VM86_UNKNOWN	1	/* unhandled GP fault - IO-instruction or similar */
760 765
#define TARGET_VM86_INTx	2	/* int3/int x instruction (ARG = x) */

Also available in: Unified diff