# HG changeset patch
# User kaf24@xxxxxxxxxxxxxxxxxxxx
# Node ID 2d5b92e7c79a714640397b6c7d797a56aa230f8b
# Parent 8eaaa622db81393ef0eae497090c34c04adf4212
This is a follow up of PIC device model by Xiaofeng and me to move to
hypervisor using virtual weired interrupt line. With this patch the
performance of CPU2K improves 7%, kernel kuild improves 14% and
cyclesoak improves 12%. It is quite amazing!
Signed-off-by: Xiaofeng Ling <xiaofeng.ling@xxxxxxxxx>
Signed-off-by: Eddie Dong <eddie.dong@xxxxxxxxx>
diff -r 8eaaa622db81 -r 2d5b92e7c79a tools/ioemu/hw/i8254.c
--- a/tools/ioemu/hw/i8254.c Fri Oct 21 17:19:38 2005
+++ b/tools/ioemu/hw/i8254.c Fri Oct 21 17:29:26 2005
@@ -222,9 +222,7 @@
int irq, i;
PITChannelState *s;
- /* Assumes PIT is wired to IRQ0 and -1 is uninitialized irq base */
- if ((irq = pic_irq2vec(0)) == -1)
- return;
+ irq = 0;
for(i = 0; i < 3; i++) {
if (pit_state.channels[i].vmx_channel)
diff -r 8eaaa622db81 -r 2d5b92e7c79a tools/ioemu/target-i386-dm/Makefile
--- a/tools/ioemu/target-i386-dm/Makefile Fri Oct 21 17:19:38 2005
+++ b/tools/ioemu/target-i386-dm/Makefile Fri Oct 21 17:29:26 2005
@@ -271,7 +271,7 @@
# Hardware support
VL_OBJS+= ide.o ne2000.o pckbd.o vga.o dma.o
-VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o port-e9.o
+VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259_stub.o i8254.o pc.o port-e9.o
VL_OBJS+= cirrus_vga.o pcnet.o
ifeq ($(TARGET_ARCH), ppc)
diff -r 8eaaa622db81 -r 2d5b92e7c79a tools/ioemu/target-i386-dm/helper2.c
--- a/tools/ioemu/target-i386-dm/helper2.c Fri Oct 21 17:19:38 2005
+++ b/tools/ioemu/target-i386-dm/helper2.c Fri Oct 21 17:29:26 2005
@@ -404,20 +404,6 @@
}
void
-do_interrupt(CPUState *env, int vector)
-{
- unsigned long *intr;
-
- // Send a message on the event channel. Add the vector to the shared mem
- // page.
- intr = (unsigned long *) &(shared_page->sp_global.pic_intr[0]);
- atomic_set_bit(vector, intr);
- if (loglevel & CPU_LOG_INT)
- fprintf(logfile, "injecting vector: %x\n", vector);
- env->send_event = 1;
-}
-
-void
destroy_vmx_domain(void)
{
extern FILE* logfile;
@@ -429,7 +415,6 @@
int main_loop(void)
{
- int vector;
fd_set rfds;
struct timeval tv;
extern CPUState *global_env;
@@ -476,11 +461,6 @@
ioapic_update_EOI();
#endif
cpu_timer_handler(env);
- if (env->interrupt_request & CPU_INTERRUPT_HARD) {
- env->interrupt_request &= ~CPU_INTERRUPT_HARD;
- vector = cpu_get_pic_interrupt(env);
- do_interrupt(env, vector);
- }
#ifdef APIC_SUPPORT
if (ioapic_has_intr())
do_ioapic();
diff -r 8eaaa622db81 -r 2d5b92e7c79a xen/arch/x86/Makefile
--- a/xen/arch/x86/Makefile Fri Oct 21 17:19:38 2005
+++ b/xen/arch/x86/Makefile Fri Oct 21 17:29:26 2005
@@ -4,6 +4,7 @@
OBJS += $(patsubst %.S,%.o,$(wildcard $(TARGET_SUBARCH)/*.S))
OBJS += $(patsubst %.c,%.o,$(wildcard $(TARGET_SUBARCH)/*.c))
OBJS += $(patsubst %.c,%.o,$(wildcard acpi/*.c))
+OBJS += $(patsubst %.c,%.o,$(wildcard dm/*.c))
OBJS += $(patsubst %.c,%.o,$(wildcard mtrr/*.c))
OBJS += $(patsubst %.c,%.o,$(wildcard genapic/*.c))
OBJS += $(patsubst %.c,%.o,$(wildcard cpu/*.c))
@@ -66,6 +67,7 @@
rm -f x86_64/*.o x86_64/*~ x86_64/core
rm -f mtrr/*.o mtrr/*~ mtrr/core
rm -f acpi/*.o acpi/*~ acpi/core
+ rm -f dm/*.o dm/*~ dm/core
rm -f genapic/*.o genapic/*~ genapic/core
rm -f cpu/*.o cpu/*~ cpu/core
diff -r 8eaaa622db81 -r 2d5b92e7c79a xen/arch/x86/domain.c
--- a/xen/arch/x86/domain.c Fri Oct 21 17:19:38 2005
+++ b/xen/arch/x86/domain.c Fri Oct 21 17:29:26 2005
@@ -39,7 +39,6 @@
#include <asm/msr.h>
#include <asm/physdev.h>
#include <xen/kernel.h>
-#include <public/io/ioreq.h>
#include <xen/multicall.h>
/* opt_noreboot: If true, machine will need manual reset on error. */
diff -r 8eaaa622db81 -r 2d5b92e7c79a xen/arch/x86/vmx.c
--- a/xen/arch/x86/vmx.c Fri Oct 21 17:19:38 2005
+++ b/xen/arch/x86/vmx.c Fri Oct 21 17:29:26 2005
@@ -647,8 +647,8 @@
p->u.data = value;
if (vmx_portio_intercept(p)) {
- /* no blocking & no evtchn notification */
- clear_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags);
+ p->state = STATE_IORESP_READY;
+ vmx_io_assist(v);
return;
}
diff -r 8eaaa622db81 -r 2d5b92e7c79a xen/arch/x86/vmx_intercept.c
--- a/xen/arch/x86/vmx_intercept.c Fri Oct 21 17:19:38 2005
+++ b/xen/arch/x86/vmx_intercept.c Fri Oct 21 17:29:26 2005
@@ -209,8 +209,7 @@
missed_ticks = (NOW() - vpit->scheduled)/(s_time_t) vpit->period;
/* Set the pending intr bit, and send evtchn notification to myself. */
- if (test_and_set_bit(vpit->vector, vpit->intr_bitmap))
- vpit->pending_intr_nr++; /* already set, then count the pending intr */
+ vpit->pending_intr_nr++; /* already set, then count the pending intr */
evtchn_set_pending(vpit->v, iopacket_port(vpit->v->domain));
/* pick up missed timer tick */
@@ -230,11 +229,8 @@
{
vcpu_iodata_t *vio = get_vio(v->domain, v->vcpu_id);
ioreq_t *p = &vio->vp_ioreq;
- shared_iopage_t *sp = get_sp(v->domain);
- u64 *intr = &(sp->sp_global.pic_intr[0]);
struct vmx_virpit *vpit = &(v->domain->arch.vmx_platform.vmx_pit);
int rw_mode, reinit = 0;
- int oldvec = 0;
/* load init count*/
if (p->state == STATE_IORESP_HOOK) {
@@ -243,7 +239,7 @@
VMX_DBG_LOG(DBG_LEVEL_1, "VMX_PIT: guest reset PIT with channel
%lx!\n", (unsigned long) ((p->u.data >> 24) & 0x3) );
rem_ac_timer(&(vpit->pit_timer));
reinit = 1;
- oldvec = vpit->vector;
+
}
else
init_ac_timer(&vpit->pit_timer, pit_timer_fn, vpit, v->processor);
@@ -257,12 +253,6 @@
printk("VMX_PIT: guest programmed too small an init_val: %x\n",
vpit->init_val);
vpit->period = 1000000;
- }
- vpit->vector = ((p->u.data >> 16) & 0xFF);
-
- if( reinit && oldvec != vpit->vector){
- clear_bit(oldvec, intr);
- vpit->pending_intr_nr = 0;
}
vpit->channel = ((p->u.data >> 24) & 0x3);
@@ -287,7 +277,6 @@
break;
}
- vpit->intr_bitmap = intr;
vpit->v = v;
vpit->scheduled = NOW() + vpit->period;
@@ -297,8 +286,9 @@
p->state = STATE_IORESP_READY;
/* register handler to intercept the PIT io when vm_exit */
- if (!reinit)
+ if (!reinit) {
register_portio_handler(0x40, 4, intercept_pit_io);
+ }
}
}
#endif /* CONFIG_VMX */
diff -r 8eaaa622db81 -r 2d5b92e7c79a xen/arch/x86/vmx_io.c
--- a/xen/arch/x86/vmx_io.c Fri Oct 21 17:19:38 2005
+++ b/xen/arch/x86/vmx_io.c Fri Oct 21 17:29:26 2005
@@ -37,6 +37,7 @@
#include <asm/shadow.h>
#include <public/io/ioreq.h>
+#include <public/io/vmx_vpic.h>
#include <public/io/vmx_vlapic.h>
#ifdef CONFIG_VMX
@@ -794,57 +795,6 @@
}
#define BSP_CPU(v) (!(v->vcpu_id))
-static inline void clear_extint(struct vcpu *v)
-{
- global_iodata_t *spg;
- int i;
- spg = &get_sp(v->domain)->sp_global;
-
- for(i = 0; i < INTR_LEN; i++)
- spg->pic_intr[i] = 0;
-}
-
-static inline void clear_highest_bit(struct vcpu *v, int vector)
-{
- global_iodata_t *spg;
-
- spg = &get_sp(v->domain)->sp_global;
-
- clear_bit(vector, &spg->pic_intr[0]);
-}
-
-static inline int find_highest_pic_irq(struct vcpu *v)
-{
- u64 intr[INTR_LEN];
- global_iodata_t *spg;
- int i;
-
- if(!BSP_CPU(v))
- return -1;
-
- spg = &get_sp(v->domain)->sp_global;
-
- for(i = 0; i < INTR_LEN; i++){
- intr[i] = spg->pic_intr[i] & ~spg->pic_mask[i];
- }
-
- return find_highest_irq((u32 *)&intr[0]);
-}
-
-/*
- * Return 0-255 for pending irq.
- * -1 when no pending.
- */
-static inline int find_highest_pending_irq(struct vcpu *v, int *type)
-{
- int result = -1;
- if ((result = find_highest_pic_irq(v)) != -1){
- *type = VLAPIC_DELIV_MODE_EXT;
- return result;
- }
- return result;
-}
-
static inline void
interrupt_post_injection(struct vcpu * v, int vector, int type)
{
@@ -853,17 +803,17 @@
switch(type)
{
case VLAPIC_DELIV_MODE_EXT:
- if (vpit->pending_intr_nr && vector == vpit->vector)
- vpit->pending_intr_nr--;
- else
- clear_highest_bit(v, vector);
-
- if (vector == vpit->vector && !vpit->first_injected){
- vpit->first_injected = 1;
- vpit->pending_intr_nr = 0;
- }
- if (vector == vpit->vector)
+ 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();
+
+ }
break;
default:
@@ -893,6 +843,38 @@
static inline int irq_masked(unsigned long eflags)
{
return ((eflags & X86_EFLAGS_IF) == 0);
+}
+
+void pic_irq_request(int *interrupt_request, int level)
+{
+ if (level)
+ *interrupt_request = 1;
+ else
+ *interrupt_request = 0;
+}
+
+void vmx_pic_assist(struct vcpu *v)
+{
+ global_iodata_t *spg;
+ u16 *virq_line, irqs;
+ struct vmx_virpic *pic = &v->domain->arch.vmx_platform.vmx_pic;
+
+ spg = &get_sp(v->domain)->sp_global;
+ virq_line = &spg->pic_clear_irr;
+ if ( *virq_line ) {
+ do {
+ irqs = *(volatile u16*)virq_line;
+ } while ( (u16)cmpxchg(virq_line,irqs, 0) != irqs );
+ do_pic_irqs_clear(pic, irqs);
+ }
+ virq_line = &spg->pic_irr;
+ if ( *virq_line ) {
+ do {
+ irqs = *(volatile u16*)virq_line;
+ } while ( (u16)cmpxchg(virq_line,irqs, 0) != irqs );
+ do_pic_irqs(pic, irqs);
+ }
+
}
asmlinkage void vmx_intr_assist(void)
@@ -901,11 +883,18 @@
int highest_vector;
unsigned long intr_fields, eflags, interruptibility, cpu_exec_control;
struct vcpu *v = current;
-
- highest_vector = find_highest_pending_irq(v, &intr_type);
+ struct virtual_platform_def *plat=&v->domain->arch.vmx_platform;
+ struct vmx_virpit *vpit = &plat->vmx_pit;
+ struct vmx_virpic *pic= &plat->vmx_pic;
+
+ vmx_pic_assist(v);
__vmread_vcpu(v, CPU_BASED_VM_EXEC_CONTROL, &cpu_exec_control);
-
- if (highest_vector == -1) {
+ if ( vpit->pending_intr_nr ) {
+ pic_set_irq(pic, 0, 0);
+ pic_set_irq(pic, 0, 1);
+ }
+
+ if ( !plat->interrupt_request ) {
disable_irq_window(cpu_exec_control);
return;
}
@@ -922,22 +911,20 @@
if (interruptibility) {
enable_irq_window(cpu_exec_control);
- VMX_DBG_LOG(DBG_LEVEL_1, "guesting pending: %x, interruptibility: %lx",
- highest_vector, interruptibility);
+ VMX_DBG_LOG(DBG_LEVEL_1, "interruptibility: %lx",interruptibility);
return;
}
__vmread(GUEST_RFLAGS, &eflags);
+ if (irq_masked(eflags)) {
+ enable_irq_window(cpu_exec_control);
+ return;
+ }
+ plat->interrupt_request = 0;
+ highest_vector = cpu_get_pic_interrupt(v, &intr_type);
switch (intr_type) {
case VLAPIC_DELIV_MODE_EXT:
- if (irq_masked(eflags)) {
- enable_irq_window(cpu_exec_control);
- VMX_DBG_LOG(DBG_LEVEL_1, "guesting pending: %x, eflags: %lx",
- highest_vector, eflags);
- return;
- }
-
vmx_inject_extint(v, highest_vector, VMX_INVALID_ERROR_CODE);
TRACE_3D(TRC_VMX_INT, v->domain->domain_id, highest_vector, 0);
break;
diff -r 8eaaa622db81 -r 2d5b92e7c79a xen/arch/x86/vmx_vmcs.c
--- a/xen/arch/x86/vmx_vmcs.c Fri Oct 21 17:19:38 2005
+++ b/xen/arch/x86/vmx_vmcs.c Fri Oct 21 17:29:26 2005
@@ -210,8 +210,14 @@
static void vmx_setup_platform(struct vcpu *v)
{
- if (v->vcpu_id == 0)
+ struct virtual_platform_def *platform;
+ if (v->vcpu_id == 0) {
get_io_shared_page(v);
+ platform = &v->domain->arch.vmx_platform;
+ pic_init(&platform->vmx_pic, pic_irq_request,
+ &platform->interrupt_request);
+ register_pic_io_hook();
+ }
}
static void vmx_set_host_env(struct vcpu *v)
@@ -275,7 +281,8 @@
page = (struct pfn_info *) alloc_domheap_page(NULL);
pfn = (unsigned long) (page - frame_table);
- vmx_setup_platform(v);
+ if ( v == v->domain->vcpu[0] )
+ vmx_setup_platform(v);
vmx_set_host_env(v);
diff -r 8eaaa622db81 -r 2d5b92e7c79a xen/include/asm-x86/vmx.h
--- a/xen/include/asm-x86/vmx.h Fri Oct 21 17:19:38 2005
+++ b/xen/include/asm-x86/vmx.h Fri Oct 21 17:29:26 2005
@@ -34,6 +34,7 @@
extern void vmx_asm_do_resume(void);
extern void vmx_asm_do_launch(void);
extern void vmx_intr_assist(void);
+extern void pic_irq_request(int *interrupt_request, int level);
extern void arch_vmx_do_launch(struct vcpu *);
extern void arch_vmx_do_resume(struct vcpu *);
diff -r 8eaaa622db81 -r 2d5b92e7c79a xen/include/asm-x86/vmx_intercept.h
--- a/xen/include/asm-x86/vmx_intercept.h Fri Oct 21 17:19:38 2005
+++ b/xen/include/asm-x86/vmx_intercept.h Fri Oct 21 17:29:26 2005
@@ -8,7 +8,7 @@
#include <xen/errno.h>
#include <public/io/ioreq.h>
-#define MAX_IO_HANDLER 4
+#define MAX_IO_HANDLER 8
#define VMX_PORTIO 0
#define VMX_MMIO 1
diff -r 8eaaa622db81 -r 2d5b92e7c79a xen/include/asm-x86/vmx_platform.h
--- a/xen/include/asm-x86/vmx_platform.h Fri Oct 21 17:19:38 2005
+++ b/xen/include/asm-x86/vmx_platform.h Fri Oct 21 17:29:26 2005
@@ -24,6 +24,7 @@
#include <asm/e820.h>
#include <asm/vmx_virpit.h>
#include <asm/vmx_intercept.h>
+#include <public/io/vmx_vpic.h>
#define MAX_OPERAND_NUM 2
@@ -80,6 +81,8 @@
unsigned long shared_page_va;
struct vmx_virpit vmx_pit;
struct vmx_io_handler vmx_io_handler;
+ struct vmx_virpic vmx_pic;
+ int interrupt_request;
};
extern void handle_mmio(unsigned long, unsigned long);
diff -r 8eaaa622db81 -r 2d5b92e7c79a xen/include/asm-x86/vmx_virpit.h
--- a/xen/include/asm-x86/vmx_virpit.h Fri Oct 21 17:19:38 2005
+++ b/xen/include/asm-x86/vmx_virpit.h Fri Oct 21 17:29:26 2005
@@ -18,13 +18,11 @@
struct vmx_virpit {
/* for simulation of counter 0 in mode 2*/
- int vector; /* the pit irq vector */
- unsigned int period; /* the frequency. e.g. 10ms*/
+ u32 period; /* pit frequency in ns */
s_time_t scheduled; /* scheduled timer interrupt */
unsigned int channel; /* the pit channel, counter 0~2 */
- u64 *intr_bitmap;
unsigned int pending_intr_nr; /* the couner for pending timer interrupts */
- unsigned long long inject_point; /* the time inject virt intr */
+ u64 inject_point; /* the time inject virt intr */
struct ac_timer pit_timer; /* periodic timer for mode 2*/
int first_injected; /* flag to prevent shadow window */
diff -r 8eaaa622db81 -r 2d5b92e7c79a xen/include/public/io/ioreq.h
--- a/xen/include/public/io/ioreq.h Fri Oct 21 17:19:38 2005
+++ b/xen/include/public/io/ioreq.h Fri Oct 21 17:29:26 2005
@@ -60,8 +60,10 @@
#define INTR_LEN (MAX_VECTOR/(BITS_PER_BYTE * sizeof(uint64_t)))
typedef struct {
- uint64_t pic_intr[INTR_LEN];
- uint64_t pic_mask[INTR_LEN];
+ uint16_t pic_elcr;
+ uint16_t pic_irr;
+ uint16_t pic_last_irr;
+ uint16_t pic_clear_irr;
int eport; /* Event channel port */
} global_iodata_t;
diff -r 8eaaa622db81 -r 2d5b92e7c79a tools/ioemu/hw/i8259_stub.c
--- /dev/null Fri Oct 21 17:19:38 2005
+++ b/tools/ioemu/hw/i8259_stub.c Fri Oct 21 17:29:26 2005
@@ -0,0 +1,96 @@
+/* Xen 8259 stub for interrupt controller emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2005 Intel corperation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "xenctrl.h"
+#include <xen/io/ioreq.h>
+#include <stdio.h>
+#include "cpu.h"
+#include "cpu-all.h"
+
+static __inline__ void atomic_set_bit(long nr, volatile void *addr)
+{
+ __asm__ __volatile__(
+ "lock ; bts %1,%0"
+ :"=m" (*(volatile long *)addr)
+ :"dIr" (nr));
+}
+static __inline__ void atomic_clear_bit(long nr, volatile void *addr)
+{
+ __asm__ __volatile__(
+ "lock ; btr %1,%0"
+ :"=m" (*(volatile long *)addr)
+ :"dIr" (nr));
+}
+
+#include <vl.h>
+extern shared_iopage_t *shared_page;
+extern CPUState *global_env;
+void pic_set_irq(int irq, int level)
+{
+ global_iodata_t *gio;
+ int mask;
+
+ gio = &shared_page->sp_global;
+ mask = 1 << irq;
+ if ( gio->pic_elcr & mask ) {
+ /* level */
+ if ( level ) {
+ atomic_set_bit(irq, &gio->pic_irr);
+ atomic_clear_bit(irq, &gio->pic_clear_irr);
+ global_env->send_event = 1;
+ }
+ else {
+ atomic_set_bit(irq, &gio->pic_clear_irr);
+ atomic_clear_bit(irq, &gio->pic_irr);
+ global_env->send_event = 1;
+ }
+ }
+ else {
+ /* edge */
+ if ( level ) {
+ if ( (mask & gio->pic_last_irr) == 0 ) {
+ atomic_set_bit(irq, &gio->pic_irr);
+ atomic_set_bit(irq, &gio->pic_last_irr);
+ global_env->send_event = 1;
+ }
+ }
+ else {
+ atomic_clear_bit(irq, &gio->pic_last_irr);
+ }
+ }
+}
+
+void irq_info(void)
+{
+ term_printf("irq statistic code not compiled.\n");
+}
+
+void pic_info(void)
+{
+ term_printf("pic_infoi code not compiled.\n");
+}
+
+void pic_init(void)
+{
+}
+
diff -r 8eaaa622db81 -r 2d5b92e7c79a xen/arch/x86/dm/i8259.c
--- /dev/null Fri Oct 21 17:19:38 2005
+++ b/xen/arch/x86/dm/i8259.c Fri Oct 21 17:29:26 2005
@@ -0,0 +1,520 @@
+/*
+ * QEMU 8259 interrupt controller emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2005 Intel Corperation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include <xen/config.h>
+#include <xen/types.h>
+#include <xen/mm.h>
+#include <xen/xmalloc.h>
+#include <xen/lib.h>
+#include <xen/errno.h>
+#include <xen/sched.h>
+#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>
+
+/* 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)
+{
+ int mask;
+ mask = 1 << irq;
+ if (s->elcr & mask) {
+ /* level triggered */
+ if (level) {
+ s->irr |= mask;
+ s->last_irr |= mask;
+ } else {
+ s->irr &= ~mask;
+ s->last_irr &= ~mask;
+ }
+ } else {
+ /* edge triggered */
+ if (level) {
+ if ((s->last_irr & mask) == 0) {
+ s->irr |= mask;
+ }
+ s->last_irr |= mask;
+ } else {
+ s->last_irr &= ~mask;
+ }
+ }
+}
+
+/* return the highest priority found in mask (highest = smallest
+ number). Return 8 if no irq */
+static inline int get_priority(PicState *s, int mask)
+{
+ int priority;
+ if (mask == 0)
+ return 8;
+ priority = 0;
+ while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0)
+ priority++;
+ return priority;
+}
+
+/* return the pic wanted interrupt. return -1 if none */
+static int pic_get_irq(PicState *s)
+{
+ int mask, cur_priority, priority;
+
+ mask = s->irr & ~s->imr;
+ priority = get_priority(s, mask);
+ if (priority == 8)
+ return -1;
+ /* compute current priority. If special fully nested mode on the
+ master, the IRQ coming from the slave is not taken into account
+ for the priority computation. */
+ mask = s->isr;
+ if (s->special_fully_nested_mode && s == &s->pics_state->pics[0])
+ mask &= ~(1 << 2);
+ cur_priority = get_priority(s, mask);
+ if (priority < cur_priority) {
+ /* higher priority found: an irq should be generated */
+ return (priority + s->priority_add) & 7;
+ } else {
+ return -1;
+ }
+}
+
+/* raise irq to CPU if necessary. must be called every time the active
+ irq may change */
+/* XXX: should not export it, but it is needed for an APIC kludge */
+void pic_update_irq(struct vmx_virpic *s)
+{
+ int irq2, irq;
+
+ /* first look at slave pic */
+ irq2 = pic_get_irq(&s->pics[1]);
+ if (irq2 >= 0) {
+ /* if irq request by slave pic, signal master PIC */
+ pic_set_irq1(&s->pics[0], 2, 1);
+ pic_set_irq1(&s->pics[0], 2, 0);
+ }
+ /* look at requested irq */
+ irq = pic_get_irq(&s->pics[0]);
+ if (irq >= 0) {
+ s->irq_request(s->irq_request_opaque, 1);
+ }
+}
+
+void pic_set_irq_new(void *opaque, int irq, int level)
+{
+ struct vmx_virpic *s = opaque;
+
+ pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
+ /* used for IOAPIC irqs */
+ if (s->alt_irq_func)
+ s->alt_irq_func(s->alt_irq_opaque, irq, level);
+ pic_update_irq(s);
+}
+
+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);
+}
+
+void do_pic_irqs_clear (struct vmx_virpic *s, uint16_t irqs)
+{
+ s->pics[1].irr &= ~(uint8_t)(irqs >> 8);
+ s->pics[0].irr &= ~(uint8_t) irqs;
+ pic_update_irq(s);
+}
+
+/* obsolete function */
+void pic_set_irq(struct vmx_virpic *isa_pic, int irq, int level)
+{
+ pic_set_irq_new(isa_pic, irq, level);
+}
+
+/* acknowledge interrupt 'irq' */
+static inline void pic_intack(PicState *s, int irq)
+{
+ if (s->auto_eoi) {
+ if (s->rotate_on_auto_eoi)
+ s->priority_add = (irq + 1) & 7;
+ } else {
+ s->isr |= (1 << irq);
+ }
+ /* We don't clear a level sensitive interrupt here */
+ if (!(s->elcr & (1 << irq)))
+ s->irr &= ~(1 << irq);
+}
+
+int pic_read_irq(struct vmx_virpic *s)
+{
+ int irq, irq2, intno;
+
+ irq = pic_get_irq(&s->pics[0]);
+ if (irq >= 0) {
+ pic_intack(&s->pics[0], irq);
+ if (irq == 2) {
+ irq2 = pic_get_irq(&s->pics[1]);
+ if (irq2 >= 0) {
+ pic_intack(&s->pics[1], irq2);
+ } else {
+ /* spurious IRQ on slave controller */
+ irq2 = 7;
+ }
+ intno = s->pics[1].irq_base + irq2;
+ irq = irq2 + 8;
+ } else {
+ intno = s->pics[0].irq_base + irq;
+ }
+ } else {
+ /* spurious IRQ on host controller */
+ printk("spurious IRQ irq got=%d\n",irq);
+ irq = 7;
+ intno = s->pics[0].irq_base + irq;
+ }
+ pic_update_irq(s);
+
+ return intno;
+}
+
+static void update_shared_irr(struct vmx_virpic *s, PicState *c)
+{
+ uint8_t *pl, *pe;
+
+ get_sp(current->domain)->sp_global.pic_elcr =
+ s->pics[0].elcr | ((u16)s->pics[1].elcr << 8);
+ pl =(uint8_t*)&get_sp(current->domain)->sp_global.pic_last_irr;
+ pe =(uint8_t*)&get_sp(current->domain)->sp_global.pic_elcr;
+ if ( c == &s->pics[0] ) {
+ *pl = c->last_irr;
+ *pe = c->elcr;
+ }
+ else {
+ *(pl+1) = c->last_irr;
+ *(pe+1) = c->elcr;
+ }
+}
+
+static void pic_reset(void *opaque)
+{
+ PicState *s = opaque;
+
+ s->last_irr = 0;
+ s->irr = 0;
+ s->imr = 0;
+ s->isr = 0;
+ s->priority_add = 0;
+ s->irq_base = 0;
+ s->read_reg_select = 0;
+ s->poll = 0;
+ s->special_mask = 0;
+ s->init_state = 0;
+ s->auto_eoi = 0;
+ s->rotate_on_auto_eoi = 0;
+ s->special_fully_nested_mode = 0;
+ s->init4 = 0;
+ s->elcr = 0;
+}
+
+static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+ PicState *s = opaque;
+ int priority, cmd, irq;
+
+ addr &= 1;
+ if (addr == 0) {
+ if (val & 0x10) {
+ /* init */
+ pic_reset(s);
+ update_shared_irr(s->pics_state, s);
+ /* deassert a pending interrupt */
+ s->pics_state->irq_request(s->pics_state->irq_request_opaque, 0);
+ s->init_state = 1;
+ s->init4 = val & 1;
+ if (val & 0x02)
+ hw_error("single mode not supported");
+ if (val & 0x08)
+ hw_error("level sensitive irq not supported");
+ } else if (val & 0x08) {
+ if (val & 0x04)
+ s->poll = 1;
+ if (val & 0x02)
+ s->read_reg_select = val & 1;
+ if (val & 0x40)
+ s->special_mask = (val >> 5) & 1;
+ } else {
+ cmd = val >> 5;
+ switch(cmd) {
+ case 0:
+ case 4:
+ s->rotate_on_auto_eoi = cmd >> 2;
+ break;
+ case 1: /* end of interrupt */
+ case 5:
+ priority = get_priority(s, s->isr);
+ if (priority != 8) {
+ irq = (priority + s->priority_add) & 7;
+ s->isr &= ~(1 << irq);
+ if (cmd == 5)
+ s->priority_add = (irq + 1) & 7;
+ pic_update_irq(s->pics_state);
+ }
+ break;
+ case 3:
+ irq = val & 7;
+ s->isr &= ~(1 << irq);
+ pic_update_irq(s->pics_state);
+ break;
+ case 6:
+ s->priority_add = (val + 1) & 7;
+ pic_update_irq(s->pics_state);
+ break;
+ case 7:
+ irq = val & 7;
+ s->isr &= ~(1 << irq);
+ s->priority_add = (irq + 1) & 7;
+ pic_update_irq(s->pics_state);
+ break;
+ default:
+ /* no operation */
+ break;
+ }
+ }
+ } else {
+ switch(s->init_state) {
+ case 0:
+ /* normal mode */
+ s->imr = val;
+ pic_update_irq(s->pics_state);
+ break;
+ case 1:
+ s->irq_base = val & 0xf8;
+ s->init_state = 2;
+ break;
+ case 2:
+ if (s->init4) {
+ s->init_state = 3;
+ } else {
+ s->init_state = 0;
+ }
+ break;
+ case 3:
+ s->special_fully_nested_mode = (val >> 4) & 1;
+ s->auto_eoi = (val >> 1) & 1;
+ s->init_state = 0;
+ break;
+ }
+ }
+}
+
+static uint32_t pic_poll_read (PicState *s, uint32_t addr1)
+{
+ int ret;
+
+ ret = pic_get_irq(s);
+ if (ret >= 0) {
+ if (addr1 >> 7) {
+ s->pics_state->pics[0].isr &= ~(1 << 2);
+ s->pics_state->pics[0].irr &= ~(1 << 2);
+ }
+ s->irr &= ~(1 << ret);
+ s->isr &= ~(1 << ret);
+ if (addr1 >> 7 || ret != 2)
+ pic_update_irq(s->pics_state);
+ } else {
+ ret = 0x07;
+ pic_update_irq(s->pics_state);
+ }
+
+ return ret;
+}
+
+static uint32_t pic_ioport_read(void *opaque, uint32_t addr1)
+{
+ PicState *s = opaque;
+ unsigned int addr;
+ int ret;
+
+ addr = addr1;
+ addr &= 1;
+ if (s->poll) {
+ ret = pic_poll_read(s, addr1);
+ s->poll = 0;
+ } else {
+ if (addr == 0) {
+ if (s->read_reg_select)
+ ret = s->isr;
+ else
+ ret = s->irr;
+ } else {
+ ret = s->imr;
+ }
+ }
+ return ret;
+}
+
+/* memory mapped interrupt status */
+/* XXX: may be the same than pic_read_irq() */
+uint32_t pic_intack_read(struct vmx_virpic *s)
+{
+ int ret;
+
+ ret = pic_poll_read(&s->pics[0], 0x00);
+ if (ret == 2)
+ ret = pic_poll_read(&s->pics[1], 0x80) + 8;
+ /* Prepare for ISR read */
+ s->pics[0].read_reg_select = 1;
+
+ return ret;
+}
+
+static void elcr_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+ PicState *s = opaque;
+ s->elcr = val & s->elcr_mask;
+}
+
+static uint32_t elcr_ioport_read(void *opaque, uint32_t addr1)
+{
+ PicState *s = opaque;
+ return s->elcr;
+}
+
+/* XXX: add generic master/slave system */
+static void pic_init1(int io_addr, int elcr_addr, PicState *s)
+{
+ pic_reset(s);
+}
+
+void pic_init(struct vmx_virpic *s, void (*irq_request)(),
+ void *irq_request_opaque)
+{
+ memset(s, 0, sizeof(*s));
+ pic_init1(0x20, 0x4d0, &s->pics[0]);
+ pic_init1(0xa0, 0x4d1, &s->pics[1]);
+ s->pics[0].elcr_mask = 0xf8;
+ s->pics[1].elcr_mask = 0xde;
+ s->irq_request = irq_request;
+ s->irq_request_opaque = irq_request_opaque;
+ s->pics[0].pics_state = s;
+ s->pics[1].pics_state = s;
+ return;
+}
+
+void pic_set_alt_irq_func(struct vmx_virpic *s, void (*alt_irq_func)(),
+ void *alt_irq_opaque)
+{
+ s->alt_irq_func = alt_irq_func;
+ s->alt_irq_opaque = alt_irq_opaque;
+}
+
+static int intercept_pic_io(ioreq_t *p)
+{
+ struct vmx_virpic *pic;
+ struct vcpu *v = current;
+ uint32_t data;
+
+ if ( p->size != 1 || p->count != 1) {
+ printk("PIC_IO wrong access size %d!\n", (int)p->size);
+ return 1;
+ }
+ pic = &v->domain->arch.vmx_platform.vmx_pic;
+ if ( p->dir == 0 ) {
+ if(p->pdata_valid)
+ vmx_copy(&data, (unsigned long)p->u.pdata, p->size, VMX_COPY_IN);
+ else
+ data = p->u.data;
+ pic_ioport_write((void*)&pic->pics[p->addr>>7],
+ (uint32_t) p->addr, (uint32_t) (data & 0xff));
+ }
+ else {
+ data = pic_ioport_read(
+ (void*)&pic->pics[p->addr>>7], (uint32_t) p->addr);
+ if(p->pdata_valid)
+ vmx_copy(&data, (unsigned long)p->u.pdata, p->size, VMX_COPY_OUT);
+ else
+ p->u.data = (u64)data;
+ }
+ return 1;
+}
+
+static int intercept_elcr_io(ioreq_t *p)
+{
+ struct vmx_virpic *s;
+ struct vcpu *v = current;
+ uint32_t data;
+
+ if ( p->size != 1 || p->count != 1 ) {
+ printk("PIC_IO wrong access size %d!\n", (int)p->size);
+ return 1;
+ }
+
+ s = &v->domain->arch.vmx_platform.vmx_pic;
+ if ( p->dir == 0 ) {
+ if(p->pdata_valid)
+ vmx_copy(&data, (unsigned long)p->u.pdata, p->size, VMX_COPY_IN);
+ else
+ data = p->u.data;
+ elcr_ioport_write((void*)&s->pics[p->addr&1],
+ (uint32_t) p->addr, (uint32_t)( data & 0xff));
+ get_sp(current->domain)->sp_global.pic_elcr =
+ s->pics[0].elcr | ((u16)s->pics[1].elcr << 8);
+ }
+ else {
+ data = (u64) elcr_ioport_read(
+ (void*)&s->pics[p->addr&1], (uint32_t) p->addr);
+ if(p->pdata_valid)
+ vmx_copy(&data, (unsigned long)p->u.pdata, p->size, VMX_COPY_OUT);
+ else
+ p->u.data = (u64)data;
+
+ }
+ return 1;
+}
+void register_pic_io_hook (void)
+{
+ register_portio_handler(0x20, 2, intercept_pic_io);
+ register_portio_handler(0x4d0, 1, intercept_elcr_io);
+ register_portio_handler(0xa0, 2, intercept_pic_io);
+ register_portio_handler(0x4d1, 1, intercept_elcr_io);
+}
+
+
+/* IRQ handling */
+int cpu_get_pic_interrupt(struct vcpu *v, int *type)
+{
+ int intno;
+ struct vmx_virpic *s = &v->domain->arch.vmx_platform.vmx_pic;
+
+ /* read the irq from the PIC */
+ intno = pic_read_irq(s);
+ *type = VLAPIC_DELIV_MODE_EXT;
+ return intno;
+}
+
+int is_pit_irq(struct vcpu *v, int irq)
+{
+ int pit_vec = v->domain->arch.vmx_platform.vmx_pic.pics[0].irq_base;
+
+ return (irq == pit_vec);
+}
diff -r 8eaaa622db81 -r 2d5b92e7c79a xen/include/public/io/vmx_vpic.h
--- /dev/null Fri Oct 21 17:19:38 2005
+++ b/xen/include/public/io/vmx_vpic.h Fri Oct 21 17:29:26 2005
@@ -0,0 +1,84 @@
+/*
+ * QEMU System Emulator header
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ * Copyright (c) 2005 Intel Corp
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef _VMX_VPIC_H
+#define _VMX_VPIC_H
+
+#define hw_error(x) do {} while (0);
+
+
+/* i8259.c */
+typedef struct IOAPICState IOAPICState;
+typedef struct PicState {
+ uint8_t last_irr; /* edge detection */
+ uint8_t irr; /* interrupt request register */
+ uint8_t imr; /* interrupt mask register */
+ uint8_t isr; /* interrupt service register */
+ uint8_t priority_add; /* highest irq priority */
+ uint8_t irq_base;
+ uint8_t read_reg_select;
+ uint8_t poll;
+ uint8_t special_mask;
+ uint8_t init_state;
+ uint8_t auto_eoi;
+ uint8_t rotate_on_auto_eoi;
+ uint8_t special_fully_nested_mode;
+ uint8_t init4; /* true if 4 byte init */
+ uint8_t elcr; /* PIIX edge/trigger selection*/
+ uint8_t elcr_mask;
+ struct vmx_virpic *pics_state;
+} PicState;
+
+struct vmx_virpic {
+ /* 0 is master pic, 1 is slave pic */
+ /* XXX: better separation between the two pics */
+ PicState pics[2];
+ void (*irq_request)(int *opaque, int level);
+ void *irq_request_opaque;
+ /* IOAPIC callback support */
+ void (*alt_irq_func)(void *opaque, int irq_num, int level);
+ void *alt_irq_opaque;
+};
+
+
+void pic_set_irq(struct vmx_virpic *s, int irq, int level);
+void pic_set_irq_new(void *opaque, int irq, int level);
+void pic_init(struct vmx_virpic *s,
+ void (*irq_request)(),
+ void *irq_request_opaque);
+void pic_set_alt_irq_func(struct vmx_virpic *s,
+ void(*alt_irq_func)(),
+ void *alt_irq_opaque);
+int pic_read_irq(struct vmx_virpic *s);
+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);
+void do_pic_irqs (struct vmx_virpic *s, uint16_t irqs);
+void do_pic_irqs_clear (struct vmx_virpic *s, uint16_t irqs);
+
+/* APIC */
+#endif /* _VMX_VPIC_H */
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|