On Mon, Mar 30, 2009 at 10:39:21AM +0300, Avi Kivity wrote:
> Gleb Natapov wrote:
>> The patch fixes two problems with task switching.
>> 1. Back link is written to a wrong TSS.
>> 2. Instruction emulation is not needed if the reason for task switch
>>    is a task gate in IDT and access to it is caused by an external even.
>>
>> 2 is currently solved only for VMX since there is not reliable way to
>> skip an instruction in SVM. We should emulate it instead.
>>
>>   
>
> Looks good, but please split into (at least) two patches.  Also please  
> provide a test case so we don't regress again.
>
This what I am using for testing. After running make you should get
kernel.bin that can be booted from grub. Runs on real HW too. I am
planing to add more test.

Signed-off-by: Gleb Natapov <[email protected]>
diff --git a/user/test/x86/kvmtest/Makefile b/user/test/x86/kvmtest/Makefile
new file mode 100644
index 0000000..b93935f
--- /dev/null
+++ b/user/test/x86/kvmtest/Makefile
@@ -0,0 +1,33 @@
+CC=gcc
+AS=gcc
+CFLAGS=-m32 -I. -O2 -Wall
+ASFLAGS=-m32 -I.
+OBJS=kernel.o lib.o boot.o memory.o gdt.o idt.o isrs.o tss.o uart.o
+ALLOBJS=$(OBJS) tests/tests.o
+
+PHONY := all
+all: kernel.bin
+       $(MAKE) -C tests
+
+kernel.bin: $(ALLOBJS) kernel.ld
+       ld -T kernel.ld $(ALLOBJS) -o $@
+
+install: kernel.bin
+       cp $< /boot/
+
+tests/tests.o:
+       $(MAKE) -C tests
+
+-include $(OBJS:.o=.d)
+
+# compile and generate dependency info
+%.o: %.c
+       gcc -c $(CFLAGS) $*.c -o $*.o
+       gcc -MM $(CFLAGS) $*.c > $*.d
+
+PHONY += clean
+clean:
+       $(MAKE) -C tests
+       -rm *.o *~ *.d kernel.bin
+
+.PHONY: $(PHONY)
diff --git a/user/test/x86/kvmtest/boot.S b/user/test/x86/kvmtest/boot.S
new file mode 100644
index 0000000..f74015c
--- /dev/null
+++ b/user/test/x86/kvmtest/boot.S
@@ -0,0 +1,357 @@
+/* boot.S - bootstrap the kernel */
+/* Copyright (C) 1999, 2001  Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define ASM     1
+#include <multiboot.h>
+#include <kernel.h>
+
+.text
+
+.globl  start, _start
+start:
+_start:
+jmp     multiboot_entry
+
+/* Align 32 bits boundary. */
+.align  4
+
+/* Multiboot header. */
+multiboot_header:
+/* magic */
+.long   MULTIBOOT_HEADER_MAGIC
+/* flags */
+.long   MULTIBOOT_HEADER_FLAGS
+/* checksum */
+.long   -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
+#ifndef __ELF__
+       /* header_addr */
+       .long   multiboot_header
+       /* load_addr */
+       .long   _start
+       /* load_end_addr */
+       .long   _edata
+       /* bss_end_addr */
+       .long   _end
+       /* entry_addr */
+       .long   multiboot_entry
+#endif /* ! __ELF__ */
+
+       multiboot_entry:
+       /* Initialize the stack pointer. */
+       movl    $(STACK_START), %esp
+
+       /* Reset EFLAGS. */
+       pushl   $0
+       popf
+
+       /* Push the pointer to the Multiboot information structure. */
+       pushl   %ebx
+       /* Push the magic value. */
+       pushl   %eax
+
+       /* Now enter the C main function... */
+       call    cmain
+
+       /* Halt. */
+       pushl   $halt_message
+       pushl   $0
+       call    printk
+
+       loop:   hlt
+       jmp     loop
+
+.globl isr0
+.globl isr1
+.globl isr2
+.globl isr3
+.globl isr4
+.globl isr5
+.globl isr6
+.globl isr7
+.globl isr8
+.globl isr9
+.globl isr10
+.globl isr11
+.globl isr12
+.globl isr13
+.globl isr14
+.globl isr15
+.globl isr16
+.globl isr17
+.globl isr18
+.globl isr19
+.globl isr20
+.globl isr21
+.globl isr22
+.globl isr23
+.globl isr24
+.globl isr25
+.globl isr26
+.globl isr27
+.globl isr28
+.globl isr29
+.globl isr30
+.globl isr31
+
+/* 0: Divide By Zero Exception */
+isr0:
+       cli
+       pushl $0
+       pushl $0
+       jmp isr_common_stub
+
+/*  1: Debug Exception */
+isr1:
+       cli
+       pushl $0
+       pushl $1
+       jmp isr_common_stub
+
+/*  2: Non Maskable Interrupt Exception */
+isr2:
+       cli
+       pushl $0
+       pushl $2
+       jmp isr_common_stub
+
+/*  3: Int 3 Exception */
+isr3:
+       cli
+       pushl $0
+       pushl $3
+       jmp isr_common_stub
+
+/*  4: INTO Exception */
+isr4:
+       cli
+       pushl $0
+       pushl $4
+       jmp isr_common_stub
+
+/*  5: Out of Bounds Exception */
+isr5:
+       cli
+       pushl $0
+       pushl $5
+       jmp isr_common_stub
+
+/*  6: Invalid Opcode Exception */
+isr6:
+       cli
+       pushl $0
+       pushl $6
+       jmp isr_common_stub
+
+/*  7: Coprocessor Not Available Exception */
+isr7:
+       cli
+       pushl $0
+       pushl $7
+       jmp isr_common_stub
+
+/*  8: Double Fault Exception (With Error Code!) */
+isr8:
+       cli
+       pushl $8
+       jmp isr_common_stub
+
+/*  9: Coprocessor Segment Overrun Exception */
+isr9:
+       cli
+       pushl $0
+       pushl $9
+       jmp isr_common_stub
+
+/* 10: Bad TSS Exception (With Error Code!) */
+isr10:
+       cli
+       pushl $10
+       jmp isr_common_stub
+
+/* 11: Segment Not Present Exception (With Error Code!) */
+isr11:
+       cli
+       pushl $11
+       jmp isr_common_stub
+
+/* 12: Stack Fault Exception (With Error Code!) */
+isr12:
+       cli
+       pushl $12
+       jmp isr_common_stub
+
+/* 13: General Protection Fault Exception (With Error Code!) */
+isr13:
+       cli
+       pushl $13
+       jmp isr_common_stub
+
+/* 14: Page Fault Exception (With Error Code!) */
+isr14:
+       cli
+       pushl $14
+       jmp isr_common_stub
+
+/* 15: Reserved Exception */
+isr15:
+       cli
+       pushl $0
+       pushl $15
+       jmp isr_common_stub
+
+/* 16: Floating Point Exception */
+isr16:
+       cli
+       pushl $0
+       pushl $16
+       jmp isr_common_stub
+
+/* 17: Alignment Check Exception */
+isr17:
+       cli
+       pushl $0
+       pushl $17
+       jmp isr_common_stub
+
+/* 18: Machine Check Exception */
+isr18:
+       cli
+       pushl $0
+       pushl $18
+       jmp isr_common_stub
+
+/* 19: Reserved */
+isr19:
+       cli
+       pushl $0
+       pushl $19
+       jmp isr_common_stub
+
+/* 20: Reserved */
+isr20:
+       cli
+       pushl $0
+       pushl $20
+       jmp isr_common_stub
+
+/* 21: Reserved */
+isr21:
+       cli
+       pushl $0
+       pushl $21
+       jmp isr_common_stub
+
+/* 22: Reserved */
+isr22:
+       cli
+       pushl $0
+       pushl $22
+       jmp isr_common_stub
+
+/* 23: Reserved */
+isr23:
+       cli
+       pushl $0
+       pushl $23
+       jmp isr_common_stub
+
+/* 24: Reserved */
+isr24:
+       cli
+       pushl $0
+       pushl $24
+       jmp isr_common_stub
+
+/* 25: Reserved */
+isr25:
+       cli
+       pushl $0
+       pushl $25
+       jmp isr_common_stub
+
+/* 26: Reserved */
+isr26:
+       cli
+       pushl $0
+       pushl $26
+       jmp isr_common_stub
+
+/* 27: Reserved */
+isr27:
+       cli
+       pushl $0
+       pushl $27
+       jmp isr_common_stub
+
+/* 28: Reserved */
+isr28:
+       cli
+       pushl $0
+       pushl $28
+       jmp isr_common_stub
+
+/* 29: Reserved */
+isr29:
+       cli
+       pushl $0
+       pushl $29
+       jmp isr_common_stub
+
+/* 30: Reserved */
+isr30:
+       cli
+       pushl $0
+       pushl $30
+       jmp isr_common_stub
+
+/* 31: Reserved */
+isr31:
+       cli
+       pushl $0
+       pushl $31
+       jmp isr_common_stub
+
+
+/* This is our common ISR stub. It saves the processor state, sets
+ up for kernel mode segments, calls the C-level fault handler,
+ and finally restores the stack frame. */
+isr_common_stub:
+       pusha
+       pushl %ds
+       pushl %es
+       pushl %fs
+       pushl %gs
+       mov $0x10, %ax
+       mov %ax, %ds
+       mov %ax, %es
+       mov %ax, %fs
+       mov %ax, %gs
+       mov %esp, %eax
+       pushl %eax
+       call fault_handler
+       popl %eax
+       popl %gs
+       popl %fs
+       popl %es
+       popl %ds
+       popa
+       add $8, %esp
+       iret
+
+.data
+       halt_message:
+       .asciz  "Halted.\n"
diff --git a/user/test/x86/kvmtest/gdt.c b/user/test/x86/kvmtest/gdt.c
new file mode 100644
index 0000000..38e5735
--- /dev/null
+++ b/user/test/x86/kvmtest/gdt.c
@@ -0,0 +1,84 @@
+#include <kernel.h>
+#include <lib.h>
+
+/* Defines a GDT entry */
+struct gdt_entry
+{
+       uint16_t limit_low;
+       uint16_t base_low;
+       uint8_t base_middle;
+       uint8_t access;
+       uint8_t granularity;
+       uint8_t base_high;
+} __attribute__((packed));
+
+struct gdt_ptr
+{
+       uint16_t limit;
+       uint32_t base;
+} __attribute__((packed));
+
+/* GDT, with 5 entries:
+ * 0x00 - NULL descriptor
+ * 0x08 - Code segment
+ * 0x10 - Data segment
+ * 0x18 - Primery task
+ * 0x20 - Interrupt task */
+static struct gdt_entry gdt[3 + TSS_COUNT];
+static struct gdt_ptr gp;
+
+static void gdt_flush(const struct gdt_ptr *gp_ptr)
+{
+       asm volatile ("lgdt %0\n\t"
+                     "mov $0x10, %%ax\n\t"
+                     "mov %%ax, %%ds\n\t"
+                     "mov %%ax, %%es\n\t"
+                     "mov %%ax, %%fs\n\t"
+                     "mov %%ax, %%gs\n\t"
+                     "mov %%ax, %%ss\n\t"
+                     "jmp $0x08, $.Lflush2\n\t"
+                     ".Lflush2: "::"m"(*gp_ptr));
+}
+
+void gdt_set_gate(int num, uint32_t base, uint32_t limit, uint8_t access, 
uint8_t gran)
+{
+       /* Setup the descriptor base address */
+       gdt[num].base_low = (base & 0xFFFF);
+       gdt[num].base_middle = (base >> 16) & 0xFF;
+       gdt[num].base_high = (base >> 24) & 0xFF;
+
+       /* Setup the descriptor limits */
+       gdt[num].limit_low = (limit & 0xFFFF);
+       gdt[num].granularity = ((limit >> 16) & 0x0F);
+
+       /* Finally, set up the granularity and access flags */
+       gdt[num].granularity |= (gran & 0xF0);
+       gdt[num].access = access;
+}
+
+void gdt_install(void)
+{
+       /* Setup the GDT pointer and limit */
+       gp.limit = sizeof(gdt) - 1;
+       gp.base = (uint32_t)&gdt;
+
+       memset(gdt, 0, sizeof(gdt));
+
+       /* Our NULL descriptor */
+       gdt_set_gate(0, 0, 0, 0, 0);
+
+       /* The second entry is our Code Segment. The base address
+        *  is 0, the limit is 4GBytes, it uses 4KByte granularity,
+        *  uses 32-bit opcodes, and is a Code Segment descriptor.
+        *  Please check the table above in the tutorial in order
+        *  to see exactly what each value means */
+       gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xcf);
+
+       /* The third entry is our Data Segment. It's EXACTLY the
+        *  same as our code segment, but the descriptor type in
+        *  this entry's access byte says it's a Data Segment */
+       gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xcf);
+
+       /* Flush out the old GDT and install the new changes! */
+       gdt_flush(&gp);
+}
diff --git a/user/test/x86/kvmtest/idt.c b/user/test/x86/kvmtest/idt.c
new file mode 100644
index 0000000..f2d9de7
--- /dev/null
+++ b/user/test/x86/kvmtest/idt.c
@@ -0,0 +1,47 @@
+#include <kernel.h>
+#include <lib.h>
+
+/* Defines an IDT entry */
+struct idt_entry {
+       uint16_t base_lo;
+       uint16_t sel;
+       uint8_t always0;
+       uint8_t flags;
+       uint16_t base_hi;
+} __attribute__((packed));
+
+struct idt_ptr
+{
+       uint16_t limit;
+       uint32_t base;
+} __attribute__((packed));
+
+struct idt_entry idt[256];
+struct idt_ptr idtp;
+
+
+static void idt_load(const struct idt_ptr *idtptr)
+{
+       asm volatile("lidt %0"::"m" (*idtptr));
+}
+
+void idt_set_gate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags)
+{
+       /* The interrupt routine's base address */
+       idt[num].base_lo = (base & 0xFFFF);
+       idt[num].base_hi = (base >> 16) & 0xFFFF;
+
+       idt[num].sel = sel;
+       idt[num].always0 = 0;
+       idt[num].flags = flags;
+}
+
+void idt_install()
+{
+       idtp.limit = sizeof(idt) - 1;
+       idtp.base = (uint32_t)&idt;
+
+       memset(&idt, 0, sizeof(idt));
+
+       idt_load(&idtp);
+}
diff --git a/user/test/x86/kvmtest/isrs.c b/user/test/x86/kvmtest/isrs.c
new file mode 100644
index 0000000..3dcfe59
--- /dev/null
+++ b/user/test/x86/kvmtest/isrs.c
@@ -0,0 +1,112 @@
+#include <kernel.h>
+#include <lib.h>
+
+/* This defines what the stack looks like after an ISR was running */
+struct regs
+{
+       unsigned int gs, fs, es, ds;      /* pushed the segs last */
+       unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax;  /* pushed by 
'pusha' */
+       unsigned int int_no, err_code;    /* our 'push byte #' and ecodes do 
this */
+       unsigned int eip, cs, eflags, useresp, ss;   /* pushed by the processor 
automatically */
+};
+
+extern void isr0();
+extern void isr1();
+extern void isr2();
+extern void isr3();
+extern void isr4();
+extern void isr5();
+extern void isr6();
+extern void isr7();
+extern void isr8();
+extern void isr9();
+extern void isr10();
+extern void isr11();
+extern void isr12();
+extern void isr13();
+extern void isr14();
+extern void isr15();
+extern void isr16();
+extern void isr17();
+extern void isr18();
+extern void isr19();
+extern void isr20();
+extern void isr21();
+extern void isr22();
+extern void isr23();
+extern void isr24();
+extern void isr25();
+extern void isr26();
+extern void isr27();
+extern void isr28();
+extern void isr29();
+extern void isr30();
+extern void isr31();
+
+void (*isrs[32])() = {isr0, isr1, isr2, isr3, isr4, isr5, isr6, isr7, isr8,
+                     isr9, isr10, isr11, isr12, isr13, isr14, isr15, isr16,
+                     isr17, isr18, isr19, isr20, isr21, isr22, isr23, isr24,
+                     isr25, isr26, isr27, isr28, isr29, isr30, isr31};
+
+void isrs_install_one(uint8_t isr)
+{
+       idt_set_gate(isr, (uint32_t)isrs[isr], 0x08, 0x8E);
+}
+
+void isrs_install(void)
+{
+       int i;
+
+       for (i = 0; i < 32; i++)
+               isrs_install_one(i);
+}
+
+char *exception_messages[] =
+{
+       "Division By Zero",
+       "Debug",
+       "Non Maskable Interrupt",
+       "Breakpoint",
+       "Into Detected Overflow",
+       "Out of Bounds",
+       "Invalid Opcode",
+       "No Coprocessor",
+
+       "Double Fault",
+       "Coprocessor Segment Overrun",
+       "Bad TSS",
+       "Segment Not Present",
+       "Stack Fault",
+       "General Protection Fault",
+       "Page Fault",
+       "Unknown Interrupt",
+
+       "Coprocessor Fault",
+       "Alignment Check",
+       "Machine Check",
+       "Reserved",
+       "Reserved",
+       "Reserved",
+       "Reserved",
+       "Reserved",
+
+       "Reserved",
+       "Reserved",
+       "Reserved",
+       "Reserved",
+       "Reserved",
+       "Reserved",
+       "Reserved",
+       "Reserved"
+};
+
+void fault_handler(struct regs *r)
+{
+       if (r->int_no < 32)
+       {
+               printk(0, exception_messages[r->int_no]);
+               printk(0, "Exception. System Halted!\n");
+               for (;;)
+                       asm volatile ("hlt");
+       }
+}
diff --git a/user/test/x86/kvmtest/kernel.c b/user/test/x86/kvmtest/kernel.c
new file mode 100644
index 0000000..1920af7
--- /dev/null
+++ b/user/test/x86/kvmtest/kernel.c
@@ -0,0 +1,194 @@
+/* kernel.c - the C part of the kernel */
+/* Copyright (C) 1999  Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <kernel.h>
+#include <multiboot.h>
+#include <lib.h>
+#include <memory.h>
+
+/* Macros. */
+
+/* Check if the bit BIT in FLAGS is set. */
+#define CHECK_FLAG(flags,bit)   ((flags) & (1 << (bit)))
+
+/* Forward declarations. */
+void cmain (unsigned long magic, unsigned long addr);
+
+#if 0
+/* Check if MAGIC is valid and print the Multiboot information structure
+   pointed by ADDR. */
+static void print_boot_info(unsigned long magic, unsigned long addr)
+{
+       multiboot_info_t *mbi;
+
+       /* Am I booted by a Multiboot-compliant boot loader? */
+       if (magic != MULTIBOOT_BOOTLOADER_MAGIC)
+       {
+               printk ("Invalid magic number: 0x%x\n", (unsigned) magic);
+               return;
+       }
+
+       /* Set MBI to the address of the Multiboot information structure. */
+       mbi = (multiboot_info_t *) addr;
+
+       /* Print out the flags. */
+       printk ("flags = 0x%x\n", (unsigned) mbi->flags);
+
+       /* Are mem_* valid? */
+       if (CHECK_FLAG (mbi->flags, 0))
+               printk ("mem_lower = %uKB, mem_upper = %uKB\n",
+                               (unsigned) mbi->mem_lower, (unsigned) 
mbi->mem_upper);
+
+       /* Is boot_device valid? */
+       if (CHECK_FLAG (mbi->flags, 1))
+               printk ("boot_device = 0x%x\n", (unsigned) mbi->boot_device);
+
+       /* Is the command line passed? */
+       if (CHECK_FLAG (mbi->flags, 2))
+               printk ("cmdline = %s\n", (char *) mbi->cmdline);
+
+       /* Are mods_* valid? */
+       if (CHECK_FLAG (mbi->flags, 3))
+       {
+               module_t *mod;
+               int i;
+
+               printk ("mods_count = %d, mods_addr = 0x%x\n",
+                               (int) mbi->mods_count, (int) mbi->mods_addr);
+               for (i = 0, mod = (module_t *) mbi->mods_addr;
+                               i < mbi->mods_count;
+                               i++, mod++)
+                       printk (" mod_start = 0x%x, mod_end = 0x%x, string = 
%s\n",
+                                       (unsigned) mod->mod_start,
+                                       (unsigned) mod->mod_end,
+                                       (char *) mod->string);
+       }
+
+       /* Bits 4 and 5 are mutually exclusive! */
+       if (CHECK_FLAG (mbi->flags, 4) && CHECK_FLAG (mbi->flags, 5))
+       {
+               printk ("Both bits 4 and 5 are set.\n");
+               return;
+       }
+
+       /* Is the symbol table of a.out valid? */
+       if (CHECK_FLAG (mbi->flags, 4))
+       {
+               aout_symbol_table_t *aout_sym = &(mbi->u.aout_sym);
+
+               printk ("aout_symbol_table: tabsize = 0x%0x, "
+                               "strsize = 0x%x, addr = 0x%x\n",
+                               (unsigned) aout_sym->tabsize,
+                               (unsigned) aout_sym->strsize,
+                               (unsigned) aout_sym->addr);
+       }
+
+       /* Is the section header table of ELF valid? */
+       if (CHECK_FLAG (mbi->flags, 5))
+       {
+               elf_section_header_table_t *elf_sec = &(mbi->u.elf_sec);
+
+               printk ("elf_sec: num = %u, size = 0x%x,"
+                               " addr = 0x%x, shndx = 0x%x\n",
+                               (unsigned) elf_sec->num, (unsigned) 
elf_sec->size,
+                               (unsigned) elf_sec->addr, (unsigned) 
elf_sec->shndx);
+       }
+
+       /* Are mmap_* valid? */
+       if (CHECK_FLAG (mbi->flags, 6))
+       {
+               memory_map_t *mmap;
+
+               printk ("mmap_addr = 0x%x, mmap_length = 0x%x\n",
+                               (unsigned) mbi->mmap_addr, (unsigned) 
mbi->mmap_length);
+               for (mmap = (memory_map_t *) mbi->mmap_addr;
+                               (unsigned long) mmap < mbi->mmap_addr + 
mbi->mmap_length;
+                               mmap = (memory_map_t *) ((unsigned long) mmap
+                                       + mmap->size + sizeof (mmap->size)))
+                       printk (" size = 0x%x, base_addr = 0x%x%x,"
+                                       " length = 0x%x%x, type = 0x%x\n",
+                                       (unsigned) mmap->size,
+                                       (unsigned) mmap->base_addr_high,
+                                       (unsigned) mmap->base_addr_low,
+                                       (unsigned) mmap->length_high,
+                                       (unsigned) mmap->length_low,
+                                       (unsigned) mmap->type);
+       }
+}
+#endif
+
+uint16_t verbosity;
+
+static void cmd_parse(multiboot_info_t *mbi)
+{
+       char *v;
+
+       if (!CHECK_FLAG (mbi->flags, 2))
+               return;
+
+       v = strstr((char*)mbi->cmdline, "v=");
+
+       if (!v)
+               return;
+
+       verbosity = atoi(v + 2);
+       printk(3, "cmdline = %s\n", (char *) mbi->cmdline);
+}
+
+extern struct test_desc __tests_start[], __tests_end[];
+
+static void run_tests(void)
+{
+       struct test_desc *test;
+
+       for (test = __tests_start; test < __tests_end; test++) {
+               int r;
+               printk(0, "Start test: %s\n", test->name);
+               r = test->fn();
+               if (r < 0) {
+                       printk(0, "Critical failure. Exiting.\n");
+                       return;
+               } else if (r == TEST_FAIL)
+                       printk(0, "Test fails\n");
+               else
+                       printk(0, "Test Succeeds\n");
+       }
+}
+
+void cmain(unsigned long magic, unsigned long addr)
+{
+       cmd_parse((multiboot_info_t*)addr);
+
+       gdt_install();
+       tss_install();
+       uart_init();
+
+       kalloc_init(_kernel_end, KALLOC_SIZE);
+
+       /* Clear the screen. */
+       cls ();
+
+       printk(3, "kernel start=0x%x end=0x%x\n", _kernel_start, _kernel_end);
+       printk(3, "kalloc_size=%d\n", KALLOC_SIZE);
+
+       idt_install();
+       isrs_install();
+
+       run_tests();
+/*     print_boot_info(magic, addr); */
+}
+
diff --git a/user/test/x86/kvmtest/kernel.h b/user/test/x86/kvmtest/kernel.h
new file mode 100644
index 0000000..a2df4a2
--- /dev/null
+++ b/user/test/x86/kvmtest/kernel.h
@@ -0,0 +1,68 @@
+#ifndef _KERNEL_H
+#define _KERNEL_H
+#ifndef ASM
+#include <stdint.h>
+
+
+typedef uint32_t size_t;
+#define NULL ((void*)0)
+
+/* 1M for dynamic memory management */
+#define KALLOC_SIZE (1024*1024 - (_kernel_end - _kernel_start))
+#define TSS_COUNT 4
+#define TSS_GDT_OFFSET 3
+
+extern char _kernel_start[], _kernel_end[];
+
+static inline void outb(int addr, int val)
+{
+       asm volatile ("outb %b1, %w0" : : "d" (addr), "a" (val));
+}
+
+static inline uint8_t inb(int addr)
+{
+       uint8_t val;
+       asm volatile ("inb %w1, %b0" : "=a" (val) : "d" (addr));
+       return val;
+}
+
+void gdt_install(void);
+void gdt_set_gate(int num, uint32_t base, uint32_t limit, uint8_t access,
+                 uint8_t gran);
+void idt_install(void);
+void idt_set_gate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags);
+
+void isrs_install(void);
+void isrs_install_one(uint8_t isr);
+
+void tss_install(void);
+void tss_setup(uint8_t gate, uint8_t desc, void (*fn)(void));
+void tss_info(void);
+
+void uart_init(void);
+void serial_outch(char c);
+char serial_inch(void);
+
+#define TEST_FAIL 0
+#define TEST_SUCCEED 1
+#define TEST_FAIL_EXIT -1
+typedef int (*testfn_t)(void);
+
+struct test_desc {
+       char *name;
+       testfn_t fn;
+};
+
+#define define_test(_fn, _name)                                                
\
+        static struct test_desc __test_##fn __attribute__((__used__))  \
+        __attribute__((__section__(".tests"))) = {.name = _name, .fn = _fn}
+
+extern uint16_t verbosity;
+
+#endif /* ASM */
+
+/* put stack somewhere in low memory */
+#define STACK_START   0x80000
+#define INT_STACK_START   0x70000
+
+#endif
diff --git a/user/test/x86/kvmtest/kernel.ld b/user/test/x86/kvmtest/kernel.ld
new file mode 100644
index 0000000..4be48e3
--- /dev/null
+++ b/user/test/x86/kvmtest/kernel.ld
@@ -0,0 +1,28 @@
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")

+OUTPUT_ARCH(i386)

+ENTRY(start)

+SECTIONS

+{

+  . = 0x100000;

+  _kernel_start = .;

+  .text : {

+    *(.text)

+  }

+  .rodata : {

+    *(.rodata)

+  }

+  .data  : {

+    *(.data)

+  }

+  .bss  : {

+    *(.bss)

+  }

+  __tests_start = .;

+  .tests : {

+    *(.tests)

+  }

+  __tests_end = .;

+  . = ALIGN(4096);

+  _kernel_end = .;

+  /DISCARD/ : { *(.comment) }

+}
\ No newline at end of file
diff --git a/user/test/x86/kvmtest/lib.c b/user/test/x86/kvmtest/lib.c
new file mode 100644
index 0000000..e9a86ca
--- /dev/null
+++ b/user/test/x86/kvmtest/lib.c
@@ -0,0 +1,296 @@
+#include <kernel.h>
+#include <lib.h>
+
+/* Some screen stuff. */
+/* The number of columns. */
+#define COLUMNS                 80
+/* The number of lines. */
+#define LINES                   24
+/* The attribute of an character. */
+#define ATTRIBUTE               7
+/* The video memory address. */
+#define VIDEO                   0xB8000
+
+/* Variables. */
+/* Save the X position. */
+static int xpos;
+/* Save the Y position. */
+static int ypos;
+/* Point to the video memory. */
+static volatile unsigned char *video;
+
+/* Clear the screen and initialize VIDEO, XPOS and YPOS. */
+void cls (void)
+{
+       int i;
+
+       video = (unsigned char *) VIDEO;
+
+       for (i = 0; i < COLUMNS * LINES * 2; i++)
+               *(video + i) = 0;
+
+       xpos = 0;
+       ypos = 0;
+}
+
+/* Convert the integer D to a string and save the string in BUF. If
+   BASE is equal to 'd', interpret that D is decimal, and if BASE is
+   equal to 'x', interpret that D is hexadecimal. */
+void itoa (char *buf, int base, int d)
+{
+       char *p = buf;
+       char *p1, *p2;
+       unsigned long ud = d;
+       int divisor = 10;
+
+       /* If %d is specified and D is minus, put `-' in the head. */
+       if (base == 'd' && d < 0)
+       {
+               *p++ = '-';
+               buf++;
+               ud = -d;
+       }
+       else if (base == 'x')
+               divisor = 16;
+
+       /* Divide UD by DIVISOR until UD == 0. */
+       do
+       {
+               int remainder = ud % divisor;
+
+               *p++ = (remainder < 10) ? remainder + '0' : remainder + 'a' - 
10;
+       }
+       while (ud /= divisor);
+
+       /* Terminate BUF. */
+       *p = 0;
+
+       /* Reverse BUF. */
+       p1 = buf;
+       p2 = p - 1;
+       while (p1 < p2)
+       {
+               char tmp = *p1;
+               *p1 = *p2;
+               *p2 = tmp;
+               p1++;
+               p2--;
+       }
+}
+
+int isdigit(int c)
+{
+       return c >= '0' && c <='9';
+}
+
+int isupper(int c)
+{
+       return c >= 'A' && c <= 'Z';
+}
+
+int islower(int c)
+{
+       return c >= 'a' && c <= 'z';
+}
+
+int atoi_base(const char *buf, int base)
+{
+       int minus,val,digit,base_1;
+       char c;
+
+       base_1 = base - 1;
+
+       if((minus = *buf == '-'))
+               buf++;
+
+       val = 0;
+       while ((c = *buf++)) {
+               if (isdigit(c))
+                       digit = c - 48;
+               else if (isupper(c))
+                       digit = c - 'A' + 10;
+               else if (islower(c))
+                       digit = c - 'a' + 10;
+               else
+                       break;
+
+               if (digit < 0 || digit > base_1)
+                       break;
+
+               val = base*val + digit;
+       }
+
+       return minus ? -val : val;
+}
+
+/* Put the character C on the screen. */
+static void kputchar (int c)
+{
+#ifdef QEMU
+       outb(0x504, c);
+#endif
+       serial_outch(c);
+
+       if (c == '\n' || c == '\r')
+       {
+newline:
+               xpos = 0;
+               ypos++;
+               if (ypos >= LINES)
+                       ypos = 0;
+               return;
+       }
+
+       *(video + (xpos + ypos * COLUMNS) * 2) = c & 0xFF;
+       *(video + (xpos + ypos * COLUMNS) * 2 + 1) = ATTRIBUTE;
+
+       xpos++;
+       if (xpos >= COLUMNS)
+               goto newline;
+}
+
+/* Format a string and print it on the screen, just like the libc
+   function printf. */
+void printk (uint16_t level, const char *format, ...)
+{
+       char **arg = (char **) &format;
+       int c;
+       char buf[20];
+
+       if (level > verbosity)
+               return;
+
+       arg++;
+
+       while ((c = *format++) != 0)
+       {
+               if (c != '%')
+                       kputchar (c);
+               else
+               {
+                       char *p;
+
+                       c = *format++;
+                       switch (c)
+                       {
+                               case 'd':
+                               case 'u':
+                               case 'x':
+                                       itoa (buf, c, *((int *) arg++));
+                                       p = buf;
+                                       goto string;
+                                       break;
+
+                               case 's':
+                                       p = *arg++;
+                                       if (! p)
+                                               p = "(null)";
+
+string:
+                                       while (*p)
+                                               kputchar (*p++);
+                                       break;
+
+                               default:
+                                       kputchar (*((int *) arg++));
+                                       break;
+                       }
+               }
+       }
+}
+
+void *memset(void *s, int c, size_t n)
+{
+       char *ss = s;
+       int i;
+
+       for (i = 0; i < n; i++)
+               ss[i] = c;
+
+       return s;
+}
+
+char *strstr(const char *phaystack, const char *pneedle)
+{
+       const unsigned char *haystack, *needle;
+       char b, c;
+
+       haystack = (const unsigned char *) phaystack;
+       needle = (const unsigned char *) pneedle;
+
+       b = *needle;
+       if (b != '\0')
+       {
+               haystack--;   /* possible ANSI violation */
+               do
+               {
+                       c = *++haystack;
+                       if (c == '\0')
+                               goto ret0;
+               }
+               while (c != b);
+
+               c = *++needle;
+               if (c == '\0')
+                       goto foundneedle;
+               ++needle;
+               goto jin;
+
+               for (;;)
+               {
+                       char a;
+                       const unsigned char *rhaystack, *rneedle;
+
+                       do
+                       {
+                               a = *++haystack;
+                               if (a == '\0')
+                                       goto ret0;
+                               if (a == b)
+                                       break;
+                               a = *++haystack;
+                               if (a == '\0')
+                                       goto ret0;
+                       shloop:;
+                       }
+                       while (a != b);
+
+               jin:
+                       a = *++haystack;
+                       if (a == '\0')
+                               goto ret0;
+
+                       if (a != c)
+                               goto shloop;
+
+                       rhaystack = haystack-- + 1;
+                       rneedle = needle;
+                       a = *rneedle;
+
+                       if (*rhaystack == a)
+                               do
+                               {
+                                       if (a == '\0')
+                                               goto foundneedle;
+                                       ++rhaystack;
+                                       a = *++needle;
+                                       if (*rhaystack != a)
+                                               break;
+                                       if (a == '\0')
+                                               goto foundneedle;
+                                       ++rhaystack;
+                                       a = *++needle;
+                               }
+                               while (*rhaystack == a);
+
+                       needle = rneedle; /* took the register-poor approach */
+
+                       if (a == '\0')
+                               break;
+               }
+       }
+foundneedle:
+       return (char*) haystack;
+ret0:
+       return 0;
+}
diff --git a/user/test/x86/kvmtest/lib.h b/user/test/x86/kvmtest/lib.h
new file mode 100644
index 0000000..b00849c
--- /dev/null
+++ b/user/test/x86/kvmtest/lib.h
@@ -0,0 +1,13 @@
+#ifndef _LIB_H
+#define _LIB_H
+void cls(void);
+void itoa(char *buf, int base, int d);
+void printk(uint16_t level, const char *format, ...);
+void *memset(void *s, int c, size_t n);
+char *strstr(const char *phaystack, const char *pneedle);
+int atoi_base(const char *buf, int base);
+static inline int atoi(const char *buf)
+{
+       return atoi_base(buf, 10);
+}
+#endif
diff --git a/user/test/x86/kvmtest/memory.c b/user/test/x86/kvmtest/memory.c
new file mode 100644
index 0000000..1f0e7f2
--- /dev/null
+++ b/user/test/x86/kvmtest/memory.c
@@ -0,0 +1,100 @@
+#include <kernel.h>
+#include <memory.h>
+
+#define ALIGNMASK 1U
+#define ALIGN(s) (((s) + ALIGNMASK) & ~ALIGNMASK)
+#define POFF ALIGN(sizeof(size_t))
+#define MINSIZ ALIGN(sizeof(struct cell *))
+#define C2P(c) ((char *)(c) + POFF)
+#define P2C(p) ((struct cell *)((char *)(p) - POFF))
+#define ISADJ(c1,c2) ((struct cell *)(C2P(c1) + (c1)->size) == (struct cell 
*)(c2))
+
+struct cell {
+       size_t size;
+       struct cell *next;
+};
+
+static struct mem_pool {
+       struct cell *tail;
+} *kmem;
+
+void kalloc_init(void *mem, size_t size)
+{
+       kmem->tail = mem;
+       kmem->tail->size = size - POFF;
+       kmem->tail->next = kmem->tail;
+}
+
+void *kalloc(size_t size)
+{
+       struct cell *c1, *c2, *c3;
+
+       size = size < MINSIZ ? MINSIZ : ALIGN(size);
+
+       c1 = kmem->tail;
+       while (c1->next->size < size) {
+               if (c1->next == kmem->tail)
+                       return NULL;
+               c1 = c1->next;
+       }
+       c2 = c1->next;
+       if (c2->size > (POFF + size)) { /* split new cell */
+               c3 = (struct cell *)(C2P(c2) + size);
+               c3->size = c2->size - (size + POFF);
+               c3->next = c2->next;
+               c2->size = size;
+               c1->next = c3;
+       } else { /* use the entire cell */
+               c1->next = c2->next;
+               if (c2 == kmem->tail) {
+                       kmem->tail = c1;
+               }
+       }
+
+       return C2P(c2);
+}
+
+void kfree(void *ptr)
+{
+       struct cell *c1, *c2, *c3;
+       int j1, j2;
+
+/* splice the cell back into the list */
+       c1 = kmem->tail;
+       c2 = P2C(ptr);
+
+       if (c2 > c1) { /* append to end of list */
+               if (ISADJ(c1,c2)) { /* join with last cell */
+                       c1->size += POFF + c2->size;
+                       return;
+               }
+               c2->next = c1->next;
+               c1->next = c2;
+               kmem->tail = c2;
+               return;
+       }
+
+       while (c1->next < c2) { /* find insertion point */
+               c1 = c1->next;
+       }
+       c3 = c1->next;
+
+       j1 = ISADJ(c1,c2); /* c1 and c2 need to be joined */
+       j2 = ISADJ(c2,c3); /* c2 and c3 need to be joined */
+
+       if (j1) {
+               if (j2) { /* splice all three cells together */
+                       c1->next = c3->next;
+                       c1->size += POFF + c3->size;
+               }
+               c1->size += POFF + c2->size;
+       } else {
+               c1->next = c2;
+               if (j2) {
+                       c2->next = c3->next;
+                       c2->size += POFF + c3->size;
+               } else {
+                       c2->next = c3;
+               }
+       }
+}
diff --git a/user/test/x86/kvmtest/memory.h b/user/test/x86/kvmtest/memory.h
new file mode 100644
index 0000000..9a0c984
--- /dev/null
+++ b/user/test/x86/kvmtest/memory.h
@@ -0,0 +1,6 @@
+#ifndef _MEMORY_H
+#define _MEMORY_H
+void kalloc_init(void *mem, size_t size);
+void *kalloc(size_t size);
+void kfree(void *ptr);
+#endif
diff --git a/user/test/x86/kvmtest/multiboot.h 
b/user/test/x86/kvmtest/multiboot.h
new file mode 100644
index 0000000..85a4605
--- /dev/null
+++ b/user/test/x86/kvmtest/multiboot.h
@@ -0,0 +1,109 @@
+/* multiboot.h - the header for Multiboot */
+/* Copyright (C) 1999, 2001  Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Macros. */
+
+/* The magic number for the Multiboot header. */
+#define MULTIBOOT_HEADER_MAGIC          0x1BADB002
+
+/* The flags for the Multiboot header. */
+#ifdef __ELF__
+# define MULTIBOOT_HEADER_FLAGS         0x00000003
+#else
+# define MULTIBOOT_HEADER_FLAGS         0x00010003
+#endif
+
+/* The magic number passed by a Multiboot-compliant boot loader. */
+#define MULTIBOOT_BOOTLOADER_MAGIC      0x2BADB002
+
+#ifndef ASM
+/* Do not include here in boot.S. */
+
+/* Types. */
+
+/* The Multiboot header. */
+typedef struct multiboot_header
+{
+       unsigned long magic;
+       unsigned long flags;
+       unsigned long checksum;
+       unsigned long header_addr;
+       unsigned long load_addr;
+       unsigned long load_end_addr;
+       unsigned long bss_end_addr;
+       unsigned long entry_addr;
+} multiboot_header_t;
+
+/* The symbol table for a.out. */
+typedef struct aout_symbol_table
+{
+       unsigned long tabsize;
+       unsigned long strsize;
+       unsigned long addr;
+       unsigned long reserved;
+} aout_symbol_table_t;
+
+/* The section header table for ELF. */
+typedef struct elf_section_header_table
+{
+       unsigned long num;
+       unsigned long size;
+       unsigned long addr;
+       unsigned long shndx;
+} elf_section_header_table_t;
+
+/* The Multiboot information. */
+typedef struct multiboot_info
+{
+       unsigned long flags;
+       unsigned long mem_lower;
+       unsigned long mem_upper;
+       unsigned long boot_device;
+       unsigned long cmdline;
+       unsigned long mods_count;
+       unsigned long mods_addr;
+       union
+       {
+               aout_symbol_table_t aout_sym;
+               elf_section_header_table_t elf_sec;
+       } u;
+       unsigned long mmap_length;
+       unsigned long mmap_addr;
+} multiboot_info_t;
+
+/* The module structure. */
+typedef struct module
+{
+       unsigned long mod_start;
+       unsigned long mod_end;
+       unsigned long string;
+       unsigned long reserved;
+} module_t;
+
+/* The memory map. Be careful that the offset 0 is base_addr_low
+   but no size. */
+typedef struct memory_map
+{
+       unsigned long size;
+       unsigned long base_addr_low;
+       unsigned long base_addr_high;
+       unsigned long length_low;
+       unsigned long length_high;
+       unsigned long type;
+} memory_map_t;
+
+#endif /* ! ASM */
diff --git a/user/test/x86/kvmtest/tests/Makefile 
b/user/test/x86/kvmtest/tests/Makefile
new file mode 100644
index 0000000..751d352
--- /dev/null
+++ b/user/test/x86/kvmtest/tests/Makefile
@@ -0,0 +1,22 @@
+CC=gcc
+AS=gcc
+CFLAGS=-m32 -I. -I.. -O2 -Wall
+ASFLAGS=-m32 -I. -I..
+OBJS=tss_test.o
+
+PHONY := all
+all: tests.o
+
+tests.o: $(OBJS)
+       ld -m elf_i386 -r $(OBJS) -o $@
+
+-include $(OBJS:.o=.d)
+
+# compile and generate dependency info
+%.o: %.c
+       gcc -c $(CFLAGS) $*.c -o $*.o
+       gcc -MM $(CFLAGS) $*.c > $*.d
+
+PHONY += clean
+clean:
+       -rm *.o *~ *.d
diff --git a/user/test/x86/kvmtest/tests/tss_test.c 
b/user/test/x86/kvmtest/tests/tss_test.c
new file mode 100644
index 0000000..835dc0b
--- /dev/null
+++ b/user/test/x86/kvmtest/tests/tss_test.c
@@ -0,0 +1,74 @@
+#include <kernel.h>
+#include <lib.h>
+
+
+static void nmi_tss(void)
+{
+start:
+       printk(0, "NMI task is running\n");
+       tss_info();
+       asm volatile ("iret");
+       printk(0, "NMI task restart after iret.\n");
+       goto start;
+}
+
+static int test_divider;
+
+static void de_tss(void)
+{
+start:
+       printk(0, "DE task is running\n");
+       tss_info();
+       test_divider = 10;
+       asm volatile ("iret");
+       goto start;
+}
+
+static void of_tss(void)
+{
+start:
+       printk(0, "OF task is running\n");
+       tss_info();
+       asm volatile ("iret");
+       goto start;
+}
+
+static int tss_test(void)
+{
+       int ret = TEST_SUCCEED, res;
+
+       tss_setup(2, 1, nmi_tss);
+       tss_setup(0, 2, de_tss);
+       tss_setup(4, 3, of_tss);
+
+       printk(0, "Triggering nmi\n");
+       asm volatile ("int $2");
+       printk(0, "Return from nmi 1\n");
+       asm volatile ("int $2");
+       printk(0, "Return from nmi 2\n");
+       printk(0, "Try to devide by 0\n");
+       res = 1500 / test_divider;
+       printk(0, "Result is %d\n", res);
+       if (res != 150) {
+               ret = TEST_FAIL;
+               goto restore_isrs;
+       }
+       printk(0, "Call int 0\n");
+       asm volatile ("int $0");
+       printk(0, "Return from int 0\n");
+       printk(0, "Call into\n");
+       asm volatile ("addb $127, %b0\ninto"::"a"(127));
+       printk(0, "Return from into\n");
+       printk(0, "Calling nmi task by lcall\n");
+       asm volatile("lcall $0x20, $0");
+       printk(0, "Return from call\n");
+
+restore_isrs:
+       isrs_install_one(0);
+       isrs_install_one(2);
+       isrs_install_one(4);
+
+       return ret;
+}
+
+define_test(tss_test, "TSS test");
diff --git a/user/test/x86/kvmtest/tss.c b/user/test/x86/kvmtest/tss.c
new file mode 100644
index 0000000..1d73531
--- /dev/null
+++ b/user/test/x86/kvmtest/tss.c
@@ -0,0 +1,108 @@
+#include <kernel.h>
+#include <lib.h>
+
+struct tss_desc {
+       uint16_t   link;
+       uint16_t   link_h;
+
+       uint32_t   esp0;
+       uint16_t   ss0;
+       uint16_t   ss0_h;
+       
+       uint32_t   esp1;
+       uint16_t   ss1;
+       uint16_t   ss1_h;
+       
+       uint32_t   esp2;
+       uint16_t   ss2;
+       uint16_t   ss2_h;
+       
+       uint32_t   cr3;
+       uint32_t   eip;
+       uint32_t   eflags;
+       
+       uint32_t   eax;
+       uint32_t   ecx;
+       uint32_t   edx;
+       uint32_t   ebx;
+       
+       uint32_t   esp;
+       uint32_t   ebp;
+       
+       uint32_t   esi;
+       uint32_t   edi;
+       
+       uint16_t   es;
+       uint16_t   es_h;
+       
+       uint16_t   cs;
+       uint16_t   cs_h;
+       
+       uint16_t   ss;
+       uint16_t   ss_h;
+       
+       uint16_t   ds;
+       uint16_t   ds_h;
+       
+       uint16_t   fs;
+       uint16_t   fs_h;
+       
+       uint16_t   gs;
+       uint16_t   gs_h;
+       
+       uint16_t   ldt;
+       uint16_t   ldt_h;
+       
+       uint16_t   trap;
+       uint16_t   iomap;
+} __attribute__ ((packed));
+
+static struct tss_desc tss[TSS_COUNT];
+
+void tss_install(void)
+{
+       uint16_t desc_size = sizeof(struct tss_desc);
+       int i;
+
+       for (i = 0; i < TSS_COUNT; i++) {
+               tss[i].ss0 = tss[i].ss1 = tss[i].ss2 = 0x10;
+               tss[i].esp0 = tss[i].esp1 = tss[i].esp2 = INT_STACK_START;
+               tss[i].cs = 0x08;
+               tss[i].ds = tss[i].es = tss[i].fs = tss[i].gs = tss[i].ss =0x10;
+               tss[i].esp = INT_STACK_START;
+               tss[i].iomap = (uint16_t)desc_size;
+               gdt_set_gate(TSS_GDT_OFFSET + i, (uint32_t)&tss[i],
+                            desc_size - 1, 0x89, 0x0f);
+       }
+
+       tss[0].esp0 = tss[0].esp1 = tss[0].esp2 = tss[0].esp = STACK_START;
+
+       asm volatile ( "ltr %%ax" : : "a" ( 0x18 ) );
+}
+
+void tss_setup(uint8_t gate, uint8_t i, void (*fn)(void))
+{
+       if (i >= TSS_COUNT) {
+               printk(0, "Try to setup TSS out if bound %d\n", tss);
+               return;
+       }
+       tss[i].eip = (uint32_t)fn;
+       printk(2, "TSS set gate %d to TSS %x\n", gate,
+              (i + TSS_GDT_OFFSET) << 3);
+       idt_set_gate(gate, 0, (i + TSS_GDT_OFFSET) << 3, 0x85);
+}
+
+void tss_info(void)
+{
+       uint16_t tr, i;
+
+       asm volatile ("str %0":"=r"(tr));
+
+       i = (tr >> 3) - TSS_GDT_OFFSET;
+
+       if (i >= TSS_COUNT)
+               printk(0, "Current TR %x is wrong!\n", tr);
+
+       printk(0, "TR=%x Main TSS back link %x. Current TSS back link %x\n",
+              tr, tss[0]. link, tss[i].link);
+}
diff --git a/user/test/x86/kvmtest/uart.c b/user/test/x86/kvmtest/uart.c
new file mode 100644
index 0000000..d9661d1
--- /dev/null
+++ b/user/test/x86/kvmtest/uart.c
@@ -0,0 +1,43 @@
+#include <kernel.h>
+
+#define PORT1 0x3F8
+#define PORT2 0x2F8
+#define PORT3 0x3E8
+#define PORT4 0x2E8
+
+#define BAUD38400  0x03
+#define BAUD115200 0x01
+#define BAUD57600  0x02
+#define BAUD19200  0x06
+#define BAUD9600   0x0C
+#define BAUD4800   0x18
+#define BAUD2400   0x30
+
+void uart_init(void)
+{
+       outb(PORT1 + 1 , 0);   /* Turn off interrupts */
+
+       outb(PORT1 + 3 , 0x80);  /* SET DLAB ON */
+       /* Set Baud rate - Divisor Latch Low Byte */
+       outb(PORT1 + 0 , BAUD38400);
+       /* Set Baud rate - Divisor Latch High Byte */
+       outb(PORT1 + 1 , 0x00);
+       outb(PORT1 + 3 , 0x03);  /* 8 Bits, No Parity, 1 Stop Bit */
+       outb(PORT1 + 2 , 0xC7);  /* FIFO Control Register */
+       outb(PORT1 + 4 , 0x0B);  /* Turn on DTR, RTS, and OUT2 */
+}
+
+void serial_outch(char c)
+{
+       outb(PORT1, c);
+}
+
+char serial_inch(void)
+{
+       char c;
+       do {
+               c = inb(PORT1 + 5);
+               if (c & 1)
+                       return inb(PORT1);
+       } while(1);
+}
--
                        Gleb.
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to