diff --git a/kvm/test/config-x86-common.mak b/kvm/test/config-x86-common.mak
index c97de52..800b635 100644
--- a/kvm/test/config-x86-common.mak
+++ b/kvm/test/config-x86-common.mak
@@ -59,6 +59,8 @@ $(TEST_DIR)/realmode.o: bits = 32
 
 $(TEST_DIR)/msr.flat: $(cstart.o) $(TEST_DIR)/msr.o
 
+$(TEST_DIR)/idt_test.flat: $(cstart.o) $(TEST_DIR)/idt.o $(TEST_DIR)/idt_test.o
+
 arch_clean:
 	$(RM) $(TEST_DIR)/*.o $(TEST_DIR)/*.flat \
 	$(TEST_DIR)/.*.d $(TEST_DIR)/lib/.*.d $(TEST_DIR)/lib/*.o
diff --git a/kvm/test/config-x86_64.mak b/kvm/test/config-x86_64.mak
index d8fd2b5..f9cd121 100644
--- a/kvm/test/config-x86_64.mak
+++ b/kvm/test/config-x86_64.mak
@@ -5,6 +5,6 @@ ldarch = elf64-x86-64
 CFLAGS += -D__x86_64__
 
 tests = $(TEST_DIR)/access.flat $(TEST_DIR)/apic.flat \
-	  $(TEST_DIR)/emulator.flat
+	  $(TEST_DIR)/emulator.flat $(TEST_DIR)/idt_test.flat
 
 include config-x86-common.mak
diff --git a/kvm/test/lib/x86/idt.h b/kvm/test/lib/x86/idt.h
new file mode 100644
index 0000000..f449f01
--- /dev/null
+++ b/kvm/test/lib/x86/idt.h
@@ -0,0 +1,19 @@
+#ifndef __IDT_TEST__
+#define __IDT_TEST__
+
+void setup_idt(void);
+
+#define EXCEPTION_REGION_BEGIN(r, lb) \
+    asm volatile("pushq $"lb"\n\t" \
+                 "mov $2, %0\n\t" \
+                 : "=r"(r))
+#define EXCEPTION_REGION_END(r, lb) \
+    asm volatile("popq %%rdx\n\t" \
+		 "mov $0, %0\n\t" \
+                 lb":\n\t": \
+                 "=r"(r) :: "%rdx")
+
+#define UD_VECTOR   6
+#define GP_VECTOR   13
+
+#endif
diff --git a/kvm/test/x86/idt.c b/kvm/test/x86/idt.c
new file mode 100644
index 0000000..e3172cb
--- /dev/null
+++ b/kvm/test/x86/idt.c
@@ -0,0 +1,85 @@
+#include "idt.h"
+
+typedef struct {
+    unsigned short offset0;
+    unsigned short selector;
+    unsigned short ist : 3;
+    unsigned short : 5;
+    unsigned short type : 4;
+    unsigned short : 1;
+    unsigned short dpl : 2;
+    unsigned short p : 1;
+    unsigned short offset1;
+    unsigned offset2;
+    unsigned reserved;
+} idt_entry_t;
+
+static idt_entry_t idt[256];
+
+typedef struct {
+    unsigned short limit;
+    unsigned long linear_addr;
+} __attribute__((packed)) descriptor_table_t;
+
+void lidt(idt_entry_t *idt, int nentries)
+{
+    descriptor_table_t dt;
+
+    dt.limit = nentries * sizeof(*idt) - 1;
+    dt.linear_addr = (unsigned long)idt;
+    asm volatile ("lidt %0" : : "m"(dt));
+}
+
+unsigned short read_cs()
+{
+    unsigned short r;
+
+    asm volatile ("mov %%cs, %0" : "=r"(r));
+    return r;
+}
+
+void memset(void *a, unsigned char v, int n)
+{
+    unsigned char *x = a;
+
+    while (n--)
+	*x++ = v;
+}
+
+void set_idt_entry(idt_entry_t *e, void *addr, int dpl)
+{
+    memset(e, 0, sizeof *e);
+    e->offset0 = (unsigned long)addr;
+    e->selector = read_cs();
+    e->ist = 0;
+    e->type = 14;
+    e->dpl = dpl;
+    e->p = 1;
+    e->offset1 = (unsigned long)addr >> 16;
+    e->offset2 = (unsigned long)addr >> 32;
+}
+
+void setup_idt(void)
+{
+    asm volatile (".section .text.ud \n\t"
+                  "ud_fault: \n\t"
+		  "mov 40(%%rsp), %%rax\n\t"
+                  "mov %%rax, (%%rsp)\n\t"
+                  "mov $6, %%rax\n\t"
+                  "iretq \n\t"
+                  ".section .text":);
+
+    asm volatile (".section .text.gp \n\t"
+                  "gp_fault: \n\t"
+                  "pop %%rax \n\t"
+		  "mov 40(%%rsp), %%rax\n\t"
+                  "mov %%rax, (%%rsp)\n\t"
+                  "mov $13, %%rax\n\t"
+                  "iretq \n\t"
+                  ".section .text":);
+    extern char ud_fault, gp_fault;
+
+    lidt(idt, 256);
+    set_idt_entry(&idt[6], &ud_fault, 0);
+    set_idt_entry(&idt[13], &gp_fault, 0);
+}
diff --git a/kvm/test/x86/idt_test.c b/kvm/test/x86/idt_test.c
new file mode 100644
index 0000000..08f0da8
--- /dev/null
+++ b/kvm/test/x86/idt_test.c
@@ -0,0 +1,48 @@
+#include "libcflat.h"
+#include "idt.h"
+
+int test_ud2(void)
+{
+    int r;
+    EXCEPTION_REGION_BEGIN(r, "fixed_ud");
+    asm volatile("ud2;\n\t");
+    EXCEPTION_REGION_END(r, "fixed_ud");
+    return r;
+}
+
+int test_gp(void)
+{
+    int r;
+    EXCEPTION_REGION_BEGIN(r, "fixed_gp");
+    asm volatile("mov $0xffffffff, %%rax\n\t"
+		 "mov %%rax, %%cr4\n\t":);
+    EXCEPTION_REGION_END(r, "fixed_gp");
+    return r;
+}
+
+int test(void)
+{
+    int r;
+
+    setup_idt();
+    printf("GP testing: ");
+    r = test_gp();
+    if (r == GP_VECTOR)
+        printf("Pass!\n");
+    else
+        printf("Fail!\n");
+    printf("UD testing: ");
+    r = test_ud2();
+    if (r == UD_VECTOR)
+        printf("Pass!\n");
+    else
+        printf("Fail!\n");
+    return 0;
+}
+
+int main(void)
+{
+    printf("start testing\n");
+    test();
+    return 0;
+}
