From patchwork Wed Apr 14 14:12:46 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kiszka X-Patchwork-Id: 92411 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o3EED4FH019796 for ; Wed, 14 Apr 2010 14:13:04 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755476Ab0DNONB (ORCPT ); Wed, 14 Apr 2010 10:13:01 -0400 Received: from goliath.siemens.de ([192.35.17.28]:21761 "EHLO goliath.siemens.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753134Ab0DNONA (ORCPT ); Wed, 14 Apr 2010 10:13:00 -0400 Received: from mail1.siemens.de (localhost [127.0.0.1]) by goliath.siemens.de (8.12.11.20060308/8.12.11) with ESMTP id o3EECkRF015667; Wed, 14 Apr 2010 16:12:47 +0200 Received: from [139.25.109.167] (mchn012c.mchp.siemens.de [139.25.109.167] (may be forged)) by mail1.siemens.de (8.12.11.20060308/8.12.11) with ESMTP id o3EECkcO014348; Wed, 14 Apr 2010 16:12:46 +0200 Message-ID: <4BC5CD5E.6000608@siemens.com> Date: Wed, 14 Apr 2010 16:12:46 +0200 From: Jan Kiszka User-Agent: Mozilla/5.0 (X11; U; Linux i686 (x86_64); de; rv:1.8.1.12) Gecko/20080226 SUSE/2.0.0.12-1.1 Thunderbird/2.0.0.12 Mnenhy/0.7.5.666 MIME-Version: 1.0 To: Avi Kivity , Marcelo Tosatti CC: kvm , Gleb Natapov Subject: [PATCH] kvm test: Add 32-bit task switch micro-test Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Wed, 14 Apr 2010 14:13:04 +0000 (UTC) diff --git a/kvm/user/config-i386.mak b/kvm/user/config-i386.mak index 09175d5..a9becfc 100644 --- a/kvm/user/config-i386.mak +++ b/kvm/user/config-i386.mak @@ -5,6 +5,8 @@ ldarch = elf32-i386 CFLAGS += -D__i386__ CFLAGS += -I $(KERNELDIR)/include -tests= +tests = $(TEST_DIR)/taskswitch.flat include config-x86-common.mak + +$(TEST_DIR)/taskswitch.flat: $(cstart.o) $(TEST_DIR)/taskswitch.o diff --git a/kvm/user/test/x86/taskswitch.c b/kvm/user/test/x86/taskswitch.c new file mode 100644 index 0000000..8ed8a93 --- /dev/null +++ b/kvm/user/test/x86/taskswitch.c @@ -0,0 +1,164 @@ +/* + * Copyright 2010 Siemens AG + * Author: Jan Kiszka + * + * Released under GPLv2. + */ + +#include "libcflat.h" + +#define FIRST_SPARE_SEL 0x18 + +struct exception_frame { + unsigned long error_code; + unsigned long ip; + unsigned long cs; + unsigned long flags; +}; + +struct tss32 { + unsigned short prev; + unsigned short res1; + unsigned long esp0; + unsigned short ss0; + unsigned short res2; + unsigned long esp1; + unsigned short ss1; + unsigned short res3; + unsigned long esp2; + unsigned short ss2; + unsigned short res4; + unsigned long cr3; + unsigned long eip; + unsigned long eflags; + unsigned long eax, ecx, edx, ebx, esp, ebp, esi, edi; + unsigned short es; + unsigned short res5; + unsigned short cs; + unsigned short res6; + unsigned short ss; + unsigned short res7; + unsigned short ds; + unsigned short res8; + unsigned short fs; + unsigned short res9; + unsigned short gs; + unsigned short res10; + unsigned short ldt; + unsigned short res11; + unsigned short t:1; + unsigned short res12:15; + unsigned short iomap_base; +}; + +static char main_stack[4096]; +static char fault_stack[4096]; +static struct tss32 main_tss; +static struct tss32 fault_tss; + +static unsigned long long gdt[] __attribute__((aligned(16))) = { + 0, + 0x00cf9b000000ffffull, + 0x00cf93000000ffffull, + 0, 0, /* TSS segments */ + 0, /* task return gate */ +}; + +static unsigned long long gdtr; + +void fault_entry(void); + +static __attribute__((used, regparm(1))) void +fault_handler(unsigned long error_code) +{ + unsigned short *desc; + + printf("fault at %x:%x, prev task %x, error code %x\n", + main_tss.cs, main_tss.eip, fault_tss.prev, error_code); + + main_tss.eip += 2; + + desc = (unsigned short *)&gdt[3]; + desc[2] &= ~0x0200; + + desc = (unsigned short *)&gdt[5]; + desc[0] = 0; + desc[1] = fault_tss.prev; + desc[2] = 0x8500; + desc[3] = 0; +} + +asm ( + "fault_entry:\n" + " mov (%esp),%eax\n" + " call fault_handler\n" + " jmp $0x28, $0\n" +); + +static void setup_tss(struct tss32 *tss, void *entry, + void *stack_base, unsigned long stack_size) +{ + unsigned long cr3; + unsigned short cs, ds; + + asm ("mov %%cr3,%0" : "=r" (cr3)); + asm ("mov %%cs,%0" : "=r" (cs)); + asm ("mov %%ds,%0" : "=r" (ds)); + + tss->ss0 = tss->ss1 = tss->ss2 = tss->ss = ds; + tss->esp0 = tss->esp1 = tss->esp2 = tss->esp = + (unsigned long)stack_base + stack_size; + tss->ds = tss->es = tss->fs = tss->gs = ds; + tss->cs = cs; + tss->eip = (unsigned long)entry; + tss->cr3 = cr3; +} + +static void setup_tss_desc(unsigned short tss_sel, struct tss32 *tss) +{ + unsigned long addr = (unsigned long)tss; + unsigned short *desc; + + desc = (unsigned short *)&gdt[tss_sel/8]; + desc[0] = sizeof(*tss) - 1; + desc[1] = addr; + desc[2] = 0x8900 | ((addr & 0x00ff0000) >> 16); + desc[3] = (addr & 0xff000000) >> 16; +} + +static void set_intr_task(unsigned short tss_sel, int intr, struct tss32 *tss) +{ + unsigned short *desc = (void *)(intr* sizeof(long) * 2); + + setup_tss_desc(tss_sel, tss); + + desc[0] = 0; + desc[1] = tss_sel; + desc[2] = 0x8500; + desc[3] = 0; +} + +int main(int ac, char **av) +{ + const long invalid_segment = 0x1234; + + gdtr = ((unsigned long long)(unsigned long)&gdt << 16) | + (sizeof(gdt) - 1); + asm ("lgdt %0" : : "m" (gdtr)); + + setup_tss(&main_tss, 0, main_stack, sizeof(main_stack)); + setup_tss_desc(FIRST_SPARE_SEL, &main_tss); + asm ("ltr %0" : : "r" ((unsigned short)FIRST_SPARE_SEL)); + + setup_tss(&fault_tss, fault_entry, fault_stack, sizeof(fault_stack)); + set_intr_task(FIRST_SPARE_SEL+8, 13, &fault_tss); + + asm ( + "mov %0,%%es\n" + : : "r" (invalid_segment) : "edi" + ); + + printf("post fault\n"); + + return 0; +}