mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 02:30:03 +01:00
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:
1 parent
a3cdca7914
commit
7429bfd50d
18 files changed
+1522
-116
No files matched your search
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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())
|
||||
|
||||
|
||||
|
||||
@@ -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]])
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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:
|
||||
|
||||
@@ -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 */
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||