Revision f4beb510

b/linux-user/main.c
100 100
    return 0;
101 101
}
102 102

  
103
void write_dt(void *ptr, unsigned long addr, unsigned long limit, 
104
              int seg32_bit)
103
static void write_dt(void *ptr, unsigned long addr, unsigned long limit, 
104
                     int flags)
105 105
{
106
    unsigned int e1, e2, limit_in_pages;
107
    limit_in_pages = 0;
108
    if (limit > 0xffff) {
109
        limit = limit >> 12;
110
        limit_in_pages = 1;
111
    }
106
    unsigned int e1, e2;
112 107
    e1 = (addr << 16) | (limit & 0xffff);
113 108
    e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
114
    e2 |= limit_in_pages << 23; /* byte granularity */
115
    e2 |= seg32_bit << 22; /* 32 bit segment */
109
    e2 |= flags;
110
    stl((uint8_t *)ptr, e1);
111
    stl((uint8_t *)ptr + 4, e2);
112
}
113

  
114
static void set_gate(void *ptr, unsigned int type, unsigned int dpl, 
115
                     unsigned long addr, unsigned int sel)
116
{
117
    unsigned int e1, e2;
118
    e1 = (addr & 0xffff) | (sel << 16);
119
    e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
116 120
    stl((uint8_t *)ptr, e1);
117 121
    stl((uint8_t *)ptr + 4, e2);
118 122
}
119 123

  
120 124
uint64_t gdt_table[6];
125
uint64_t idt_table[256];
126

  
127
/* only dpl matters as we do only user space emulation */
128
static void set_idt(int n, unsigned int dpl)
129
{
130
    set_gate(idt_table + n, 0, dpl, 0, 0);
131
}
121 132

  
122 133
void cpu_loop(CPUX86State *env)
123 134
{
......
128 139
    for(;;) {
129 140
        trapnr = cpu_x86_exec(env);
130 141
        switch(trapnr) {
142
        case 0x80:
143
            /* linux syscall */
144
            env->regs[R_EAX] = do_syscall(env, 
145
                                          env->regs[R_EAX], 
146
                                          env->regs[R_EBX],
147
                                          env->regs[R_ECX],
148
                                          env->regs[R_EDX],
149
                                          env->regs[R_ESI],
150
                                          env->regs[R_EDI],
151
                                          env->regs[R_EBP]);
152
            break;
153
        case EXCP0B_NOSEG:
154
        case EXCP0C_STACK:
155
            info.si_signo = SIGBUS;
156
            info.si_errno = 0;
157
            info.si_code = TARGET_SI_KERNEL;
158
            info._sifields._sigfault._addr = 0;
159
            queue_signal(info.si_signo, &info);
160
            break;
131 161
        case EXCP0D_GPF:
132 162
            if (env->eflags & VM_MASK) {
133 163
                handle_vm86_fault(env);
134 164
            } else {
135
                pc = env->seg_cache[R_CS].base + env->eip;
136
                if (pc[0] == 0xcd && pc[1] == 0x80) {
137
                    /* syscall */
138
                    env->eip += 2;
139
                    env->regs[R_EAX] = do_syscall(env, 
140
                                                  env->regs[R_EAX], 
141
                                                  env->regs[R_EBX],
142
                                                  env->regs[R_ECX],
143
                                                  env->regs[R_EDX],
144
                                                  env->regs[R_ESI],
145
                                                  env->regs[R_EDI],
146
                                                  env->regs[R_EBP]);
147
                } else {
148
                    /* XXX: more precise info */
149
                    info.si_signo = SIGSEGV;
150
                    info.si_errno = 0;
151
                    info.si_code = TARGET_SI_KERNEL;
152
                    info._sifields._sigfault._addr = 0;
153
                    queue_signal(info.si_signo, &info);
154
                }
165
                info.si_signo = SIGSEGV;
166
                info.si_errno = 0;
167
                info.si_code = TARGET_SI_KERNEL;
168
                info._sifields._sigfault._addr = 0;
169
                queue_signal(info.si_signo, &info);
155 170
            }
156 171
            break;
157 172
        case EXCP0E_PAGE:
......
365 380
    env->regs[R_ESP] = regs->esp;
366 381
    env->eip = regs->eip;
367 382

  
383
    /* linux interrupt setup */
384
    env->idt.base = (void *)idt_table;
385
    env->idt.limit = sizeof(idt_table) - 1;
386
    set_idt(0, 0);
387
    set_idt(1, 0);
388
    set_idt(2, 0);
389
    set_idt(3, 3);
390
    set_idt(4, 3);
391
    set_idt(5, 3);
392
    set_idt(6, 0);
393
    set_idt(7, 0);
394
    set_idt(8, 0);
395
    set_idt(9, 0);
396
    set_idt(10, 0);
397
    set_idt(11, 0);
398
    set_idt(12, 0);
399
    set_idt(13, 0);
400
    set_idt(14, 0);
401
    set_idt(15, 0);
402
    set_idt(16, 0);
403
    set_idt(17, 0);
404
    set_idt(18, 0);
405
    set_idt(19, 0);
406
    set_idt(0x80, 3);
407

  
368 408
    /* linux segment setup */
369 409
    env->gdt.base = (void *)gdt_table;
370 410
    env->gdt.limit = sizeof(gdt_table) - 1;
371
    write_dt(&gdt_table[__USER_CS >> 3], 0, 0xffffffff, 1);
372
    write_dt(&gdt_table[__USER_DS >> 3], 0, 0xffffffff, 1);
411
    write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
412
             DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | 
413
             (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
414
    write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
415
             DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | 
416
             (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
373 417
    cpu_x86_load_seg(env, R_CS, __USER_CS);
374 418
    cpu_x86_load_seg(env, R_DS, __USER_DS);
375 419
    cpu_x86_load_seg(env, R_ES, __USER_DS);
b/op-i386.c
364 364

  
365 365
    num = (EAX & 0xffff);
366 366
    den = (T0 & 0xff);
367
    if (den == 0)
367
    if (den == 0) {
368
        EIP = PARAM1;
368 369
        raise_exception(EXCP00_DIVZ);
370
    }
369 371
    q = (num / den) & 0xff;
370 372
    r = (num % den) & 0xff;
371 373
    EAX = (EAX & 0xffff0000) | (r << 8) | q;
......
377 379

  
378 380
    num = (int16_t)EAX;
379 381
    den = (int8_t)T0;
380
    if (den == 0)
382
    if (den == 0) {
383
        EIP = PARAM1;
381 384
        raise_exception(EXCP00_DIVZ);
385
    }
382 386
    q = (num / den) & 0xff;
383 387
    r = (num % den) & 0xff;
384 388
    EAX = (EAX & 0xffff0000) | (r << 8) | q;
......
390 394

  
391 395
    num = (EAX & 0xffff) | ((EDX & 0xffff) << 16);
392 396
    den = (T0 & 0xffff);
393
    if (den == 0)
397
    if (den == 0) {
398
        EIP = PARAM1;
394 399
        raise_exception(EXCP00_DIVZ);
400
    }
395 401
    q = (num / den) & 0xffff;
396 402
    r = (num % den) & 0xffff;
397 403
    EAX = (EAX & 0xffff0000) | q;
......
404 410

  
405 411
    num = (EAX & 0xffff) | ((EDX & 0xffff) << 16);
406 412
    den = (int16_t)T0;
407
    if (den == 0)
413
    if (den == 0) {
414
        EIP = PARAM1;
408 415
        raise_exception(EXCP00_DIVZ);
416
    }
409 417
    q = (num / den) & 0xffff;
410 418
    r = (num % den) & 0xffff;
411 419
    EAX = (EAX & 0xffff0000) | q;
......
435 443
    
436 444
    num = EAX | ((uint64_t)EDX << 32);
437 445
    den = T0;
438
    if (den == 0)
446
    if (den == 0) {
447
        EIP = PARAM1;
439 448
        raise_exception(EXCP00_DIVZ);
449
    }
440 450
#ifdef BUGGY_GCC_DIV64
441 451
    r = div64(&q, num, den);
442 452
#else
......
454 464
    
455 465
    num = EAX | ((uint64_t)EDX << 32);
456 466
    den = T0;
457
    if (den == 0)
467
    if (den == 0) {
468
        EIP = PARAM1;
458 469
        raise_exception(EXCP00_DIVZ);
470
    }
459 471
#ifdef BUGGY_GCC_DIV64
460 472
    r = idiv64(&q, num, den);
461 473
#else
......
614 626
    EIP = PARAM1;
615 627
}
616 628

  
617
void OPPROTO op_int_im(void)
629
#if 0
630
/* full interrupt support (only useful for real CPU emulation, not
631
   finished) - I won't do it any time soon, finish it if you want ! */
632
void raise_interrupt(int intno, int is_int, int error_code, 
633
                     unsigned int next_eip)
634
{
635
    SegmentDescriptorTable *dt;
636
    uint8_t *ptr;
637
    int type, dpl, cpl;
638
    uint32_t e1, e2;
639
    
640
    dt = &env->idt;
641
    if (intno * 8 + 7 > dt->limit)
642
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
643
    ptr = dt->base + intno * 8;
644
    e1 = ldl(ptr);
645
    e2 = ldl(ptr + 4);
646
    /* check gate type */
647
    type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
648
    switch(type) {
649
    case 5: /* task gate */
650
    case 6: /* 286 interrupt gate */
651
    case 7: /* 286 trap gate */
652
    case 14: /* 386 interrupt gate */
653
    case 15: /* 386 trap gate */
654
        break;
655
    default:
656
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
657
        break;
658
    }
659
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
660
    cpl = env->segs[R_CS] & 3;
661
    /* check privledge if software int */
662
    if (is_int && dpl < cpl)
663
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
664
    /* check valid bit */
665
    if (!(e2 & DESC_P_MASK))
666
        raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
667
}
668

  
669
#else
670

  
671
/*
672
 * is_int is TRUE if coming from the int instruction. next_eip is the
673
 * EIP value AFTER the interrupt instruction. It is only relevant if
674
 * is_int is TRUE.  
675
 */
676
void raise_interrupt(int intno, int is_int, int error_code, 
677
                     unsigned int next_eip)
678
{
679
    SegmentDescriptorTable *dt;
680
    uint8_t *ptr;
681
    int dpl, cpl;
682
    uint32_t e2;
683

  
684
    dt = &env->idt;
685
    ptr = dt->base + (intno * 8);
686
    e2 = ldl(ptr + 4);
687
    
688
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
689
    cpl = 3;
690
    /* check privledge if software int */
691
    if (is_int && dpl < cpl)
692
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
693

  
694
    /* Since we emulate only user space, we cannot do more than
695
       exiting the emulation with the suitable exception and error
696
       code */
697
    if (is_int)
698
        EIP = next_eip;
699
    env->exception_index = intno;
700
    env->error_code = error_code;
701

  
702
    cpu_loop_exit();
703
}
704

  
705
#endif
706

  
707
/* shortcuts to generate exceptions */
708
void raise_exception_err(int exception_index, int error_code)
709
{
710
    raise_interrupt(exception_index, 0, error_code, 0);
711
}
712

  
713
void raise_exception(int exception_index)
714
{
715
    raise_interrupt(exception_index, 0, 0, 0);
716
}
717

  
718
void OPPROTO op_raise_interrupt(void)
618 719
{
619 720
    int intno;
721
    unsigned int next_eip;
620 722
    intno = PARAM1;
621
    EIP = PARAM2;
622
    raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
723
    next_eip = PARAM2;
724
    raise_interrupt(intno, 1, 0, next_eip);
623 725
}
624 726

  
625 727
void OPPROTO op_raise_exception(void)
......
634 736
    int eflags;
635 737
    eflags = cc_table[CC_OP].compute_all();
636 738
    if (eflags & CC_O) {
637
        EIP = PARAM1;
638
        raise_exception(EXCP04_INTO);
739
        raise_interrupt(EXCP04_INTO, 1, 0, PARAM1);
639 740
    }
640 741
    FORCE_RET();
641 742
}
......
674 775
    low = ldsw((uint8_t *)A0);
675 776
    high = ldsw((uint8_t *)A0 + 2);
676 777
    v = (int16_t)T0;
677
    if (v < low || v > high)
778
    if (v < low || v > high) {
779
        EIP = PARAM1;
678 780
        raise_exception(EXCP05_BOUND);
781
    }
679 782
    FORCE_RET();
680 783
}
681 784

  
......
685 788
    low = ldl((uint8_t *)A0);
686 789
    high = ldl((uint8_t *)A0 + 4);
687 790
    v = T0;
688
    if (v < low || v > high)
791
    if (v < low || v > high) {
792
        EIP = PARAM1;
689 793
        raise_exception(EXCP05_BOUND);
794
    }
690 795
    FORCE_RET();
691 796
}
692 797

  
......
1116 1221

  
1117 1222
/* segment handling */
1118 1223

  
1119
/* XXX: use static VM86 information */
1120
void load_seg(int seg_reg, int selector)
1224
/* only works if protected mode and not VM86 */
1225
void load_seg(int seg_reg, int selector, unsigned cur_eip)
1121 1226
{
1122 1227
    SegmentCache *sc;
1123 1228
    SegmentDescriptorTable *dt;
......
1126 1231
    uint8_t *ptr;
1127 1232

  
1128 1233
    sc = &env->seg_cache[seg_reg];
1129
    if (env->eflags & VM_MASK) {
1130
        sc->base = (void *)(selector << 4);
1131
        sc->limit = 0xffff;
1132
        sc->seg_32bit = 0;
1234
    if ((selector & 0xfffc) == 0) {
1235
        /* null selector case */
1236
        if (seg_reg == R_SS) {
1237
            EIP = cur_eip;
1238
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1239
        } else {
1240
            /* XXX: each access should trigger an exception */
1241
            sc->base = NULL;
1242
            sc->limit = 0;
1243
            sc->seg_32bit = 1;
1244
        }
1133 1245
    } else {
1134 1246
        if (selector & 0x4)
1135 1247
            dt = &env->ldt;
1136 1248
        else
1137 1249
            dt = &env->gdt;
1138 1250
        index = selector & ~7;
1139
        if ((index + 7) > dt->limit)
1140
            raise_exception_err(EXCP0D_GPF, selector);
1251
        if ((index + 7) > dt->limit) {
1252
            EIP = cur_eip;
1253
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1254
        }
1141 1255
        ptr = dt->base + index;
1142 1256
        e1 = ldl(ptr);
1143 1257
        e2 = ldl(ptr + 4);
1258
        if (!(e2 & DESC_S_MASK) ||
1259
            (e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) {
1260
            EIP = cur_eip;
1261
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1262
        }
1263

  
1264
        if (seg_reg == R_SS) {
1265
            if ((e2 & (DESC_CS_MASK | DESC_W_MASK)) == 0) {
1266
                EIP = cur_eip;
1267
                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1268
            }
1269
        } else {
1270
            if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) {
1271
                EIP = cur_eip;
1272
                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
1273
            }
1274
        }
1275

  
1276
        if (!(e2 & DESC_P_MASK)) {
1277
            EIP = cur_eip;
1278
            if (seg_reg == R_SS)
1279
                raise_exception_err(EXCP0C_STACK, selector & 0xfffc);
1280
            else
1281
                raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
1282
        }
1283
        
1144 1284
        sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
1145 1285
        sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000);
1146 1286
        if (e2 & (1 << 23))
......
1156 1296

  
1157 1297
void OPPROTO op_movl_seg_T0(void)
1158 1298
{
1159
    load_seg(PARAM1, T0 & 0xffff);
1299
    load_seg(PARAM1, T0 & 0xffff, PARAM2);
1300
}
1301

  
1302
/* faster VM86 version */
1303
void OPPROTO op_movl_seg_T0_vm(void)
1304
{
1305
    int selector;
1306
    
1307
    selector = T0 & 0xffff;
1308
    /* env->segs[] access */
1309
    *(uint32_t *)((char *)env + PARAM1) = selector;
1310
    /* env->seg_cache[] access */
1311
    ((SegmentCache *)((char *)env + PARAM2))->base = (void *)(selector << 4);
1160 1312
}
1161 1313

  
1162 1314
void OPPROTO op_movl_T0_seg(void)

Also available in: Unified diff