Skip to contentSkip to conversation

Various (mostly) x86-64 related patches

PATCH In review Filip Navara 1 participant 3 messages Jul 21, 2005 – Jul 23, 2005

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Various (mostly) x86-64 related patches

qemu-20050718-01-vaddr.patch
Fix TB virtual page map for x86-64 (at least 48bits of VA must
be honoured).

qemu-20050718-02-insns.patch
- Add support for AMD cache info MCR.
- Fix INVLPG instruction in 64bit mode.
- Implement the ENTER instruction for 64bit mode.
- Add dummy support for MCA, PAT, MTRR and CLFLUSH.
- Correct size of 16bit stack pushes in 64bit mode.
- Correct segment arithmetics for various instructions in 64bit
mode.
- Correctly honour the ADDR prefix for these instrutions:
maskmov; mov EAX, Ov; mov Ov, EAX
- Fix the implicit 64bit semantics for these instrutions:
ret im; lcall; lret
- Support the PREFETCHW instruction.

qemu-20050718-03-apic.patch
* vl.h (ioapic_init, ioapic_set_irq): Declare.
* hw/apic.c (apic_get_current_count, apic_timer_update):
Fix division by zero if s->initial_count == ~0. (apic_get_delivery_bitmask, apic_bus_deliver, apic_deliver, apic_mem_readl, apic_mem_writel):
Implent basic interrupt control and delivery (no arbitration). (ioapic_service, ioapic_set_irq, ioapic_mem_readl, ioapic_mem_writel, ioapic_mem_read, ioapic_mem_write, ioapic_init): Implement I/O APIC.
(apic_init): Automatically assign ID to the APIC and link it to local APIC list.
(apic_reset, ioapic_reset): Add reset handlers. (apic_save, apic_load, ioapic_save, ioapic_load):
Add save and load handlers.
* hw/i8259.c (pic_set_irq): Forward interrupts to I/O APIC.
* hw/pc.c (pc_init1): Initialize the I/O APIC. (cpu_get_pic_interrupt): Compile the APIC stuff even in non-x86-64 case.

qemu-20050718-04-doc.patch
Minor qemu-img documentation update.

qemu-20050718-05-sdl.patch
Don't make the SDL window resizable. It doesn't make sense to
mark it that way since we really don't handle it (either by scrolling or scaling).

Index: sdl.c
===================================================================
RCS file: /cvsroot/qemu/qemu/sdl.c,v
retrieving revision 1.21

sdl.c +0 -1
diff -u -r1.21 sdl.c
@@ -53,7 +53,6 @@
     //    printf("resizing to %d %d\n", w, h);
 
     flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL;
-    flags |= SDL_RESIZABLE;
     if (gui_fullscreen)
         flags |= SDL_FULLSCREEN;
     screen = SDL_SetVideoMode(w, h, 0, flags);

Index: exec.c
===================================================================
RCS file: /cvsroot/qemu/qemu/exec.c,v
retrieving revision 1.60

exec.c +27 -16

105 lines not on this page · raw message

Index: target-i386/cpu.h
===================================================================
RCS file: /cvsroot/qemu/qemu/target-i386/cpu.h,v
retrieving revision 1.30

cpu.h +30 -19

68 lines not on this page · raw message

Index: target-i386/exec.h
===================================================================
RCS file: /cvsroot/qemu/qemu/target-i386/exec.h,v
retrieving revision 1.24

exec.h +2 -2
diff -u -r1.24 exec.h
@@ -157,11 +157,11 @@
 void helper_ltr_T0(void);
 void helper_movl_crN_T0(int reg);
 void helper_movl_drN_T0(int reg);
-void helper_invlpg(unsigned int addr);
+void helper_invlpg(target_ulong addr);
 void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0);
 void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3);
 void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4);
-void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr);
+void cpu_x86_flush_tlb(CPUX86State *env, target_ulong addr);
 int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, 
                              int is_write, int is_user, int is_softmmu);
 void tlb_fill(target_ulong addr, int is_write, int is_user, 

Index: target-i386/helper.c
===================================================================
RCS file: /cvsroot/qemu/qemu/target-i386/helper.c,v retrieving revision 1.49

helper.c +36 -2
diff -u -r1.49 helper.c
@@ -1334,6 +1334,20 @@
         ECX = env->cpuid_model[(index - 0x80000002) * 4 + 2];
         EDX = env->cpuid_model[(index - 0x80000002) * 4 + 3];
         break;
+    case 0x80000005:
+        /* cache info (L1 cache) */
+        EAX = 0x01ff01ff;
+        EBX = 0x01ff01ff;
+        ECX = 0x40020140;
+        EDX = 0x40020140;
+        break;
+    case 0x80000006:
+        /* cache info (L2 cache) */
+        EAX = 0;
+        EBX = 0x42004200;
+        ECX = 0x02008140;
+        EDX = 0;
+        break;
     case 0x80000008:
         /* virtual & phys address size in low 2 bytes. */
         EAX = 0x00003028;
@@ -1354,12 +1368,26 @@
 void helper_enter_level(int level, int data32)
 {
     target_ulong ssp;
-    uint32_t esp_mask, esp, ebp;
+    uint32_t esp_mask;
+    target_ulong esp, ebp;
 
     esp_mask = get_sp_mask(env->segs[R_SS].flags);
     ssp = env->segs[R_SS].base;
     ebp = EBP;
     esp = ESP;
+#ifdef TARGET_X86_64
+    if (env->hflags & HF_CS64_MASK) {
+        /* 64 bit */
+        esp -= 8;
+        while (--level) {
+            esp -= 8;
+            ebp -= 8;
+            stq(ssp + esp, ldq(ssp + ebp));
+        }
+        esp -= 8;
+        stq(ssp + esp, T1);
+    } else 
+#endif
     if (data32) {
         /* 32 bit */
         esp -= 4;
@@ -2271,7 +2299,7 @@
     env->dr[reg] = T0;
 }
 
-void helper_invlpg(unsigned int addr)
+void helper_invlpg(target_ulong addr)
 {
     cpu_x86_flush_tlb(env, addr);
 }
@@ -2332,6 +2360,9 @@
     case MSR_STAR:
         env->star = val;
         break;
+    case MSR_PAT:
+        env->pat = val;
+        break;
 #ifdef TARGET_X86_64
     case MSR_LSTAR:
         env->lstar = val;
@@ -2379,6 +2410,9 @@
         break;
     case MSR_STAR:
         val = env->star;
+        break;
+    case MSR_PAT:
+        val = env->pat;
         break;
 #ifdef TARGET_X86_64
     case MSR_LSTAR:

Index: target-i386/helper2.c
===================================================================
RCS file: /cvsroot/qemu/qemu/target-i386/helper2.c,v retrieving revision 1.34

helper2.c +7 -2
diff -u -r1.34 helper2.c
@@ -106,7 +106,9 @@
         env->cpuid_version = (family << 8) | (model << 4) | stepping;
         env->cpuid_features = (CPUID_FP87 | CPUID_DE | CPUID_PSE |
                                CPUID_TSC | CPUID_MSR | CPUID_MCE |
-                               CPUID_CX8 | CPUID_PGE | CPUID_CMOV);
+                               CPUID_CX8 | CPUID_PGE | CPUID_CMOV |
+                               CPUID_PAT);
+        env->pat = 0x0007040600070406ULL;
         env->cpuid_ext_features = 0;
         env->cpuid_features |= CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | CPUID_PAE | CPUID_SEP;
         env->cpuid_xlevel = 0;
@@ -128,6 +130,9 @@
         env->cpuid_ext2_features = (env->cpuid_features & 0x0183F3FF);
         env->cpuid_ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_SYSCALL;
         env->cpuid_xlevel = 0x80000008;
+
+        /* these features are needed for Win64 and aren't fully implemented */
+        env->cpuid_features |= CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA;
 #endif
     }
     cpu_single_env = env;
@@ -546,7 +551,7 @@
 }
 
 /* XXX: also flush 4MB pages */
-void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr)
+void cpu_x86_flush_tlb(CPUX86State *env, target_ulong addr)
 {
     tlb_flush_page(env, addr);
 }

Index: target-i386/op.c
===================================================================
RCS file: /cvsroot/qemu/qemu/target-i386/op.c,v
retrieving revision 1.37

op.c +5 -0
diff -u -r1.37 op.c
@@ -898,6 +898,11 @@
 }
 
 #ifdef TARGET_X86_64
+void op_subq_A0_2(void)
+{
+    A0 -= 2;
+}
+
 void op_subq_A0_8(void)
 {
     A0 -= 8;

Index: target-i386/translate.c
===================================================================
RCS file: /cvsroot/qemu/qemu/target-i386/translate.c,v retrieving revision 1.49

translate.c +113 -33

286 lines not on this page · raw message

Index: vl.h
===================================================================
RCS file: /cvsroot/qemu/qemu/vl.h,v
retrieving revision 1.79

vl.h +2 -0
diff -u -r1.79 vl.h
@@ -703,6 +703,8 @@
 /* APIC */
 int apic_init(CPUState *env);
 int apic_get_interrupt(CPUState *env);
+int ioapic_init(void);
+void ioapic_set_irq(uint32_t vector, int level);
 
 /* i8254.c */
 

Index: hw/apic.c
===================================================================
RCS file: /cvsroot/qemu/qemu/hw/apic.c,v
retrieving revision 1.2

apic.c +526 -40

729 lines not on this page · raw message

Index: hw/i8259.c
===================================================================
RCS file: /cvsroot/qemu/qemu/hw/i8259.c,v
retrieving revision 1.16

i8259.c +1 -0
diff -u -r1.16 i8259.c
@@ -186,6 +186,7 @@
     }
 #endif
     pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
+    ioapic_set_irq(irq, level);
     pic_update_irq(s);
 }
 

Index: hw/pc.c
===================================================================
RCS file: /cvsroot/qemu/qemu/hw/pc.c,v
retrieving revision 1.38

pc.c +3 -3
diff -u -r1.38 pc.c
@@ -70,7 +70,6 @@
 {
     int intno;
 
-#ifdef TARGET_X86_64
     intno = apic_get_interrupt(env);
     if (intno >= 0) {
         /* set irq request if a PIC irq is still pending */
@@ -78,7 +77,6 @@
         pic_update_irq(isa_pic); 
         return intno;
     }
-#endif
     /* read the irq from the PIC */
     intno = pic_read_irq(isa_pic);
     return intno;
@@ -557,8 +555,10 @@
     register_ioport_read(0x92, 1, 1, ioport92_read, NULL);
     register_ioport_write(0x92, 1, 1, ioport92_write, NULL);
 
-    if (pci_enabled)
+    if (pci_enabled) {
         apic_init(cpu_single_env);
+        ioapic_init();
+    }
     isa_pic = pic_init(pic_irq_request, cpu_single_env);
     pit = pit_init(0x40, 0);
 

Index: qemu-img.texi
===================================================================
RCS file: /cvsroot/qemu/qemu/qemu-img.texi,v
retrieving revision 1.1

qemu-img.texi +1 -2
diff -u -r1.1 qemu-img.texi
@@ -44,8 +44,7 @@
 image format in QEMU. It is supported only for compatibility with
 previous versions. It does not work on win32.
 @item vmdk
-VMware 3 and 4 compatible image format. Currently only supported as
-read-only.
+VMware 3 and 4 compatible image format.
 @item cloop
 Linux Compressed Loop image, useful only to reuse directly compressed
 CD-ROM images present for example in the Knoppix CD-ROMs.
#1 lore raw

Filip Navara wrote:
[snip]

Quoted 5 lines

qemu-20050718-02-insns.patch
- Add support for AMD cache info MCR.
- Fix INVLPG instruction in 64bit mode.
- Implement the ENTER instruction for 64bit mode.
- Add dummy support for MCA, PAT, MTRR and CLFLUSH.

Quoted 8 lines

- Correct size of 16bit stack pushes in 64bit mode.
- Correct segment arithmetics for various instructions in 64bit
mode.
- Correctly honour the ADDR prefix for these instrutions:
maskmov; mov EAX, Ov; mov Ov, EAX
- Fix the implicit 64bit semantics for these instrutions:
ret im; lcall; lret
- Support the PREFETCHW instruction.

This time with the correct patch (qemu-20050721-02-insns.patch).

Quoted 1 line

qemu-20050718-03-apic.patch

[snip]
I forgot to credit malc_ for his extensive testing, ideas and general help with this patch. Thanks!

- Filip

Index: target-i386/cpu.h
===================================================================
RCS file: /cvsroot/qemu/qemu/target-i386/cpu.h,v
retrieving revision 1.30

cpu.h +30 -19
diff -u -r1.30 cpu.h
@@ -214,6 +214,12 @@
 #define MSR_IA32_SYSENTER_ESP           0x175
 #define MSR_IA32_SYSENTER_EIP           0x176
 
+#define MSR_MCG_CAP                     0x179
+#define MSR_MCG_STATUS                  0x17a
+#define MSR_MCG_CTL                     0x17b
+
+#define MSR_PAT                         0x277
+
 #define MSR_EFER                        0xc0000080
 
 #define MSR_EFER_SCE   (1 << 0)
@@ -231,26 +237,29 @@
 #define MSR_KERNELGSBASE                0xc0000102
 
 /* cpuid_features bits */
-#define CPUID_FP87 (1 << 0)
-#define CPUID_VME  (1 << 1)
-#define CPUID_DE   (1 << 2)
-#define CPUID_PSE  (1 << 3)
-#define CPUID_TSC  (1 << 4)
-#define CPUID_MSR  (1 << 5)
-#define CPUID_PAE  (1 << 6)
-#define CPUID_MCE  (1 << 7)
-#define CPUID_CX8  (1 << 8)
-#define CPUID_APIC (1 << 9)
-#define CPUID_SEP  (1 << 11) /* sysenter/sysexit */
-#define CPUID_MTRR (1 << 12)
-#define CPUID_PGE  (1 << 13)
-#define CPUID_MCA  (1 << 14)
-#define CPUID_CMOV (1 << 15)
+#define CPUID_FP87    (1 << 0)
+#define CPUID_VME     (1 << 1)
+#define CPUID_DE      (1 << 2)
+#define CPUID_PSE     (1 << 3)
+#define CPUID_TSC     (1 << 4)
+#define CPUID_MSR     (1 << 5)
+#define CPUID_PAE     (1 << 6)
+#define CPUID_MCE     (1 << 7)
+#define CPUID_CX8     (1 << 8)
+#define CPUID_APIC    (1 << 9)
+#define CPUID_SEP     (1 << 11) /* sysenter/sysexit */
+#define CPUID_MTRR    (1 << 12)
+#define CPUID_PGE     (1 << 13)
+#define CPUID_MCA     (1 << 14)
+#define CPUID_CMOV    (1 << 15)
+#define CPUID_PAT     (1 << 16)
 /* ... */
-#define CPUID_MMX  (1 << 23)
-#define CPUID_FXSR (1 << 24)
-#define CPUID_SSE  (1 << 25)
-#define CPUID_SSE2 (1 << 26)
+#define CPUID_CLFLUSH (1 << 19)
+/* ... */
+#define CPUID_MMX     (1 << 23)
+#define CPUID_FXSR    (1 << 24)
+#define CPUID_SSE     (1 << 25)
+#define CPUID_SSE2    (1 << 26)
 
 #define CPUID_EXT_SS3      (1 << 0)
 #define CPUID_EXT_MONITOR  (1 << 3)
@@ -473,6 +482,8 @@
     target_ulong fmask;
     target_ulong kernelgsbase;
 #endif
+
+    uint64_t pat;
 
     /* temporary data for USE_CODE_COPY mode */
 #ifdef USE_CODE_COPY

Index: target-i386/exec.h
===================================================================
RCS file: /cvsroot/qemu/qemu/target-i386/exec.h,v
retrieving revision 1.24

exec.h +2 -2
diff -u -r1.24 exec.h
@@ -157,11 +157,11 @@
 void helper_ltr_T0(void);
 void helper_movl_crN_T0(int reg);
 void helper_movl_drN_T0(int reg);
-void helper_invlpg(unsigned int addr);
+void helper_invlpg(target_ulong addr);
 void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0);
 void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3);
 void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4);
-void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr);
+void cpu_x86_flush_tlb(CPUX86State *env, target_ulong addr);
 int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, 
                              int is_write, int is_user, int is_softmmu);
 void tlb_fill(target_ulong addr, int is_write, int is_user, 

Index: target-i386/helper.c
===================================================================
RCS file: /cvsroot/qemu/qemu/target-i386/helper.c,v retrieving revision 1.49

helper.c +36 -2
diff -u -r1.49 helper.c
@@ -1334,6 +1334,20 @@
         ECX = env->cpuid_model[(index - 0x80000002) * 4 + 2];
         EDX = env->cpuid_model[(index - 0x80000002) * 4 + 3];
         break;
+    case 0x80000005:
+        /* cache info (L1 cache) */
+        EAX = 0x01ff01ff;
+        EBX = 0x01ff01ff;
+        ECX = 0x40020140;
+        EDX = 0x40020140;
+        break;
+    case 0x80000006:
+        /* cache info (L2 cache) */
+        EAX = 0;
+        EBX = 0x42004200;
+        ECX = 0x02008140;
+        EDX = 0;
+        break;
     case 0x80000008:
         /* virtual & phys address size in low 2 bytes. */
         EAX = 0x00003028;
@@ -1354,12 +1368,26 @@
 void helper_enter_level(int level, int data32)
 {
     target_ulong ssp;
-    uint32_t esp_mask, esp, ebp;
+    uint32_t esp_mask;
+    target_ulong esp, ebp;
 
     esp_mask = get_sp_mask(env->segs[R_SS].flags);
     ssp = env->segs[R_SS].base;
     ebp = EBP;
     esp = ESP;
+#ifdef TARGET_X86_64
+    if (env->hflags & HF_CS64_MASK) {
+        /* 64 bit */
+        esp -= 8;
+        while (--level) {
+            esp -= 8;
+            ebp -= 8;
+            stq(ssp + esp, ldq(ssp + ebp));
+        }
+        esp -= 8;
+        stq(ssp + esp, T1);
+    } else 
+#endif
     if (data32) {
         /* 32 bit */
         esp -= 4;
@@ -2271,7 +2299,7 @@
     env->dr[reg] = T0;
 }
 
-void helper_invlpg(unsigned int addr)
+void helper_invlpg(target_ulong addr)
 {
     cpu_x86_flush_tlb(env, addr);
 }
@@ -2332,6 +2360,9 @@
     case MSR_STAR:
         env->star = val;
         break;
+    case MSR_PAT:
+        env->pat = val;
+        break;
 #ifdef TARGET_X86_64
     case MSR_LSTAR:
         env->lstar = val;
@@ -2379,6 +2410,9 @@
         break;
     case MSR_STAR:
         val = env->star;
+        break;
+    case MSR_PAT:
+        val = env->pat;
         break;
 #ifdef TARGET_X86_64
     case MSR_LSTAR:

Index: target-i386/helper2.c
===================================================================
RCS file: /cvsroot/qemu/qemu/target-i386/helper2.c,v retrieving revision 1.34

helper2.c +7 -2
diff -u -r1.34 helper2.c
@@ -106,7 +106,9 @@
         env->cpuid_version = (family << 8) | (model << 4) | stepping;
         env->cpuid_features = (CPUID_FP87 | CPUID_DE | CPUID_PSE |
                                CPUID_TSC | CPUID_MSR | CPUID_MCE |
-                               CPUID_CX8 | CPUID_PGE | CPUID_CMOV);
+                               CPUID_CX8 | CPUID_PGE | CPUID_CMOV |
+                               CPUID_PAT);
+        env->pat = 0x0007040600070406ULL;
         env->cpuid_ext_features = 0;
         env->cpuid_features |= CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | CPUID_PAE | CPUID_SEP;
         env->cpuid_xlevel = 0;
@@ -128,6 +130,9 @@
         env->cpuid_ext2_features = (env->cpuid_features & 0x0183F3FF);
         env->cpuid_ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_SYSCALL;
         env->cpuid_xlevel = 0x80000008;
+
+        /* these features are needed for Win64 and aren't fully implemented */
+        env->cpuid_features |= CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA;
 #endif
     }
     cpu_single_env = env;
@@ -546,7 +551,7 @@
 }
 
 /* XXX: also flush 4MB pages */
-void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr)
+void cpu_x86_flush_tlb(CPUX86State *env, target_ulong addr)
 {
     tlb_flush_page(env, addr);
 }

Index: target-i386/op.c
===================================================================
RCS file: /cvsroot/qemu/qemu/target-i386/op.c,v
retrieving revision 1.37

op.c +5 -0
diff -u -r1.37 op.c
@@ -898,6 +898,11 @@
 }
 
 #ifdef TARGET_X86_64
+void op_subq_A0_2(void)
+{
+    A0 -= 2;
+}
+
 void op_subq_A0_8(void)
 {
     A0 -= 8;

Index: target-i386/translate.c
===================================================================
RCS file: /cvsroot/qemu/qemu/target-i386/translate.c,v retrieving revision 1.49

translate.c +87 -32

236 lines not on this page · raw message

#2 lore raw

Two more patches...

qemu-20050723-05-apic.diff
EXTINT delivery mode support for I/O APIC.

qemu-20050723-06-div.diff
Raise #DE exception on DIV/IDIV overflows.

apic.c +18 -8
@@ -127,7 +127,7 @@ static void apic_bus_deliver(uint32_t de
             return;
     
         case APIC_DM_EXTINT:
-            /* XXX: implement */
+            /* handled in I/O APIC code */
             break;
 
         default:
@@ -742,24 +742,34 @@ int apic_init(CPUState *env)
 
 static void ioapic_service(IOAPICState *s)
 {
+    uint8_t i;
+    uint8_t trig_mode;
     uint8_t vector;
+    uint8_t delivery_mode;
     uint32_t mask;
     uint64_t entry;
     uint8_t dest;
     uint8_t dest_mode;
+    uint8_t polarity;
 
-    for (vector = 0; vector < IOAPIC_NUM_PINS; vector++) {
-        mask = 1 << vector;
+    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
+        mask = 1 << i;
         if (s->irr & mask) {
-            entry = s->ioredtbl[vector];
+            entry = s->ioredtbl[i];
             if (!(entry & APIC_LVT_MASKED)) {
-                if (!((entry >> 15) & 1))
-                    s->irr &= ~mask;
+                trig_mode = ((entry >> 15) & 1);
                 dest = entry >> 56;
                 dest_mode = (entry >> 11) & 1;
+                delivery_mode = (entry >> 8) & 7;
+                polarity = (entry >> 13) & 1;
+                if (trig_mode == APIC_TRIGGER_EDGE)
+                    s->irr &= ~mask;
+                if (delivery_mode == APIC_DM_EXTINT)
+                    vector = pic_read_irq(isa_pic);
+                else
+                    vector = entry & 0xff;
                 apic_bus_deliver(apic_get_delivery_bitmask(dest, dest_mode),
-                                 (entry >> 8) & 7, entry & 0xff,
-                                 (entry >> 13) & 1, (entry >> 15) & 1);
+                                 delivery_mode, vector, polarity, trig_mode);
             }
         }
     }
helper.c +12 -6
@@ -1209,13 +1209,13 @@ void raise_exception(int exception_index
 #ifdef BUGGY_GCC_DIV64
 /* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we
    call it from another function */
-uint32_t div32(uint32_t *q_ptr, uint64_t num, uint32_t den)
+uint32_t div32(uint64_t *q_ptr, uint64_t num, uint32_t den)
 {
     *q_ptr = num / den;
     return num % den;
 }
 
-int32_t idiv32(int32_t *q_ptr, int64_t num, int32_t den)
+int32_t idiv32(int64_t *q_ptr, int64_t num, int32_t den)
 {
     *q_ptr = num / den;
     return num % den;
@@ -1224,8 +1224,8 @@ int32_t idiv32(int32_t *q_ptr, int64_t n
 
 void helper_divl_EAX_T0(void)
 {
-    unsigned int den, q, r;
-    uint64_t num;
+    unsigned int den, r;
+    uint64_t num, q;
     
     num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
     den = T0;
@@ -1238,14 +1238,17 @@ void helper_divl_EAX_T0(void)
     q = (num / den);
     r = (num % den);
 #endif
+    if (q > 0xffffffff) {
+        raise_exception(EXCP00_DIVZ);
+    }
     EAX = (uint32_t)q;
     EDX = (uint32_t)r;
 }
 
 void helper_idivl_EAX_T0(void)
 {
-    int den, q, r;
-    int64_t num;
+    int den, r;
+    int64_t num, q;
     
     num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
     den = T0;
@@ -1258,6 +1262,9 @@ void helper_idivl_EAX_T0(void)
     q = (num / den);
     r = (num % den);
 #endif
+    if (q > 0x7fffffff || q < -0x7fffffff) {
+        raise_exception(EXCP00_DIVZ);
+    }
     EAX = (uint32_t)q;
     EDX = (uint32_t)r;
 }
op.c +12 -1
@@ -328,7 +328,6 @@ void OPPROTO op_imulq_T0_T1(void)
 #endif
 
 /* division, flags are undefined */
-/* XXX: add exceptions for overflow */
 
 void OPPROTO op_divb_AL_T0(void)
 {
@@ -341,6 +340,9 @@ void OPPROTO op_divb_AL_T0(void)
     }
     q = (num / den) & 0xff;
     r = (num % den) & 0xff;
+    if (q > 0xff) {
+        raise_exception(EXCP00_DIVZ);
+    }
     EAX = (EAX & ~0xffff) | (r << 8) | q;
 }
 
@@ -355,6 +357,9 @@ void OPPROTO op_idivb_AL_T0(void)
     }
     q = (num / den) & 0xff;
     r = (num % den) & 0xff;
+    if (q > 0x7f || q < -0x7f) {
+        raise_exception(EXCP00_DIVZ);
+    }
     EAX = (EAX & ~0xffff) | (r << 8) | q;
 }
 
@@ -369,6 +374,9 @@ void OPPROTO op_divw_AX_T0(void)
     }
     q = (num / den) & 0xffff;
     r = (num % den) & 0xffff;
+    if (q > 0xffff) {
+        raise_exception(EXCP00_DIVZ);
+    }
     EAX = (EAX & ~0xffff) | q;
     EDX = (EDX & ~0xffff) | r;
 }
@@ -384,6 +392,9 @@ void OPPROTO op_idivw_AX_T0(void)
     }
     q = (num / den) & 0xffff;
     r = (num % den) & 0xffff;
+    if (q > 0x7fff || q < -0x7fff) {
+        raise_exception(EXCP00_DIVZ);
+    }
     EAX = (EAX & ~0xffff) | q;
     EDX = (EDX & ~0xffff) | r;
 }