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@intel.com>
Signed-off-by: Li Xin <xin.b.li@intel.com>
Signed-off-by: Eddie Dong <eddie.dong@intel.com>
Signed-off-by: Jun Nakajima <jun.nakajima@intel.com>
This commit is contained in:
kaf24@firebug.cl.cam.ac.uk committed 2005-10-28 09:48:46 +01:00
1 parent a3cdca7914
commit 7429bfd50d
18 files changed
+1522 -116

No files matched your search

+6 -4
View File
@@ -279,6 +279,7 @@ static int setup_guest(int xc_handle,
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 @@ static int setup_guest(int xc_handle,
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 xc_vmx_build(int xc_handle,
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 @@ int xc_vmx_build(int xc_handle,
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;
+1
View File
@@ -56,6 +56,7 @@ int xc_vmx_build(int xc_handle,
int memsize,
const char *image_name,
unsigned int control_evtchn,
unsigned int lapic,
unsigned int vcpus,
unsigned int store_evtchn,
unsigned long *store_mfn);
+5 -4
View File
@@ -438,19 +438,20 @@ static PyObject *pyxc_vmx_build(PyObject *self,
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 };
"memsize", "image", "lapic", "vcpus", NULL };
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiiisi", kwd_list,
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);
+6
View File
@@ -203,6 +203,10 @@ class VmxImageHandler(ImageHandler):
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 @@ class VmxImageHandler(ImageHandler):
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 @@ class VmxImageHandler(ImageHandler):
control_evtchn = self.device_channel,
store_evtchn = store_evtchn,
memsize = self.vm.getMemoryTarget() / 1024,
lapic = self.lapic,
vcpus = self.vm.getVCpuCount())
+7 -7
View File
@@ -158,6 +158,10 @@ gopts.var('cpu', val='CPU',
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.")
@@ -316,10 +320,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='',
use="Path to device model program.")
@@ -542,9 +542,9 @@ def configure_vfr(opts, config, vals):
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]])
+4
View File
@@ -815,6 +815,10 @@ int __init calibrate_APIC_clock(void)
return result;
}
unsigned int get_apic_bus_scale(void)
{
return bus_scale;
}
static unsigned int calibration_result;
+11 -4
View File
@@ -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 @@ void do_pic_irqs (struct vmx_virpic *s, uint16_t irqs)
{
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 cpu_get_pic_interrupt(struct vcpu *v, int *type)
{
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;
+24 -1
View File
@@ -65,6 +65,11 @@ void vmx_final_setup_guest(struct vcpu *v)
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 @@ void vmx_relinquish_resources(struct vcpu *v)
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 @@ static int vmx_do_page_fault(unsigned long va, struct cpu_user_regs *regs)
/* 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 @@ static void vmx_vmexit_do_cpuid(unsigned long input, struct cpu_user_regs *regs)
{
unsigned int eax, ebx, ecx, edx;
unsigned long eip;
struct vcpu *v = current;
__vmread(GUEST_RIP, &eip);
@@ -500,6 +512,9 @@ static void vmx_vmexit_do_cpuid(unsigned long input, struct cpu_user_regs *regs)
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 int vmx_cr_access(unsigned long exit_qualification, struct cpu_user_regs
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 @@ static inline void vmx_do_msr_read(struct cpu_user_regs *regs)
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_read(struct cpu_user_regs *regs)
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,
@@ -1491,6 +1511,9 @@ static inline void vmx_do_msr_write(struct cpu_user_regs *regs)
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);
break;
+118
View File
@@ -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>
@@ -32,6 +33,123 @@
#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
* return value: 0 --not handled; 1 --handled
+47 -71
View File
@@ -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 @@ void vmx_wait_io()
} 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 @@ interrupt_post_injection(struct vcpu * v, int vector, int type)
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 @@ void vmx_pic_assist(struct vcpu *v)
}
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 @@ asmlinkage void vmx_intr_assist(void)
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 @@ asmlinkage void vmx_intr_assist(void)
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:
+997
View File
@@ -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 */
+7
View File
@@ -252,6 +252,10 @@ static void vmx_setup_platform(struct domain* d)
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)
@@ -313,6 +317,9 @@ static void vmx_do_launch(struct vcpu *v)
vmx_stts();
if(vmx_apic_support(v->domain))
vlapic_init(v);
vmx_set_host_env(v);
error |= __vmwrite(GUEST_LDTR_SELECTOR, 0);
+21 -11
View File
@@ -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 vmx_io_handler {
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 @@ static inline int vmx_portio_intercept(ioreq_t *p)
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 @@ static inline int register_portio_handler(unsigned long addr,
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 */
+3
View File
@@ -80,10 +80,13 @@ struct instruction {
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;
};
+245
View File
@@ -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 */
+12 -7
View File
@@ -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 arch_vmx_struct {
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 @@ enum vmcs_field {
#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
+7 -6
View File
@@ -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 @@ typedef struct {
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;
+1 -1
View File
@@ -76,7 +76,7 @@ void pic_update_irq(struct vmx_virpic *s);
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);
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.