@@ -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
@@ -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
new file mode 100644
@@ -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
new file mode 100644
@@ -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);
+}
new file mode 100644
@@ -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;
+}