From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from [140.186.70.92] (port=52854 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PCvtk-0003jg-4T for qemu-devel@nongnu.org; Mon, 01 Nov 2010 11:02:30 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1PCvtW-0000f4-3j for qemu-devel@nongnu.org; Mon, 01 Nov 2010 11:02:01 -0400 Received: from cantor2.suse.de ([195.135.220.15]:39332 helo=mx2.suse.de) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1PCvtV-0000e3-MP for qemu-devel@nongnu.org; Mon, 01 Nov 2010 11:01:58 -0400 From: Alexander Graf Date: Mon, 1 Nov 2010 16:01:29 +0100 Message-Id: <1288623713-28062-17-git-send-email-agraf@suse.de> In-Reply-To: <1288623713-28062-1-git-send-email-agraf@suse.de> References: <1288623713-28062-1-git-send-email-agraf@suse.de> Subject: [Qemu-devel] [PATCH 16/40] xenner: kernel: Main (i386) List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel Developers Cc: Gerd Hoffmann This patch adds the i386 specific piece of xenner's main loop. Signed-off-by: Alexander Graf --- pc-bios/xenner/xenner-main32.c | 390 ++++++++++++++++++++++++++++++++++++++++ 1 files changed, 390 insertions(+), 0 deletions(-) create mode 100644 pc-bios/xenner/xenner-main32.c diff --git a/pc-bios/xenner/xenner-main32.c b/pc-bios/xenner/xenner-main32.c new file mode 100644 index 0000000..0c049dd --- /dev/null +++ b/pc-bios/xenner/xenner-main32.c @@ -0,0 +1,390 @@ +/* + * Copyright (C) Red Hat 2007 + * Copyright (C) Novell Inc. 2010 + * + * Author(s): Gerd Hoffmann + * Alexander Graf + * + * Xenner main functions for 32 bit + * + * 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; under version 2 of the License. + * + * 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, see . + */ + +#include "xenner.h" +#include "xenner-main.c" + +/* --------------------------------------------------------------------- */ +/* helper functions */ + +int bounce_trap(struct xen_cpu *cpu, struct regs_32 *regs, int trapno, int cbno) +{ + uint32_t *kesp, eip = 0, cs = 0; + uint32_t stack_cs, stack_eflags; + int stack_switch = 0; + int error_code = 0; + int interrupt = 0; + int k = 0; + + vminfo.faults[XEN_FAULT_BOUNCE_TRAP]++; + + if (trapno >= 0) { + /* trap bounce */ + eip = xentr[trapno].address; + cs = xentr[trapno].cs; + if (TI_GET_IF(&xentr[trapno])) { + interrupt = 1; + } + if (trapno < (sizeof(trapinfo) / sizeof(trapinfo[0]))) { + error_code = trapinfo[trapno].ec; + } + if (trapno == 14) { + /* page fault */ + cpu->v.vcpu_info->arch.cr2 = read_cr2(); + } + } + if (cbno >= 0) { + /* callback */ + eip = xencb[cbno].eip; + cs = xencb[cbno].cs; + switch (cbno) { + case CALLBACKTYPE_event: + interrupt = 1; + break; + } + } + + if (!cs) { + printk(0, "%s: trapno %d, cbno %d\n", __FUNCTION__, trapno, cbno); + panic("no guest trap handler", regs); + } + + /* set interrupt flag depending on event channel mask */ + stack_eflags = regs->eflags & ~X86_EFLAGS_IF; + if (guest_irq_flag(cpu)) { + stack_eflags |= X86_EFLAGS_IF; + } + + /* old evtchn_upcall_mask is saved in cs slot on the stack */ + stack_cs = regs->cs | ((uint32_t)cpu->v.vcpu_info->evtchn_upcall_mask << 16); + if (interrupt) { + guest_cli(cpu); + } + + if ((regs->cs & 0x03) < (cs & 0x03)) { + panic("bounce trap: illegal ring switch", regs); + } + if ((regs->cs & 0x03) > (cs & 0x03)) { + stack_switch = 1; + } + + /* prepare guest stack: copy from emu, so the handler + * jumps straigt back without round-trip via emu */ + if (stack_switch) { + kesp = (void*)cpu->tss.esp1; + kesp[-(++k)] = regs->ss; // push ss + kesp[-(++k)] = regs->esp; // push esp + } else { + kesp = (void*)regs->esp; + } + + kesp[-(++k)] = stack_eflags; // push eflags + kesp[-(++k)] = stack_cs; // push cs + kesp[-(++k)] = regs->eip; // push eip + if (error_code) { + kesp[-(++k)] = regs->error; // push error code + } + + /* prepare emu stack, so iret jumps to the kernels handler. */ + regs->eip = eip; + regs->cs = cs; + regs->eflags &= EFLAGS_TRAPMASK; + if (stack_switch) { + regs->ss = cpu->tss.ss1; + regs->esp = cpu->tss.esp1; + } + regs->esp -= 4*k; + + return 0; +} + +/* --------------------------------------------------------------------- */ + +static const struct kvm_segment xen32_cs0 = { + .base = 0, + .limit = 0xffffffff, + .selector = 0xe008, + .dpl = 0, + .type = 0xb, + .present = 1, .db = 1, .s = 1, .g = 1, +}; +static const struct kvm_segment xen32_ds0 = { + .base = 0, + .limit = 0xffffffff, + .selector = 0xe010, + .dpl = 0, + .type = 0x3, + .present = 1, .db = 1, .s = 1, .g = 1, +}; +static const struct kvm_segment xen32_cs1 = { + .base = 0, + .limit = 0xffffffff, + .selector = 0xe019, + .dpl = 1, + .type = 0xb, + .present = 1, .db = 1, .s = 1, .g = 1, +}; +static const struct kvm_segment xen32_ds1 = { + .base = 0, + .limit = 0xffffffff, + .selector = 0xe021, + .dpl = 1, + .type = 0x3, + .present = 1, .db = 1, .s = 1, .g = 1, +}; +static const struct kvm_segment xen32_cs3 = { + .base = 0, + .limit = 0xffffffff, + .selector = 0xe02b, + .dpl = 3, + .type = 0xb, + .present = 1, .db = 1, .s = 1, .g = 1, +}; +static const struct kvm_segment xen32_ds3 = { + .base = 0, + .limit = 0xffffffff, + .selector = 0xe033, + .dpl = 3, + .type = 0x3, + .present = 1, .db = 1, .s = 1, .g = 1, +}; + +void gdt_init(struct xen_cpu *cpu) +{ + printk(2, "%s: cpu %d\n", __FUNCTION__, cpu->id); + + if (!cpu->gdt) { + cpu->gdt = get_pages(16, "gdt"); + } + + gdt_set(cpu->gdt, &xen32_cs0); + gdt_set(cpu->gdt, &xen32_ds0); + gdt_set(cpu->gdt, &xen32_cs1); + gdt_set(cpu->gdt, &xen32_ds1); + gdt_set(cpu->gdt, &xen32_cs3); + gdt_set(cpu->gdt, &xen32_ds3); +} + +void tss_init(struct xen_cpu *cpu) +{ + struct descriptor_32 *gdt = cpu->gdt; + int idx = tss(cpu); + + printk(2, "%s: cpu %d\n", __FUNCTION__, cpu->id); + + cpu->tss.esp0 = (uintptr_t)cpu->stack_high; + cpu->tss.ss0 = 0xe010; + + gdt[ idx ] = mkdesc32((uintptr_t)(&cpu->tss), sizeof(cpu->tss)-1, 0x89, 0); +} + +void msrs_init(struct xen_cpu *cpu) +{ + printk(2, "%s: cpu %d\n", __FUNCTION__, cpu->id); +} + +void idt_init(void) +{ + intptr_t entry; + int i,len; + + printk(2, "%s\n", __FUNCTION__); + + len = (irq_common - irq_entries) / 256; + for (i = 0; i < 256; i++) { + entry = (intptr_t)(irq_entries + i*len); + xen_idt[i] = mkgate32(0xe008, (uintptr_t)irq_entries + i*len, 0x8e); + } + + xen_idt[ 0 ] = mkgate32(0xe008, (uintptr_t)division_by_zero, 0x8e); + xen_idt[ 1 ] = mkgate32(0xe008, (uintptr_t)debug_int1, 0x8e); + xen_idt[ 2 ] = mkgate32(0xe008, (uintptr_t)nmi, 0x8e); + xen_idt[ 3 ] = mkgate32(0xe008, (uintptr_t)debug_int3, 0xee); + xen_idt[ 4 ] = mkgate32(0xe008, (uintptr_t)overflow, 0x8e); + xen_idt[ 5 ] = mkgate32(0xe008, (uintptr_t)bound_check, 0x8e); + xen_idt[ 6 ] = mkgate32(0xe008, (uintptr_t)illegal_instruction, 0x8e); + xen_idt[ 7 ] = mkgate32(0xe008, (uintptr_t)no_device, 0x8e); + xen_idt[ 8 ] = mkgate32(0xe008, (uintptr_t)double_fault, 0x8e); + xen_idt[ 9 ] = mkgate32(0xe008, (uintptr_t)coprocessor, 0x8e); + xen_idt[ 10 ] = mkgate32(0xe008, (uintptr_t)invalid_tss, 0x8e); + xen_idt[ 11 ] = mkgate32(0xe008, (uintptr_t)segment_not_present, 0x8e); + xen_idt[ 12 ] = mkgate32(0xe008, (uintptr_t)stack_fault, 0x8e); + xen_idt[ 13 ] = mkgate32(0xe008, (uintptr_t)general_protection, 0x8e); + xen_idt[ 14 ] = mkgate32(0xe008, (uintptr_t)page_fault, 0x8e); + xen_idt[ 16 ] = mkgate32(0xe008, (uintptr_t)floating_point, 0x8e); + xen_idt[ 17 ] = mkgate32(0xe008, (uintptr_t)alignment, 0x8e); + xen_idt[ 18 ] = mkgate32(0xe008, (uintptr_t)machine_check, 0x8e); + xen_idt[ 19 ] = mkgate32(0xe008, (uintptr_t)simd_floating_point, 0x8e); + + xen_idt[ VECTOR_FLUSH_TLB ] = + mkgate32(0xe008, (uintptr_t)smp_flush_tlb, 0x8e); + + xen_idt[ 0x82 ] = mkgate32(0xe008, (uintptr_t)xen_hypercall, 0xae); +} + +/* --------------------------------------------------------------------- */ + +static int pf_fixup_readonly(struct regs_32 *regs, uint32_t cr2) +{ + pte_t *pte = find_pte_lpt(cr2); + + if (cr2 >= XEN_IPT) { + return 0; + } + + if (*pte & _PAGE_USER) { + return 0; + } + + /* is kernel page */ + *pte |= _PAGE_RW; + + vminfo.faults[XEN_FAULT_PAGE_FAULT_FIX_RO]++; + flush_tlb_addr(cr2); + + return 1; +} + +void guest_regs_init(struct xen_cpu *cpu, struct regs_32 *regs) +{ + struct vcpu_guest_context *ctxt = cpu->init_ctxt; + + regs->eax = ctxt->user_regs.eax; + regs->ebx = ctxt->user_regs.ebx; + regs->ecx = ctxt->user_regs.ecx; + regs->edx = ctxt->user_regs.edx; + regs->esi = ctxt->user_regs.esi; + regs->edi = ctxt->user_regs.edi; + regs->ebp = ctxt->user_regs.ebp; + regs->eip = ctxt->user_regs.eip; + regs->cs = ctxt->user_regs.cs; + regs->eflags = ctxt->user_regs.eflags; + regs->esp = ctxt->user_regs.esp; + regs->ss = ctxt->user_regs.ss; + + regs->ds = ctxt->user_regs.ds; + regs->es = ctxt->user_regs.es; + asm volatile("mov %0, %%fs;\n" :: "r" (ctxt->user_regs.fs) : "memory"); + asm volatile("mov %0, %%gs;\n" :: "r" (ctxt->user_regs.gs) : "memory"); +} + +static void set_up_shared_info(void) +{ + int i; + + memset(&shared_info, 0, sizeof(shared_info)); + for ( i = 0; i < XEN_LEGACY_MAX_VCPUS; i++ ) { + shared_info.vcpu_info[i].evtchn_upcall_mask = 1; + } +} + +static void set_up_context(void *_ctxt, unsigned long boot_cr3, + unsigned long init_pt_len) +{ + vcpu_guest_context_t *ctxt = _ctxt; + uint64_t virt_base = emudev_get(EMUDEV_CONF_PV_VIRT_BASE, 0); + uint64_t virt_entry = emudev_get(EMUDEV_CONF_PV_VIRT_ENTRY, 0); + uint64_t boot_stack_pfn = emudev_get(EMUDEV_CONF_PFN_INIT_PT, 0) + + addr_to_frame(init_pt_len + PAGE_SIZE - 1); + uint64_t start_info_pfn = emudev_get(EMUDEV_CONF_PFN_START_INFO, 0); + + set_up_shared_info(); + + /* clear everything */ + memset(ctxt, 0, sizeof(*ctxt)); + + ctxt->user_regs.ds = FLAT_KERNEL_DS_X86_32; + ctxt->user_regs.es = FLAT_KERNEL_DS_X86_32; + ctxt->user_regs.fs = FLAT_KERNEL_DS_X86_32; + ctxt->user_regs.gs = FLAT_KERNEL_DS_X86_32; + ctxt->user_regs.ss = FLAT_KERNEL_SS_X86_32; + ctxt->user_regs.cs = FLAT_KERNEL_CS_X86_32; + ctxt->user_regs.eip = virt_entry; + ctxt->user_regs.esp = virt_base | ((boot_stack_pfn + 1) << PAGE_SHIFT); + ctxt->user_regs.esi = virt_base | (start_info_pfn << PAGE_SHIFT); + ctxt->user_regs.eflags = 1 << 9; /* Interrupt Enable */ + + ctxt->kernel_ss = ctxt->user_regs.ss; + ctxt->kernel_sp = ctxt->user_regs.esp; + + ctxt->flags = VGCF_in_kernel_X86_32 | VGCF_online_X86_32; + ctxt->ctrlreg[3] = boot_cr3; +} + +static void guest_hypercall_page(struct xen_cpu *cpu) +{ + unsigned long _hypercall_page = emudev_get(EMUDEV_CONF_HYPERCALL_PAGE, 0); + char *hypercall_page = (char*)_hypercall_page; + + char *p; + int i; + + /* Fill in all the transfer points with template machine code. */ + for ( i = 0; i < (PAGE_SIZE / 32); i++ ) { + p = (char *)(hypercall_page + (i * 32)); + *(uint8_t *)(p+ 0) = 0xb8; /* mov $,%eax */ + *(uint32_t *)(p+ 1) = i; + *(uint16_t *)(p+ 5) = 0x82cd; /* int $0x82 */ + *(uint8_t *)(p+ 7) = 0xc3; /* ret */ + } + + /* + * HYPERVISOR_iret is special because it doesn't return and expects a + * special stack frame. Guests jump at this transfer point instead of + * calling it. + */ + p = (char *)(hypercall_page + (__HYPERVISOR_iret * 32)); + *(uint8_t *)(p+ 0) = 0x50; /* push %eax */ + *(uint8_t *)(p+ 1) = 0xb8; /* mov $__HYPERVISOR_iret,%eax */ + *(uint32_t *)(p+ 2) = __HYPERVISOR_iret; + *(uint16_t *)(p+ 6) = 0x82cd; /* int $0x82 */ +} + + +/* --------------------------------------------------------------------- */ +/* called from assembler */ + +asmlinkage void do_page_fault(struct regs_32 *regs) +{ + struct xen_cpu *cpu =get_cpu(); + uint32_t cr2 = read_cr2(); + + vminfo.faults[XEN_FAULT_PAGE_FAULT]++; + + if (context_is_emu(regs)) { + if (fixup_extable(regs)) { + return; + } + print_page_fault_info(0, cpu, regs, cr2); + panic("ring0 (emu) page fault", regs); + } + + if (wrpt && regs->error == 3) { + /* kernel write to r/o page */ + if (pf_fixup_readonly(regs, cr2)) { + return; + } + } + + vminfo.faults[XEN_FAULT_PAGE_FAULT_GUEST]++; + bounce_trap(cpu, regs, 14, -1); +} -- 1.6.0.2