[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] This patch provide local APIC support for vmx guest.
# HG changeset patch # User kaf24@xxxxxxxxxxxxxxxxxxxx # Node ID cc23d4236b2054f9d0cea98cff2e2955d6b3bdd9 # Parent f23b897930d15ec692060ff25c7acc1f44894d69 This patch provide local APIC support for vmx guest. A configure option is also added to disable it, which is off by default. Signed-off-by: Jiang Yunhong <yunhong.jiang@xxxxxxxxx> Signed-off-by: Li Xin <xin.b.li@xxxxxxxxx> Signed-off-by: Eddie Dong <eddie.dong@xxxxxxxxx> Signed-off-by: Jun Nakajima <jun.nakajima@xxxxxxxxx> diff -r f23b897930d1 -r cc23d4236b20 tools/libxc/xc_vmx_build.c --- a/tools/libxc/xc_vmx_build.c Thu Oct 27 17:22:45 2005 +++ b/tools/libxc/xc_vmx_build.c Fri Oct 28 08:48:46 2005 @@ -279,6 +279,7 @@ vcpu_guest_context_t *ctxt, unsigned long shared_info_frame, unsigned int control_evtchn, + unsigned int lapic, unsigned int vcpus, unsigned int store_evtchn, unsigned long *store_mfn) @@ -554,7 +555,7 @@ ctxt->user_regs.eax = 0; ctxt->user_regs.esp = 0; ctxt->user_regs.ebx = 0; /* startup_32 expects this to be 0 to signal boot cpu */ - ctxt->user_regs.ecx = 0; + ctxt->user_regs.ecx = lapic; ctxt->user_regs.esi = 0; ctxt->user_regs.edi = 0; ctxt->user_regs.ebp = 0; @@ -597,6 +598,7 @@ int memsize, const char *image_name, unsigned int control_evtchn, + unsigned int lapic, unsigned int vcpus, unsigned int store_evtchn, unsigned long *store_mfn) @@ -651,9 +653,9 @@ goto error_out; } - if ( setup_guest(xc_handle, domid, memsize, image, image_size, - nr_pages, ctxt, op.u.getdomaininfo.shared_info_frame, - control_evtchn, vcpus, store_evtchn, store_mfn) < 0) + if ( setup_guest(xc_handle, domid, memsize, image, image_size, nr_pages, + ctxt, op.u.getdomaininfo.shared_info_frame, control_evtchn, + lapic, vcpus, store_evtchn, store_mfn) < 0) { ERROR("Error constructing guest OS"); goto error_out; diff -r f23b897930d1 -r cc23d4236b20 tools/libxc/xenguest.h --- a/tools/libxc/xenguest.h Thu Oct 27 17:22:45 2005 +++ b/tools/libxc/xenguest.h Fri Oct 28 08:48:46 2005 @@ -56,6 +56,7 @@ int memsize, const char *image_name, unsigned int control_evtchn, + unsigned int lapic, unsigned int vcpus, unsigned int store_evtchn, unsigned long *store_mfn); diff -r f23b897930d1 -r cc23d4236b20 tools/python/xen/lowlevel/xc/xc.c --- a/tools/python/xen/lowlevel/xc/xc.c Thu Oct 27 17:22:45 2005 +++ b/tools/python/xen/lowlevel/xc/xc.c Fri Oct 28 08:48:46 2005 @@ -438,19 +438,20 @@ char *image; int control_evtchn, store_evtchn; int vcpus = 1; + int lapic = 0; int memsize; unsigned long store_mfn = 0; static char *kwd_list[] = { "dom", "control_evtchn", "store_evtchn", - "memsize", "image", "vcpus", NULL }; - - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiiisi", kwd_list, + "memsize", "image", "lapic", "vcpus", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiiisii", kwd_list, &dom, &control_evtchn, &store_evtchn, - &memsize, &image, &vcpus) ) + &memsize, &image, &lapic, &vcpus) ) return NULL; if ( xc_vmx_build(xc->xc_handle, dom, memsize, image, control_evtchn, - vcpus, store_evtchn, &store_mfn) != 0 ) + lapic, vcpus, store_evtchn, &store_mfn) != 0 ) return PyErr_SetFromErrno(xc_error); return Py_BuildValue("{s:i}", "store_mfn", store_mfn); diff -r f23b897930d1 -r cc23d4236b20 tools/python/xen/xend/image.py --- a/tools/python/xen/xend/image.py Thu Oct 27 17:22:45 2005 +++ b/tools/python/xen/xend/image.py Fri Oct 28 08:48:46 2005 @@ -203,6 +203,10 @@ self.dmargs += self.configVNC(imageConfig) + self.lapic = 0 + lapic = sxp.child_value(imageConfig, 'lapic') + if not lapic is None: + self.lapic = int(lapic) def buildDomain(self): # Create an event channel @@ -217,6 +221,7 @@ log.debug("control_evtchn = %d", self.device_channel) log.debug("store_evtchn = %d", store_evtchn) log.debug("memsize = %d", self.vm.getMemoryTarget() / 1024) + log.debug("lapic = %d", self.lapic) log.debug("vcpus = %d", self.vm.getVCpuCount()) return xc.vmx_build(dom = self.vm.getDomid(), @@ -224,6 +229,7 @@ control_evtchn = self.device_channel, store_evtchn = store_evtchn, memsize = self.vm.getMemoryTarget() / 1024, + lapic = self.lapic, vcpus = self.vm.getVCpuCount()) diff -r f23b897930d1 -r cc23d4236b20 tools/python/xen/xm/create.py --- a/tools/python/xen/xm/create.py Thu Oct 27 17:22:45 2005 +++ b/tools/python/xen/xm/create.py Fri Oct 28 08:48:46 2005 @@ -158,6 +158,10 @@ fn=set_int, default=None, use="CPU to run the domain on.") +gopts.var('lapic', val='LAPIC', + fn=set_int, default=0, + use="Disable or enable local APIC of VMX domain.") + gopts.var('vcpus', val='VCPUS', fn=set_int, default=1, use="# of Virtual CPUS in domain.") @@ -315,10 +319,6 @@ gopts.var('nfs_root', val="PATH", fn=set_value, default=None, use="Set the path of the root NFS directory.") - -gopts.var('memmap', val='FILE', - fn=set_value, default='', - use="Path to memap SXP file.") gopts.var('device_model', val='FILE', fn=set_value, default='', @@ -542,9 +542,9 @@ def configure_vmx(opts, config_image, vals): """Create the config for VMX devices. """ - args = [ 'memmap', 'device_model', 'vcpus', 'cdrom', - 'boot', 'fda', 'fdb', 'localtime', 'serial', 'macaddr', 'stdvga', - 'isa', 'nographic', 'vnc', 'vncviewer', 'sdl', 'display', 'ne2000'] + args = [ 'device_model', 'vcpus', 'cdrom', 'boot', 'fda', 'fdb', + 'localtime', 'serial', 'macaddr', 'stdvga', 'isa', 'nographic', + 'vnc', 'vncviewer', 'sdl', 'display', 'ne2000', 'lapic'] for a in args: if (vals.__dict__[a]): config_image.append([a, vals.__dict__[a]]) diff -r f23b897930d1 -r cc23d4236b20 xen/arch/x86/apic.c --- a/xen/arch/x86/apic.c Thu Oct 27 17:22:45 2005 +++ b/xen/arch/x86/apic.c Fri Oct 28 08:48:46 2005 @@ -815,6 +815,10 @@ return result; } +unsigned int get_apic_bus_scale(void) +{ + return bus_scale; +} static unsigned int calibration_result; diff -r f23b897930d1 -r cc23d4236b20 xen/arch/x86/dm/i8259.c --- a/xen/arch/x86/dm/i8259.c Thu Oct 27 17:22:45 2005 +++ b/xen/arch/x86/dm/i8259.c Fri Oct 28 08:48:46 2005 @@ -32,8 +32,8 @@ #include <public/io/ioreq.h> #include <asm/vmx.h> #include <public/io/vmx_vpic.h> -#include <public/io/vmx_vlapic.h> #include <asm/current.h> +#include <asm/vmx_vlapic.h> /* set irq level. If an edge is detected, then the IRR is set to 1 */ static inline void pic_set_irq1(PicState *s, int irq, int level) @@ -135,7 +135,6 @@ { s->pics[1].irr |= (uint8_t)(irqs >> 8); s->pics[0].irr |= (uint8_t) irqs; - /* TODO for alt_irq_func */ pic_update_irq(s); } @@ -505,14 +504,22 @@ { int intno; struct vmx_virpic *s = &v->domain->arch.vmx_platform.vmx_pic; - + struct vmx_platform *plat = &v->domain->arch.vmx_platform; + + if ( !vlapic_accept_pic_intr(v) ) + return -1; + + if ( !plat->interrupt_request ) + return -1; + /* read the irq from the PIC */ intno = pic_read_irq(s); *type = VLAPIC_DELIV_MODE_EXT; + plat->interrupt_request = 0; return intno; } -int is_pit_irq(struct vcpu *v, int irq) +int is_pit_irq(struct vcpu *v, int irq, int type) { int pit_vec = v->domain->arch.vmx_platform.vmx_pic.pics[0].irq_base; diff -r f23b897930d1 -r cc23d4236b20 xen/arch/x86/vmx.c --- a/xen/arch/x86/vmx.c Thu Oct 27 17:22:45 2005 +++ b/xen/arch/x86/vmx.c Fri Oct 28 08:48:46 2005 @@ -65,6 +65,11 @@ if ( v == v->domain->vcpu[0] ) { + v->domain->arch.vmx_platform.lapic_enable = + v->arch.guest_context.user_regs.ecx; + v->arch.guest_context.user_regs.ecx = 0; + VMX_DBG_LOG(DBG_LEVEL_VLAPIC, "lapic enable is %d.\n", + v->domain->arch.vmx_platform.lapic_enable); /* * Required to do this once per domain * XXX todo: add a seperate function to do these. @@ -96,6 +101,10 @@ destroy_vmcs(&v->arch.arch_vmx); free_monitor_pagetable(v); rem_ac_timer(&v->domain->arch.vmx_platform.vmx_pit.pit_timer); + if ( vmx_apic_support(v->domain) ) { + rem_ac_timer( &(VLAPIC(v)->vlapic_timer) ); + xfree( VLAPIC(v) ); + } } #ifdef __x86_64__ @@ -442,7 +451,9 @@ /* Use 1:1 page table to identify MMIO address space */ if ( mmio_space(gpa) ){ - if (gpa >= 0xFEE00000) { /* workaround for local APIC */ + struct vcpu *v = current; + /* No support for APIC */ + if (!vmx_apic_support(v->domain) && gpa >= 0xFEC00000) { u32 inst_len; __vmread(VM_EXIT_INSTRUCTION_LEN, &(inst_len)); __update_guest_eip(inst_len); @@ -487,6 +498,7 @@ { unsigned int eax, ebx, ecx, edx; unsigned long eip; + struct vcpu *v = current; __vmread(GUEST_RIP, &eip); @@ -500,6 +512,9 @@ cpuid(input, &eax, &ebx, &ecx, &edx); if (input == 1) { + if ( vmx_apic_support(v->domain) && + !vlapic_global_enabled((VLAPIC(v))) ) + clear_bit(X86_FEATURE_APIC, &edx); #ifdef __i386__ clear_bit(X86_FEATURE_PSE, &edx); clear_bit(X86_FEATURE_PAE, &edx); @@ -1441,6 +1456,7 @@ static inline void vmx_do_msr_read(struct cpu_user_regs *regs) { u64 msr_content = 0; + struct vcpu *v = current; VMX_DBG_LOG(DBG_LEVEL_1, "vmx_do_msr_read: ecx=%lx, eax=%lx, edx=%lx", (unsigned long)regs->ecx, (unsigned long)regs->eax, @@ -1455,6 +1471,9 @@ case MSR_IA32_SYSENTER_EIP: __vmread(GUEST_SYSENTER_EIP, &msr_content); break; + case MSR_IA32_APICBASE: + msr_content = VLAPIC(v) ? VLAPIC(v)->apic_base_msr : 0; + break; default: if(long_mode_do_msr_read(regs)) return; @@ -1474,6 +1493,7 @@ static inline void vmx_do_msr_write(struct cpu_user_regs *regs) { u64 msr_content; + struct vcpu *v = current; VMX_DBG_LOG(DBG_LEVEL_1, "vmx_do_msr_write: ecx=%lx, eax=%lx, edx=%lx", (unsigned long)regs->ecx, (unsigned long)regs->eax, @@ -1490,6 +1510,9 @@ break; case MSR_IA32_SYSENTER_EIP: __vmwrite(GUEST_SYSENTER_EIP, msr_content); + break; + case MSR_IA32_APICBASE: + vlapic_msr_set(VLAPIC(v), msr_content); break; default: long_mode_do_msr_write(regs); diff -r f23b897930d1 -r cc23d4236b20 xen/arch/x86/vmx_intercept.c --- a/xen/arch/x86/vmx_intercept.c Thu Oct 27 17:22:45 2005 +++ b/xen/arch/x86/vmx_intercept.c Fri Oct 28 08:48:46 2005 @@ -23,6 +23,7 @@ #include <asm/vmx_platform.h> #include <asm/vmx_virpit.h> #include <asm/vmx_intercept.h> +#include <asm/vmx_vlapic.h> #include <public/io/ioreq.h> #include <xen/lib.h> #include <xen/sched.h> @@ -31,6 +32,123 @@ #include <xen/event.h> #ifdef CONFIG_VMX + +struct vmx_mmio_handler vmx_mmio_handers[VMX_MMIO_HANDLER_NR] = +{ + { + .check_handler = vlapic_range, + .read_handler = vlapic_read, + .write_handler = vlapic_write + } +}; + +static inline void vmx_mmio_access(struct vcpu *v, + ioreq_t *p, + vmx_mmio_read_t read_handler, + vmx_mmio_write_t write_handler) +{ + ioreq_t *req; + vcpu_iodata_t *vio = get_vio(v->domain, v->vcpu_id); + unsigned int tmp1, tmp2; + unsigned long data; + + if (vio == NULL) { + printk("vlapic_access: bad shared page\n"); + domain_crash_synchronous(); + } + + req = &vio->vp_ioreq; + + switch (req->type) { + case IOREQ_TYPE_COPY: + { + int sign = (req->df) ? -1 : 1, i; + + if (!req->pdata_valid) { + if (req->dir == IOREQ_READ){ + req->u.data = read_handler(v, req->addr, req->size); + } else { /* req->dir != IOREQ_READ */ + write_handler(v, req->addr, req->size, req->u.data); + } + } else { /* !req->pdata_valid */ + if (req->dir == IOREQ_READ) { + for (i = 0; i < req->count; i++) { + data = read_handler(v, + req->addr + (sign * i * req->size), + req->size); + vmx_copy(&data, + (unsigned long)p->u.pdata + (sign * i * req->size), + p->size, + VMX_COPY_OUT); + } + } else { /* !req->dir == IOREQ_READ */ + for (i = 0; i < req->count; i++) { + vmx_copy(&data, + (unsigned long)p->u.pdata + (sign * i * req->size), + p->size, + VMX_COPY_IN); + write_handler(v, + req->addr + (sign * i * req->size), + req->size, data); + } + } + } + break; + } + + case IOREQ_TYPE_AND: + tmp1 = read_handler(v, req->addr, req->size); + if (req->dir == IOREQ_WRITE) { + tmp2 = tmp1 & (unsigned long) req->u.data; + write_handler(v, req->addr, req->size, tmp2); + } + req->u.data = tmp1; + break; + + case IOREQ_TYPE_OR: + tmp1 = read_handler(v, req->addr, req->size); + if (req->dir == IOREQ_WRITE) { + tmp2 = tmp1 | (unsigned long) req->u.data; + write_handler(v, req->addr, req->size, tmp2); + } + req->u.data = tmp1; + break; + + case IOREQ_TYPE_XOR: + tmp1 = read_handler(v, req->addr, req->size); + if (req->dir == IOREQ_WRITE) { + tmp2 = tmp1 ^ (unsigned long) req->u.data; + write_handler(v, req->addr, req->size, tmp2); + } + req->u.data = tmp1; + break; + + default: + printk("error ioreq type for local APIC %x\n", req->type); + domain_crash_synchronous(); + break; + } +} + +int vmx_mmio_intercept(ioreq_t *p) +{ + struct vcpu *v = current; + int i; + struct vmx_mmio_handler *handler = vmx_mmio_handers; + + /* XXX currently only APIC use intercept */ + if ( !vmx_apic_support(v->domain) ) + return 0; + + for ( i = 0; i < VMX_MMIO_HANDLER_NR; i++ ) { + if ( handler[i].check_handler(v, p->addr) ) { + vmx_mmio_access(v, p, + handler[i].read_handler, handler[i].write_handler); + return 1; + } + } + return 0; +} /* * Check if the request is handled inside xen diff -r f23b897930d1 -r cc23d4236b20 xen/arch/x86/vmx_io.c --- a/xen/arch/x86/vmx_io.c Thu Oct 27 17:22:45 2005 +++ b/xen/arch/x86/vmx_io.c Fri Oct 28 08:48:46 2005 @@ -36,9 +36,9 @@ #include <asm/apic.h> #include <asm/shadow.h> +#include <asm/vmx_vlapic.h> #include <public/io/ioreq.h> #include <public/io/vmx_vpic.h> -#include <public/io/vmx_vlapic.h> #ifdef CONFIG_VMX #if defined (__i386__) @@ -732,48 +732,6 @@ } while(1); } -#if defined(__i386__) || defined(__x86_64__) -static inline int __fls(u32 word) -{ - int bit; - - __asm__("bsrl %1,%0" - :"=r" (bit) - :"rm" (word)); - return word ? bit : -1; -} -#else -#define __fls(x) generic_fls(x) -static __inline__ int generic_fls(u32 x) -{ - int r = 31; - - if (!x) - return -1; - if (!(x & 0xffff0000u)) { - x <<= 16; - r -= 16; - } - if (!(x & 0xff000000u)) { - x <<= 8; - r -= 8; - } - if (!(x & 0xf0000000u)) { - x <<= 4; - r -= 4; - } - if (!(x & 0xc0000000u)) { - x <<= 2; - r -= 2; - } - if (!(x & 0x80000000u)) { - x <<= 1; - r -= 1; - } - return r; -} -#endif - /* Simple minded Local APIC priority implementation. Fix later */ static __inline__ int find_highest_irq(u32 *pintr) { @@ -801,31 +759,31 @@ struct vmx_virpit *vpit = &(v->domain->arch.vmx_platform.vmx_pit); u64 drift; + if ( is_pit_irq(v, vector, type) ) { + if ( !vpit->first_injected ) { + vpit->first_injected = 1; + vpit->pending_intr_nr = 0; + } else { + vpit->pending_intr_nr--; + } + vpit->inject_point = NOW(); + drift = vpit->period_cycles * vpit->pending_intr_nr; + drift = v->arch.arch_vmx.tsc_offset - drift; + __vmwrite(TSC_OFFSET, drift); + +#if defined (__i386__) + __vmwrite(TSC_OFFSET_HIGH, (drift >> 32)); +#endif + + } + switch(type) { case VLAPIC_DELIV_MODE_EXT: - if ( is_pit_irq(v, vector) ) { - if ( !vpit->first_injected ) { - vpit->first_injected = 1; - vpit->pending_intr_nr = 0; - } - else { - vpit->pending_intr_nr--; - } - vpit->inject_point = NOW(); - drift = vpit->period_cycles * vpit->pending_intr_nr; - drift = v->arch.arch_vmx.tsc_offset - drift; - __vmwrite(TSC_OFFSET, drift); - -#if defined (__i386__) - __vmwrite(TSC_OFFSET_HIGH, (drift >> 32)); -#endif - - } break; default: - printk("Not support interrupt type\n"); + vlapic_post_injection(v, vector, type); break; } } @@ -885,6 +843,24 @@ } +int cpu_get_interrupt(struct vcpu *v, int *type) +{ + int intno; + struct vmx_virpic *s = &v->domain->arch.vmx_platform.vmx_pic; + + if ( (intno = cpu_get_apic_interrupt(v, type)) != -1 ) { + /* set irq request if a PIC irq is still pending */ + /* XXX: improve that */ + pic_update_irq(s); + return intno; + } + /* read the irq from the PIC */ + if ( (intno = cpu_get_pic_interrupt(v, type)) != -1 ) + return intno; + + return -1; +} + asmlinkage void vmx_intr_assist(void) { int intr_type = 0; @@ -902,11 +878,6 @@ pic_set_irq(pic, 0, 1); } - if ( !plat->interrupt_request ) { - disable_irq_window(cpu_exec_control); - return; - } - __vmread(VM_ENTRY_INTR_INFO_FIELD, &intr_fields); if (intr_fields & INTR_INFO_VALID_MASK) { @@ -928,16 +899,21 @@ enable_irq_window(cpu_exec_control); return; } - plat->interrupt_request = 0; - highest_vector = cpu_get_pic_interrupt(v, &intr_type); + + highest_vector = cpu_get_interrupt(v, &intr_type); + + if (highest_vector == -1) { + disable_irq_window(cpu_exec_control); + return; + } switch (intr_type) { case VLAPIC_DELIV_MODE_EXT: + case VLAPIC_DELIV_MODE_FIXED: + case VLAPIC_DELIV_MODE_LPRI: vmx_inject_extint(v, highest_vector, VMX_INVALID_ERROR_CODE); TRACE_3D(TRC_VMX_INT, v->domain->domain_id, highest_vector, 0); break; - case VLAPIC_DELIV_MODE_FIXED: - case VLAPIC_DELIV_MODE_LPRI: case VLAPIC_DELIV_MODE_SMI: case VLAPIC_DELIV_MODE_NMI: case VLAPIC_DELIV_MODE_INIT: diff -r f23b897930d1 -r cc23d4236b20 xen/arch/x86/vmx_vmcs.c --- a/xen/arch/x86/vmx_vmcs.c Thu Oct 27 17:22:45 2005 +++ b/xen/arch/x86/vmx_vmcs.c Fri Oct 28 08:48:46 2005 @@ -252,6 +252,10 @@ pic_init(&platform->vmx_pic, pic_irq_request, &platform->interrupt_request); register_pic_io_hook(); + + if ( vmx_apic_support(d) ) { + spin_lock_init(&d->arch.vmx_platform.round_robin_lock); + } } static void vmx_set_host_env(struct vcpu *v) @@ -312,6 +316,9 @@ error |= __vmwrite(CR4_READ_SHADOW, cr4); vmx_stts(); + + if(vmx_apic_support(v->domain)) + vlapic_init(v); vmx_set_host_env(v); diff -r f23b897930d1 -r cc23d4236b20 xen/include/asm-x86/vmx_intercept.h --- a/xen/include/asm-x86/vmx_intercept.h Thu Oct 27 17:22:45 2005 +++ b/xen/include/asm-x86/vmx_intercept.h Fri Oct 28 08:48:46 2005 @@ -14,6 +14,16 @@ #define VMX_MMIO 1 typedef int (*intercept_action_t)(ioreq_t *); +typedef unsigned long (*vmx_mmio_read_t)(struct vcpu *v, + unsigned long addr, + unsigned long length); + +typedef unsigned long (*vmx_mmio_write_t)(struct vcpu *v, + unsigned long addr, + unsigned long length, + unsigned long val); + +typedef int (*vmx_mmio_check_t)(struct vcpu *v, unsigned long addr); struct io_handler { int type; @@ -27,6 +37,16 @@ struct io_handler hdl_list[MAX_IO_HANDLER]; }; +struct vmx_mmio_handler { + vmx_mmio_check_t check_handler; + vmx_mmio_read_t read_handler; + vmx_mmio_write_t write_handler; +}; + +#define VMX_MMIO_HANDLER_NR 1 + +extern struct vmx_mmio_handler vmx_mmio_handers[VMX_MMIO_HANDLER_NR]; + /* global io interception point in HV */ extern int vmx_io_intercept(ioreq_t *p, int type); extern int register_io_handler(unsigned long addr, unsigned long size, @@ -37,10 +57,7 @@ return vmx_io_intercept(p, VMX_PORTIO); } -static inline int vmx_mmio_intercept(ioreq_t *p) -{ - return vmx_io_intercept(p, VMX_MMIO); -} +int vmx_mmio_intercept(ioreq_t *p); static inline int register_portio_handler(unsigned long addr, unsigned long size, @@ -49,11 +66,4 @@ return register_io_handler(addr, size, action, VMX_PORTIO); } -static inline int register_mmio_handler(unsigned long addr, - unsigned long size, - intercept_action_t action) -{ - return register_io_handler(addr, size, action, VMX_MMIO); -} - #endif /* _VMX_INTERCEPT_H */ diff -r f23b897930d1 -r cc23d4236b20 xen/include/asm-x86/vmx_platform.h --- a/xen/include/asm-x86/vmx_platform.h Thu Oct 27 17:22:45 2005 +++ b/xen/include/asm-x86/vmx_platform.h Fri Oct 28 08:48:46 2005 @@ -80,10 +80,13 @@ struct vmx_platform { unsigned long shared_page_va; unsigned int nr_vcpu; + unsigned int lapic_enable; struct vmx_virpit vmx_pit; struct vmx_io_handler vmx_io_handler; struct vmx_virpic vmx_pic; + unsigned char round_info[256]; + spinlock_t round_robin_lock; int interrupt_request; }; diff -r f23b897930d1 -r cc23d4236b20 xen/include/asm-x86/vmx_vmcs.h --- a/xen/include/asm-x86/vmx_vmcs.h Thu Oct 27 17:22:45 2005 +++ b/xen/include/asm-x86/vmx_vmcs.h Fri Oct 28 08:48:46 2005 @@ -22,6 +22,7 @@ #include <asm/config.h> #include <asm/vmx_cpu.h> #include <asm/vmx_platform.h> +#include <asm/vmx_vlapic.h> #include <public/vmx_assist.h> extern int start_vmx(void); @@ -96,6 +97,7 @@ struct msr_state msr_content; struct mmio_op mmio_op; /* MMIO */ void *io_bitmap_a, *io_bitmap_b; + struct vlapic *vlapic; u64 tsc_offset; }; @@ -272,18 +274,21 @@ #define VMX_DEBUG 1 #if VMX_DEBUG -#define DBG_LEVEL_0 (1 << 0) -#define DBG_LEVEL_1 (1 << 1) -#define DBG_LEVEL_2 (1 << 2) -#define DBG_LEVEL_3 (1 << 3) -#define DBG_LEVEL_IO (1 << 4) -#define DBG_LEVEL_VMMU (1 << 5) +#define DBG_LEVEL_0 (1 << 0) +#define DBG_LEVEL_1 (1 << 1) +#define DBG_LEVEL_2 (1 << 2) +#define DBG_LEVEL_3 (1 << 3) +#define DBG_LEVEL_IO (1 << 4) +#define DBG_LEVEL_VMMU (1 << 5) +#define DBG_LEVEL_VLAPIC (1 << 6) +#define DBG_LEVEL_VLAPIC_TIMER (1 << 7) +#define DBG_LEVEL_VLAPIC_INTERRUPT (1 << 7) extern unsigned int opt_vmx_debug_level; #define VMX_DBG_LOG(level, _f, _a...) \ if ((level) & opt_vmx_debug_level) \ printk("[VMX:%d.%d] " _f "\n", \ - current->domain->domain_id, current->vcpu_id, ## _a) + current->domain->domain_id, current->vcpu_id, ## _a) #else #define VMX_DBG_LOG(level, _f, _a...) #endif diff -r f23b897930d1 -r cc23d4236b20 xen/include/public/io/ioreq.h --- a/xen/include/public/io/ioreq.h Thu Oct 27 17:22:45 2005 +++ b/xen/include/public/io/ioreq.h Fri Oct 28 08:48:46 2005 @@ -29,11 +29,11 @@ #define STATE_IORESP_READY 3 #define STATE_IORESP_HOOK 4 -#define IOREQ_TYPE_PIO 0 /* pio */ -#define IOREQ_TYPE_COPY 1 /* mmio ops */ -#define IOREQ_TYPE_AND 2 -#define IOREQ_TYPE_OR 3 -#define IOREQ_TYPE_XOR 4 +#define IOREQ_TYPE_PIO 0 /* pio */ +#define IOREQ_TYPE_COPY 1 /* mmio ops */ +#define IOREQ_TYPE_AND 2 +#define IOREQ_TYPE_OR 3 +#define IOREQ_TYPE_XOR 4 /* * VMExit dispatcher should cooperate with instruction decoder to @@ -55,9 +55,10 @@ uint8_t type; /* I/O type */ } ioreq_t; -#define MAX_VECTOR 256 +#define MAX_VECTOR 256 #define BITS_PER_BYTE 8 #define INTR_LEN (MAX_VECTOR/(BITS_PER_BYTE * sizeof(uint64_t))) +#define INTR_LEN_32 (MAX_VECTOR/(BITS_PER_BYTE * sizeof(uint32_t))) typedef struct { uint16_t pic_elcr; diff -r f23b897930d1 -r cc23d4236b20 xen/include/public/io/vmx_vpic.h --- a/xen/include/public/io/vmx_vpic.h Thu Oct 27 17:22:45 2005 +++ b/xen/include/public/io/vmx_vpic.h Fri Oct 28 08:48:46 2005 @@ -76,7 +76,7 @@ uint32_t pic_intack_read(struct vmx_virpic *s); void register_pic_io_hook (void); int cpu_get_pic_interrupt(struct vcpu *v, int *type); -int is_pit_irq(struct vcpu *v, int irq); +int is_pit_irq(struct vcpu *v, int irq, int type); void do_pic_irqs (struct vmx_virpic *s, uint16_t irqs); void do_pic_irqs_clear (struct vmx_virpic *s, uint16_t irqs); diff -r f23b897930d1 -r cc23d4236b20 xen/arch/x86/vmx_vlapic.c --- /dev/null Thu Oct 27 17:22:45 2005 +++ b/xen/arch/x86/vmx_vlapic.c Fri Oct 28 08:48:46 2005 @@ -0,0 +1,997 @@ +/* + * vmx_vlapic.c: virtualize LAPIC for VMX vcpus. + * Copyright (c) 2004, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * + */ + +#include <xen/config.h> +#include <xen/types.h> +#include <xen/mm.h> +#include <xen/xmalloc.h> +#include <asm/shadow.h> +#include <asm/page.h> +#include <xen/event.h> +#include <xen/trace.h> +#include <asm/vmx.h> +#include <asm/vmx_platform.h> +#include <asm/vmx_vlapic.h> + +#include <xen/lib.h> +#include <xen/sched.h> +#include <asm/current.h> +#include <public/io/ioreq.h> + +#ifdef CONFIG_VMX + +/* XXX remove this definition after GFW enabled */ +#define VLAPIC_NO_BIOS + +extern unsigned int get_apic_bus_scale(void); + +static unsigned int vlapic_lvt_mask[VLAPIC_LVT_NUM] = +{ + 0x310ff, 0x117ff, 0x117ff, 0x1f7ff, 0x1f7ff, 0x117ff +}; + +int vlapic_find_highest_irr(struct vlapic *vlapic) +{ + int result; + + result = find_highest_bit((uint32_t *)&vlapic->irr[0], INTR_LEN_32); + + if (result != -1 && result < 16) { + printk("VLAPIC: irr on reserved bits %d\n ", result); + domain_crash_synchronous(); + } + + return result; +} + +inline int vmx_apic_support(struct domain *d) +{ + return d->arch.vmx_platform.lapic_enable; +} + +int vlapic_find_highest_isr(struct vlapic *vlapic) +{ + int result; + + result = find_highest_bit((uint32_t *)&vlapic->isr[0], INTR_LEN_32); + + if (result != -1 && result < 16) { + int i = 0; + printk("VLAPIC: isr on reserved bits %d, isr is\n ", result); + for (i = 0; i < INTR_LEN_32; i += 2) + printk("%d: 0x%08x%08x\n", i, vlapic->isr[i], vlapic->isr[i+1]); + return -1; + } + + return result; +} + +uint32_t vlapic_update_ppr(struct vlapic *vlapic) +{ + uint32_t tpr, isrv, ppr; + int isr; + + tpr = (vlapic->task_priority >> 4) & 0xf; /* we want 7:4 */ + + isr = vlapic_find_highest_isr(vlapic); + if (isr != -1) + isrv = (isr >> 4) & 0xf; /* ditto */ + else + isrv = 0; + + if (tpr >= isrv) + ppr = vlapic->task_priority & 0xff; + else + ppr = isrv << 4; /* low 4 bits of PPR have to be cleared */ + + vlapic->processor_priority = ppr; + + VMX_DBG_LOG(DBG_LEVEL_VLAPIC_INTERRUPT, + "vlapic_update_ppr: vlapic %p ppr %x isr %x isrv %x", + vlapic, ppr, isr, isrv); + + return ppr; +} + +/* This only for fixed delivery mode */ +int vlapic_match_dest(struct vlapic *target, struct vlapic *source, + int short_hand, int dest, int dest_mode, + int delivery_mode) +{ + int result = 0; + + VMX_DBG_LOG(DBG_LEVEL_VLAPIC, "vlapic_match_dest: " + "target %p source %p dest %x dest_mode %x short_hand %x " + "delivery_mode %x", + target, source, dest, dest_mode, short_hand, delivery_mode); + + switch (short_hand) { + case VLAPIC_NO_SHORTHAND: + if (!dest_mode) { /* Physical */ + result = (target->id == dest); + } else { /* Logical */ + if (((target->dest_format >> 28) & 0xf) == 0xf) { /* Flat mode */ + result = (target->logical_dest >> 24) & dest; + } else { + if ((delivery_mode == VLAPIC_DELIV_MODE_LPRI) && + (dest == 0xff)) { + /* What shall we do now? */ + printk("Broadcast IPI with lowest priority " + "delivery mode\n"); + domain_crash_synchronous(); + } + result = (target->logical_dest == (dest & 0xf)) ? + ((target->logical_dest >> 4) & (dest >> 4)) : 0; + } + } + break; + + case VLAPIC_SHORTHAND_SELF: + if (target == source) + result = 1; + break; + + case VLAPIC_SHORTHAND_INCLUDE_SELF: + result = 1; + break; + + case VLAPIC_SHORTHAND_EXCLUDE_SELF: + if (target != source) + result = 1; + break; + + default: + break; + } + + return result; +} + +/* + * Add a pending IRQ into lapic. + * Return 1 if successfully added and 0 if discarded. + */ +int vlapic_accept_irq(struct vlapic *vlapic, int delivery_mode, + int vector, int level, int trig_mode) +{ + int result = 1; + + switch (delivery_mode) { + case VLAPIC_DELIV_MODE_FIXED: + case VLAPIC_DELIV_MODE_LPRI: + /* FIXME add logic for vcpu on reset */ + if (!vlapic->vcpu || !vlapic_enabled(vlapic)) + return 0; + + if (test_and_set_bit(vector, &vlapic->irr[0])) { + printk("<vlapic_accept_irq>" + "level trig mode repeatedly for vector %d\n", vector); + result = 0; + } else { + if (level) { + printk("<vlapic_accept_irq> level trig mode for vector %d\n", vector); + set_bit(vector, &vlapic->tmr[0]); + } + } + evtchn_set_pending(vlapic->vcpu, iopacket_port(vlapic->domain)); + break; + + case VLAPIC_DELIV_MODE_RESERVED: + printk("Ignore deliver mode 3 in vlapic_accept_irq\n"); + break; + + case VLAPIC_DELIV_MODE_SMI: + case VLAPIC_DELIV_MODE_NMI: + /* Fixme */ + printk("TODO: for guest SMI/NMI\n"); + break; + + case VLAPIC_DELIV_MODE_INIT: + if (!level && trig_mode == 1) { //Deassert + printk("This vmx_vlapic is for P4, no work for De-assert init\n"); + } else { + /* FIXME How to check the situation after vcpu reset? */ + vlapic->init_sipi_sipi_state = VLAPIC_INIT_SIPI_SIPI_STATE_WAIT_SIPI; + if (vlapic->vcpu) { + vcpu_pause(vlapic->vcpu); + } + } + break; + + case VLAPIC_DELIV_MODE_STARTUP: + if (vlapic->init_sipi_sipi_state != VLAPIC_INIT_SIPI_SIPI_STATE_WAIT_SIPI) + break; + vlapic->init_sipi_sipi_state = VLAPIC_INIT_SIPI_SIPI_STATE_NORM; + if (!vlapic->vcpu) { + /* XXX Call vmx_bringup_ap here */ + result = 0; + }else{ + //vmx_vcpu_reset(vlapic->vcpu); + } + break; + + default: + printk("TODO: not support interrup type %x\n", delivery_mode); + domain_crash_synchronous(); + break; + } + + return result; +} +/* + This function is used by both ioapic and local APIC + The bitmap is for vcpu_id + */ +struct vlapic* apic_round_robin(struct domain *d, + uint8_t dest_mode, + uint8_t vector, + uint32_t bitmap) +{ + int next, old; + struct vlapic* target = NULL; + + if (dest_mode == 0) { //Physical mode + printk("<apic_round_robin> lowest priority for physical mode\n"); + return NULL; + } + + if (!bitmap) { + printk("<apic_round_robin> no bit on bitmap\n"); + return NULL; + } + + spin_lock(&d->arch.vmx_platform.round_robin_lock); + + old = next = d->arch.vmx_platform.round_info[vector]; + + next++; + if (next == MAX_VIRT_CPUS || !d->vcpu[next]) + next = 0; + + do { + /* the vcpu array is arranged according to vcpu_id */ + if (test_bit(next, &bitmap)) { + target = d->vcpu[next]->arch.arch_vmx.vlapic; + if (!vlapic_enabled(target)) { + printk("warning: targe round robin local apic disabled\n"); + /* XXX should we domain crash?? Or should we return NULL */ + } + break; + } + + next ++; + if (next == MAX_VIRT_CPUS || !d->vcpu[next]) + next = 0; + }while(next != old); + + d->arch.vmx_platform.round_info[vector] = next; + spin_unlock(&d->arch.vmx_platform.round_robin_lock); + return target; +} + +void +vlapic_EOI_set(struct vlapic *vlapic) +{ + int vector = vlapic_find_highest_isr(vlapic); + + /* Not every write EOI will has correpsoning ISR, + one example is when Kernel check timer on setup_IO_APIC */ + if (vector == -1) { + return ; + } + + vlapic_clear_isr(vlapic, vector); + vlapic_update_ppr(vlapic); +} + +int vlapic_check_vector(struct vlapic *vlapic, + unsigned char dm, int vector) +{ + if ((dm == VLAPIC_DELIV_MODE_FIXED) && (vector < 16)) { + vlapic->err_status |= 0x40; + vlapic_accept_irq(vlapic, VLAPIC_DELIV_MODE_FIXED, + vlapic_lvt_vector(vlapic, VLAPIC_LVT_ERROR), 0, 0); + printk("<vlapic_check_vector>: check fail\n"); + return 0; + } + return 1; +} + + +void vlapic_ipi(struct vlapic *vlapic) +{ + unsigned int dest = (vlapic->icr_high >> 24) & 0xff; + unsigned int short_hand = (vlapic->icr_low >> 18) & 3; + unsigned int trig_mode = (vlapic->icr_low >> 15) & 1; + unsigned int level = (vlapic->icr_low >> 14) & 1; + unsigned int dest_mode = (vlapic->icr_low >> 11) & 1; + unsigned int delivery_mode = (vlapic->icr_low >> 8) & 7; + unsigned int vector = (vlapic->icr_low & 0xff); + + struct vlapic *target; + struct vcpu *v = NULL; + int result = 0; + uint32_t lpr_map; + + VMX_DBG_LOG(DBG_LEVEL_VLAPIC, "vlapic_ipi: " + "icr_high %x icr_low %x " + "short_hand %x dest %x trig_mode %x level %x " + "dest_mode %x delivery_mode %x vector %x", + vlapic->icr_high, vlapic->icr_low, + short_hand, dest, trig_mode, level, dest_mode, + delivery_mode, vector); + + for_each_vcpu ( vlapic->domain, v ) { + target = VLAPIC(v); + if (vlapic_match_dest(target, vlapic, short_hand, + dest, dest_mode, delivery_mode)) { + if (delivery_mode == VLAPIC_DELIV_MODE_LPRI) { + set_bit(v->vcpu_id, &lpr_map); + }else + result = vlapic_accept_irq(target, delivery_mode, + vector, level, trig_mode); + } + } + + if (delivery_mode == VLAPIC_DELIV_MODE_LPRI) { + extern struct vlapic* + apic_round_robin(struct domain *d, + uint8_t dest_mode, uint8_t vector, uint32_t bitmap); + + v = vlapic->vcpu; + target = apic_round_robin(v->domain, dest_mode, vector, lpr_map); + + if (target) + vlapic_accept_irq(target, delivery_mode, + vector, level, trig_mode); + } +} + +void vlapic_begin_timer(struct vlapic *vlapic) +{ + s_time_t cur = NOW(), offset; + + offset = vlapic->timer_current * + (262144 / get_apic_bus_scale()) * vlapic->timer_divide_counter; + vlapic->vlapic_timer.expires = cur + offset; + + set_ac_timer(&(vlapic->vlapic_timer), vlapic->vlapic_timer.expires ); + + VMX_DBG_LOG(DBG_LEVEL_VLAPIC, "vlapic_begin_timer: " + "bus_scale %x now %08x%08x expire %08x%08x " + "offset %08x%08x current %x", + get_apic_bus_scale(), (uint32_t)(cur >> 32), (uint32_t)cur, + (uint32_t)(vlapic->vlapic_timer.expires >> 32), + (uint32_t) vlapic->vlapic_timer.expires, + (uint32_t)(offset >> 32), (uint32_t)offset, + vlapic->timer_current); +} + +void vlapic_read_aligned(struct vlapic *vlapic, unsigned int offset, + unsigned int len, unsigned int *result) +{ + if (len != 4) { + VMX_DBG_LOG(DBG_LEVEL_VLAPIC, + "local apic read with len=%d (should be 4)", len); + } + + *result = 0; + + switch (offset) { + case APIC_ID: + *result = (vlapic->id) << 24; + break; + + case APIC_LVR: + *result = vlapic->version; + break; + + case APIC_TASKPRI: + *result = vlapic->task_priority; + break; + + case APIC_ARBPRI: + printk("Access local APIC ARBPRI register which is for P6\n"); + break; + + case APIC_PROCPRI: + *result = vlapic->processor_priority; + break; + + case APIC_EOI: /* EOI is write only */ + break; + + case APIC_LDR: + *result = vlapic->logical_dest; + break; + + case APIC_DFR: + *result = vlapic->dest_format; + break; + + case APIC_SPIV: + *result = vlapic->spurious_vec; + break; + + case APIC_ISR: + case 0x110: + case 0x120: + case 0x130: + case 0x140: + case 0x150: + case 0x160: + case 0x170: + *result = vlapic->isr[(offset - APIC_ISR) >> 4]; + break; + + case APIC_TMR: + case 0x190: + case 0x1a0: + case 0x1b0: + case 0x1c0: + case 0x1d0: + case 0x1e0: + case 0x1f0: + *result = vlapic->tmr[(offset - APIC_TMR) >> 4]; + break; + + case APIC_IRR: + case 0x210: + case 0x220: + case 0x230: + case 0x240: + case 0x250: + case 0x260: + case 0x270: + *result = vlapic->irr[(offset - APIC_IRR) >> 4]; + break; + + case APIC_ESR: + if (vlapic->err_write_count) + *result = vlapic->err_status; + break; + + case APIC_ICR: + *result = vlapic->icr_low; + break; + + case APIC_ICR2: + *result = vlapic->icr_high; + break; + + case APIC_LVTT: /* LVT Timer Reg */ + case APIC_LVTTHMR: /* LVT Thermal Monitor */ + case APIC_LVTPC: /* LVT Performance Counter */ + case APIC_LVT0: /* LVT LINT0 Reg */ + case APIC_LVT1: /* LVT Lint1 Reg */ + case APIC_LVTERR: /* LVT Error Reg */ + *result = vlapic->lvt[(offset - APIC_LVTT) >> 4]; + break; + + case APIC_TMICT: + *result = vlapic->timer_initial; + break; + + case APIC_TMCCT: //Timer CCR + { + uint32_t counter; + s_time_t passed, cur = NOW(); + + if (cur <= vlapic->timer_current_update) { + passed = ~0x0LL - vlapic->timer_current_update + cur; + VMX_DBG_LOG(DBG_LEVEL_VLAPIC,"time elapsed"); + }else + passed = cur - vlapic->timer_current_update; + + counter = (passed * get_apic_bus_scale()) / (262144* vlapic->timer_divide_counter); + if (vlapic->timer_current > counter) + *result = vlapic->timer_current - counter; + else { + if (!vlapic_lvt_timer_period(vlapic)) + *result = 0; + //FIXME should we add interrupt here? + else + //*result = counter % vlapic->timer_initial; + *result = vlapic->timer_initial - (counter - vlapic->timer_current); + } + vlapic->timer_current = *result; + vlapic->timer_current_update = NOW(); + + VMX_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER, + "initial %x timer current %x " + "update %08x%08x cur %08x%08x offset %d", + vlapic->timer_initial, vlapic->timer_current, + (uint32_t)(vlapic->timer_current_update >> 32), + (uint32_t)vlapic->timer_current_update , + (uint32_t)(cur >> 32), (uint32_t)cur, counter); + } + break; + + case APIC_TDCR: + *result = vlapic->timer_divconf; + break; + + default: + printk("Read local APIC address %x not implemented\n",offset); + *result = 0; + break; + } +} + +unsigned long vlapic_read(struct vcpu *v, unsigned long address, + unsigned long len) +{ + unsigned int alignment; + unsigned int tmp; + unsigned long result; + struct vlapic *vlapic = VLAPIC(v); + unsigned int offset = address - vlapic->base_address; + + if ( len != 4) { + /* some bugs on kernel cause read this with byte*/ + printk("Local APIC read with len = %lx, should be 4 instead\n", len); + } + + alignment = offset & 0x3; + + vlapic_read_aligned(vlapic, offset & ~0x3, 4, &tmp); + switch (len) { + case 1: + result = *((unsigned char *)&tmp + alignment); + break; + + case 2: + result = *(unsigned short *)((unsigned char *)&tmp + alignment); + break; + + case 4: + result = *(unsigned int *)((unsigned char *)&tmp + alignment); + break; + + default: + printk("Local APIC read with len = %lx, should be 4 instead\n", len); + domain_crash_synchronous(); + break; + } + + VMX_DBG_LOG(DBG_LEVEL_VLAPIC, + "vlapic_read offset %x with length %lx and the result is %lx", + offset, len, result); + return result; +} + +unsigned long vlapic_write(struct vcpu *v, unsigned long address, + unsigned long len, unsigned long val) +{ + struct vlapic *vlapic = VLAPIC(v); + unsigned int offset = address - vlapic->base_address; + + if (offset != 0xb0) + VMX_DBG_LOG(DBG_LEVEL_VLAPIC, + "vlapic_write offset %x with length %lx source %lx", + offset, len, val); + + /* + * According to IA 32 Manual, all resgiters should be accessed with + * 32 bits alignment. + */ + if (len != 4) { + unsigned int tmp; + unsigned char alignment; + + /* Some kernel do will access with byte/word alignment*/ + printk("Notice: Local APIC write with len = %lx\n",len); + alignment = offset & 0x3; + tmp = vlapic_read(v, offset & (~0x3), 4); + switch (len) { + case 1: + /* XXX the saddr is a tmp variable from caller, so should be ok + But we should still change the following ref to val to + local variable later */ + val = (tmp & ~(0xff << alignment)) | + ((val & 0xff) << alignment); + break; + + case 2: + if (alignment != 0x0 && alignment != 0x2) { + printk("alignment error for vlapic with len == 2\n"); + domain_crash_synchronous(); + } + + val = (tmp & ~(0xffff << alignment)) | + ((val & 0xffff) << alignment); + break; + + case 3: + /* will it happen? */ + printk("vlapic_write with len = 3 !!!\n"); + domain_crash_synchronous(); + break; + + default: + printk("Local APIC write with len = %lx, should be 4 instead\n", len); + domain_crash_synchronous(); + break; + } + } + + offset &= 0xff0; + + switch (offset) { + case APIC_ID: /* Local APIC ID */ + vlapic->id = ((val) >> 24) & VAPIC_ID_MASK; + break; + + case APIC_TASKPRI: + vlapic->task_priority = val & 0xff; + vlapic_update_ppr(vlapic); + break; + + case APIC_EOI: + vlapic_EOI_set(vlapic); + break; + + case APIC_LDR: + vlapic->logical_dest = val & VAPIC_LDR_MASK; + break; + + case APIC_DFR: + vlapic->dest_format = val ; + break; + + case APIC_SPIV: + vlapic->spurious_vec = val & 0x1ff; + if (!(vlapic->spurious_vec & 0x100)) { + int i = 0; + for (i=0; i < VLAPIC_LVT_NUM; i++) + vlapic->lvt[i] |= 0x10000; + vlapic->status |= VLAPIC_SOFTWARE_DISABLE_MASK; + } + else + vlapic->status &= ~VLAPIC_SOFTWARE_DISABLE_MASK; + break; + + case APIC_ESR: + vlapic->err_write_count = !vlapic->err_write_count; + if (!vlapic->err_write_count) + vlapic->err_status = 0; + break; + + case APIC_ICR: + /* No delay here, so we always clear the pending bit*/ + vlapic->icr_low = val & ~(1 << 12); + vlapic_ipi(vlapic); + break; + + case APIC_ICR2: + vlapic->icr_high = val & 0xff000000; + break; + + case APIC_LVTT: // LVT Timer Reg + case APIC_LVTTHMR: // LVT Thermal Monitor + case APIC_LVTPC: // LVT Performance Counter + case APIC_LVT0: // LVT LINT0 Reg + case APIC_LVT1: // LVT Lint1 Reg + case APIC_LVTERR: // LVT Error Reg + { + int vt = (offset - APIC_LVTT) >> 4; + + vlapic->lvt[vt] = val & vlapic_lvt_mask[vt]; + if (vlapic->status & VLAPIC_SOFTWARE_DISABLE_MASK) + vlapic->lvt[vt] |= VLAPIC_LVT_BIT_MASK; + + /* On hardware, when write vector less than 0x20 will error */ + vlapic_check_vector(vlapic, vlapic_lvt_dm(vlapic->lvt[vt]), + vlapic_lvt_vector(vlapic, vt)); + + if (!vlapic->vcpu_id && (offset == APIC_LVT0)) { + if ((vlapic->lvt[VLAPIC_LVT_LINT0] & VLAPIC_LVT_BIT_DELIMOD) + == 0x700) { + if (!(vlapic->lvt[VLAPIC_LVT_LINT0] & VLAPIC_LVT_BIT_MASK)) { + set_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status); + }else + clear_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status); + } + else + clear_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status); + } + + } + break; + + case APIC_TMICT: + if (vlapic_timer_active(vlapic)) + rem_ac_timer(&(vlapic->vlapic_timer)); + + vlapic->timer_initial = val; + vlapic->timer_current = val; + vlapic->timer_current_update = NOW(); + + VMX_DBG_LOG(DBG_LEVEL_VLAPIC, + "timer_init %x timer_current %x timer_current_update %08x%08x", + vlapic->timer_initial, vlapic->timer_current, (uint32_t)(vlapic->timer_current_update>>32), (uint32_t)vlapic->timer_current_update); + vlapic_begin_timer(vlapic); + break; + + case APIC_TDCR: + { + //FIXME clean this code + unsigned char tmp1,tmp2; + tmp1 = (val & 0xf); + tmp2 = ((tmp1 & 0x3 )|((tmp1 & 0x8) >>1)) + 1; + vlapic->timer_divide_counter = 0x1<<tmp2; + + VMX_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER, + "timer divider is 0x%x", + vlapic->timer_divide_counter); + } + break; + + default: + printk("Local APIC Write to read-only register\n"); + break; + } + return 1; +} + +int vlapic_range(struct vcpu *v, unsigned long addr) +{ + struct vlapic *vlapic = VLAPIC(v); + + if (vlapic_global_enabled(vlapic) && + (addr >= vlapic->base_address) && + (addr <= (vlapic->base_address + VLOCAL_APIC_MEM_LENGTH))) + return 1; + + return 0; +} + +void vlapic_msr_set(struct vlapic *vlapic, uint64_t value) +{ + /* When apic disabled */ + if (!vlapic) + return; + + if (vlapic->vcpu_id) + value &= ~MSR_IA32_APICBASE_BSP; + + vlapic->apic_base_msr = value; + vlapic->base_address = vlapic_get_base_address(vlapic); + + if (!(value & 0x800)) + set_bit(_VLAPIC_GLOB_DISABLE, &vlapic->status ); + + VMX_DBG_LOG(DBG_LEVEL_VLAPIC, + "apic base msr = 0x%08x%08x,\nbase address = 0x%lx", + (uint32_t)(vlapic->apic_base_msr >> 32), + (uint32_t)vlapic->apic_base_msr, + vlapic->base_address); +} + +static inline int vlapic_get_init_id(struct vcpu *v) +{ + return v->vcpu_id; +} + +void vlapic_timer_fn(void *data) +{ + struct vlapic *vlapic; + + vlapic = data; + if (!vlapic_enabled(vlapic)) return; + + vlapic->timer_current_update = NOW(); + + if (vlapic_lvt_timer_enabled(vlapic)) { + if (!vlapic_irr_status(vlapic, + vlapic_lvt_vector(vlapic, VLAPIC_LVT_TIMER))) { + test_and_set_bit(vlapic_lvt_vector(vlapic, VLAPIC_LVT_TIMER), + &vlapic->irr[0]); + } + else + vlapic->intr_pending_count[vlapic_lvt_vector(vlapic, VLAPIC_LVT_TIMER)]++; + } + + vlapic->timer_current_update = NOW(); + if (vlapic_lvt_timer_period(vlapic)) { + s_time_t offset; + + vlapic->timer_current = vlapic->timer_initial; + offset = vlapic->timer_current * (262144/get_apic_bus_scale()) * vlapic->timer_divide_counter; + vlapic->vlapic_timer.expires = NOW() + offset; + set_ac_timer(&(vlapic->vlapic_timer), vlapic->vlapic_timer.expires); + }else { + vlapic->timer_current = 0; + } + + VMX_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER, + "vlapic_timer_fn: now: %08x%08x expire %08x%08x init %x current %x", + (uint32_t)(NOW() >> 32),(uint32_t)NOW(), + (uint32_t)(vlapic->vlapic_timer.expires >> 32), + (uint32_t)vlapic->vlapic_timer.expires, + vlapic->timer_initial,vlapic->timer_current); +} + +#if 0 +static int +vlapic_check_direct_intr(struct vcpu *v, int * mode) +{ + struct vlapic *vlapic = VLAPIC(v); + int type; + + type = __fls(vlapic->direct_intr.deliver_mode); + if (type == -1) + return -1; + + *mode = type; + return 0; +} +#endif + +int +vlapic_accept_pic_intr(struct vcpu *v) +{ + struct vlapic *vlapic = VLAPIC(v); + + return vlapic ? test_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status) : 1; +} + +int cpu_get_apic_interrupt(struct vcpu* v, int *mode) +{ + struct vlapic *vlapic = VLAPIC(v); + + if (vlapic && vlapic_enabled(vlapic)) { + int highest_irr = vlapic_find_highest_irr(vlapic); + + if (highest_irr != -1 && highest_irr >= vlapic->processor_priority) { + if (highest_irr < 0x10) { + vlapic->err_status |= 0x20; + /* XXX What will happen if this vector illegal stil */ + VMX_DBG_LOG(DBG_LEVEL_VLAPIC, + "vmx_intr_assist: illegal vector number %x err_status %x", + highest_irr, vlapic_lvt_vector(vlapic, VLAPIC_LVT_ERROR)); + + set_bit(vlapic_lvt_vector(vlapic, VLAPIC_LVT_ERROR), &vlapic->irr[0]); + highest_irr = vlapic_lvt_vector(vlapic, VLAPIC_LVT_ERROR); + } + + *mode = VLAPIC_DELIV_MODE_FIXED; + return highest_irr; + } + } + return -1; +} + +void vlapic_post_injection(struct vcpu *v, int vector, int deliver_mode) { + struct vlapic *vlapic = VLAPIC(v); + + if (!vlapic) + return; + + switch (deliver_mode) { + case VLAPIC_DELIV_MODE_FIXED: + case VLAPIC_DELIV_MODE_LPRI: + vlapic_set_isr(vlapic, vector); + vlapic_clear_irr(vlapic, vector); + vlapic_update_ppr(vlapic); + + if (vector == vlapic_lvt_vector(vlapic, VLAPIC_LVT_TIMER)) { + vlapic->intr_pending_count[vector]--; + if (vlapic->intr_pending_count[vector] > 0) + test_and_set_bit(vlapic_lvt_vector(vlapic, VLAPIC_LVT_TIMER), + &vlapic->irr[0]); + } + + break; + /*XXX deal with these later */ + + case VLAPIC_DELIV_MODE_RESERVED: + printk("Ignore deliver mode 3 in vlapic_post_injection\n"); + break; + + case VLAPIC_DELIV_MODE_SMI: + case VLAPIC_DELIV_MODE_NMI: + case VLAPIC_DELIV_MODE_INIT: + case VLAPIC_DELIV_MODE_STARTUP: + vlapic->direct_intr.deliver_mode &= ~(1 << deliver_mode); + break; + + default: + printk("<vlapic_post_injection> error deliver mode\n"); + break; + } +} + +static int vlapic_reset(struct vlapic *vlapic) +{ + struct vcpu *v = vlapic->vcpu; + int apic_id = v->vcpu_id, i; + + if (!v || !vlapic) + return 0; + + memset(vlapic, 0,sizeof(struct vlapic)); + + v->arch.arch_vmx.vlapic = vlapic; + + vlapic->domain = v->domain; + + vlapic->id = apic_id; + + vlapic->version = VLAPIC_VERSION; + + vlapic->apic_base_msr = VLAPIC_BASE_MSR_INIT_VALUE; + + if (apic_id == 0) + vlapic->apic_base_msr |= MSR_IA32_APICBASE_BSP; + vlapic->base_address = vlapic_get_base_address(vlapic); + + for (i = 0; i < VLAPIC_LVT_NUM; i++) + vlapic->lvt[i] = VLAPIC_LVT_BIT_MASK; + + vlapic->dest_format = 0xffffffffU; + + vlapic->spurious_vec = 0xff; + + + init_ac_timer(&vlapic->vlapic_timer, + vlapic_timer_fn, vlapic, v->processor); + +#ifdef VLAPIC_NO_BIOS + /* + * XXX According to mp sepcific, BIOS will enable LVT0/1, + * remove it after BIOS enabled + */ + if (!v->vcpu_id) { + vlapic->lvt[VLAPIC_LVT_LINT0] = 0x700; + vlapic->lvt[VLAPIC_LVT_LINT1] = 0x500; + set_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status); + } +#endif + + VMX_DBG_LOG(DBG_LEVEL_VLAPIC, "vlapic_reset: " + "vcpu=%p id=%d vlapic_apic_base_msr=%08x%08x " + "vlapic_base_address=%0lx", + v, vlapic->id, (uint32_t)(vlapic->apic_base_msr >> 32), + (uint32_t)vlapic->apic_base_msr, vlapic->base_address); + + return 1; +} + +int vlapic_init(struct vcpu *v) +{ + struct vlapic *vlapic = NULL; + + VMX_DBG_LOG(DBG_LEVEL_VLAPIC, "vlapic_init %d", v->vcpu_id); + + vlapic = xmalloc_bytes(sizeof(struct vlapic)); + + if (!vlapic) { + printk("malloc vlapic error for vcpu %x\n", v->vcpu_id); + return -ENOMEM; + } + + vlapic->vcpu = v; + + vlapic_reset(vlapic); + + return 0; +} + +#endif /* CONFIG_VMX */ diff -r f23b897930d1 -r cc23d4236b20 xen/include/asm-x86/vmx_vlapic.h --- /dev/null Thu Oct 27 17:22:45 2005 +++ b/xen/include/asm-x86/vmx_vlapic.h Fri Oct 28 08:48:46 2005 @@ -0,0 +1,245 @@ +/* + * vmx_vlapic.h: virtualize LAPIC definitions. + * Copyright (c) 2004, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * + */ + +#ifndef VMX_VLAPIC_H +#define VMX_VLAPIC_H + +#include <asm/msr.h> +#include <public/io/ioreq.h> + +#if defined(__i386__) || defined(__x86_64__) +static inline int __fls(uint32_t word) +{ + int bit; + + __asm__("bsrl %1,%0" + :"=r" (bit) + :"rm" (word)); + return word ? bit : -1; +} +#else +#define __fls(x) generic_fls(x) +static __inline__ int generic_fls(uint32_t x) +{ + int r = 31; + + if (!x) + return -1; + if (!(x & 0xffff0000u)) { + x <<= 16; + r -= 16; + } + if (!(x & 0xff000000u)) { + x <<= 8; + r -= 8; + } + if (!(x & 0xf0000000u)) { + x <<= 4; + r -= 4; + } + if (!(x & 0xc0000000u)) { + x <<= 2; + r -= 2; + } + if (!(x & 0x80000000u)) { + x <<= 1; + r -= 1; + } + return r; +} +#endif + +static __inline__ int find_highest_bit(uint32_t *data, int length) +{ + while(length && !data[--length]); + return __fls(data[length]) + 32 * length; +} + +#define VLAPIC(v) (v->arch.arch_vmx.vlapic) + +#define VAPIC_ID_MASK 0xff +#define VAPIC_LDR_MASK (VAPIC_ID_MASK << 24) +#define VLAPIC_VERSION 0x00050014 + +#define VLAPIC_BASE_MSR_MASK 0x00000000fffff900ULL +#define VLAPIC_BASE_MSR_INIT_BASE_ADDR 0xfee00000U +#define VLAPIC_BASE_MSR_BASE_ADDR_MASK 0xfffff000U +#define VLAPIC_BASE_MSR_INIT_VALUE (VLAPIC_BASE_MSR_INIT_BASE_ADDR | \ + MSR_IA32_APICBASE_ENABLE) +#define VLOCAL_APIC_MEM_LENGTH (1 << 12) + +#define VLAPIC_LVT_TIMER 0 +#define VLAPIC_LVT_THERMAL 1 +#define VLAPIC_LVT_PERFORM 2 +#define VLAPIC_LVT_LINT0 3 +#define VLAPIC_LVT_LINT1 4 +#define VLAPIC_LVT_ERROR 5 +#define VLAPIC_LVT_NUM 6 + +#define VLAPIC_LVT_BIT_MASK (1 << 16) +#define VLAPIC_LVT_BIT_VECTOR 0xff +#define VLAPIC_LVT_BIT_DELIMOD (0x7 << 8) +#define VLAPIC_LVT_BIT_DELISTATUS (1 << 12) +#define VLAPIC_LVT_BIT_POLARITY (1 << 13) +#define VLAPIC_LVT_BIT_IRR (1 << 14) +#define VLAPIC_LVT_BIT_TRIG (1 << 15) +#define VLAPIC_LVT_TIMERMODE (1 << 17) + +#define VLAPIC_DELIV_MODE_FIXED 0x0 +#define VLAPIC_DELIV_MODE_LPRI 0x1 +#define VLAPIC_DELIV_MODE_SMI 0x2 +#define VLAPIC_DELIV_MODE_RESERVED 0x3 +#define VLAPIC_DELIV_MODE_NMI 0x4 +#define VLAPIC_DELIV_MODE_INIT 0x5 +#define VLAPIC_DELIV_MODE_STARTUP 0x6 +#define VLAPIC_DELIV_MODE_EXT 0x7 + + + +#define VLAPIC_NO_SHORTHAND 0x0 +#define VLAPIC_SHORTHAND_SELF 0x1 +#define VLAPIC_SHORTHAND_INCLUDE_SELF 0x2 +#define VLAPIC_SHORTHAND_EXCLUDE_SELF 0x3 + +#define vlapic_lvt_timer_enabled(vlapic) \ + (!(vlapic->lvt[VLAPIC_LVT_TIMER] & VLAPIC_LVT_BIT_MASK)) + +#define vlapic_lvt_vector(vlapic, type) \ + (vlapic->lvt[type] & VLAPIC_LVT_BIT_VECTOR) + +#define vlapic_lvt_dm(value) ((value >> 8) && 7) +#define vlapic_lvt_timer_period(vlapic) \ + (vlapic->lvt[VLAPIC_LVT_TIMER] & VLAPIC_LVT_TIMERMODE) + +#define vlapic_isr_status(vlapic,vector) \ + test_bit(vector, &vlapic->isr[0]) + +#define vlapic_irr_status(vlapic,vector) \ + test_bit(vector, &vlapic->irr[0]) + +#define vlapic_set_isr(vlapic,vector) \ + test_and_set_bit(vector, &vlapic->isr[0]) + +#define vlapic_set_irr(vlapic,vector) \ + test_and_set_bit(vector, &vlapic->irr[0]) + +#define vlapic_clear_irr(vlapic,vector) \ + clear_bit(vector, &vlapic->irr[0]) +#define vlapic_clear_isr(vlapic,vector) \ + clear_bit(vector, &vlapic->isr[0]) + +#define vlapic_enabled(vlapic) \ + (!(vlapic->status & \ + (VLAPIC_GLOB_DISABLE_MASK | VLAPIC_SOFTWARE_DISABLE_MASK))) + +#define vlapic_global_enabled(vlapic) \ + !(test_bit(_VLAPIC_GLOB_DISABLE, &(vlapic)->status)) + +typedef struct direct_intr_info { + int deliver_mode; + int source[6]; +} direct_intr_info_t; + +#define VLAPIC_INIT_SIPI_SIPI_STATE_NORM 0 +#define VLAPIC_INIT_SIPI_SIPI_STATE_WAIT_SIPI 1 + +struct vlapic +{ + //FIXME check what would be 64 bit on EM64T + uint32_t version; +#define _VLAPIC_GLOB_DISABLE 0x0 +#define VLAPIC_GLOB_DISABLE_MASK 0x1 +#define VLAPIC_SOFTWARE_DISABLE_MASK 0x2 +#define _VLAPIC_BSP_ACCEPT_PIC 0x3 + uint32_t status; + uint32_t id; + uint32_t vcpu_id; + unsigned long base_address; + uint32_t isr[8]; + uint32_t irr[INTR_LEN_32]; + uint32_t tmr[INTR_LEN_32]; + uint32_t task_priority; + uint32_t processor_priority; + uint32_t logical_dest; + uint32_t dest_format; + uint32_t spurious_vec; + uint32_t lvt[6]; + uint32_t timer_initial; + uint32_t timer_current; + uint32_t timer_divconf; + uint32_t timer_divide_counter; + struct ac_timer vlapic_timer; + int intr_pending_count[MAX_VECTOR]; + s_time_t timer_current_update; + uint32_t icr_high; + uint32_t icr_low; + direct_intr_info_t direct_intr; + uint32_t err_status; + unsigned long init_ticks; + uint32_t err_write_count; + uint64_t apic_base_msr; + uint32_t init_sipi_sipi_state; + struct vcpu *vcpu; + struct domain *domain; +}; + +static inline int vlapic_timer_active(struct vlapic *vlapic) +{ + return active_ac_timer(&(vlapic->vlapic_timer)); +} + +int vlapic_find_highest_irr(struct vlapic *vlapic); + +int vlapic_find_highest_isr(struct vlapic *vlapic); + +static uint32_t inline vlapic_get_base_address(struct vlapic *vlapic) +{ + return (vlapic->apic_base_msr & VLAPIC_BASE_MSR_BASE_ADDR_MASK); +} + +void vlapic_post_injection(struct vcpu* v, int vector, int deliver_mode); + +int cpu_get_apic_interrupt(struct vcpu* v, int *mode); + +extern uint32_t vlapic_update_ppr(struct vlapic *vlapic); + +int vlapic_update(struct vcpu *v); + +extern int vlapic_init(struct vcpu *vc); + +extern void vlapic_msr_set(struct vlapic *vlapic, uint64_t value); + +int vlapic_range(struct vcpu *v, unsigned long addr); + +unsigned long vlapic_write(struct vcpu *v, unsigned long address, + unsigned long len, unsigned long val); + +unsigned long vlapic_read(struct vcpu *v, unsigned long address, + unsigned long len); + +int vlapic_accept_pic_intr(struct vcpu *v); + +struct vlapic* apic_round_robin(struct domain *d, + uint8_t dest_mode, + uint8_t vector, + uint32_t bitmap); + +int vmx_apic_support(struct domain *d); + +#endif /* VMX_VLAPIC_H */ _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |