* support for in-kernel piohandlers
@ 2007-06-18 9:55 Dong, Eddie
[not found] ` <10EA09EFD8728347A513008B6B0DA77A01A01C9E-wq7ZOvIWXbNpB2pF5aRoyrfspsVTdybXVpNB7YpNyf8@public.gmane.org>
0 siblings, 1 reply; 3+ messages in thread
From: Dong, Eddie @ 2007-06-18 9:55 UTC (permalink / raw)
To: kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
[-- Attachment #1: Type: text/plain, Size: 3895 bytes --]
This patch add in-kernel piohandlers on top of Greg's in-kernel
mmiohandlers as a preparation of in kernel PIC patch.
Eddie
Signed-off-by: Yaozu (Eddie) Dong <eddie.dong-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
index 31846b1..a7c5e6b 100644
--- a/drivers/kvm/kvm.h
+++ b/drivers/kvm/kvm.h
@@ -241,6 +241,7 @@ struct kvm_pio_request {
struct page *guest_pages[2];
unsigned guest_page_offset;
int in;
+ int port;
int size;
int string;
int down;
@@ -303,7 +304,8 @@ static inline int kvm_iodevice_inrange(struct
kvm_io_device *dev, gpa_t addr)
static inline void kvm_iodevice_destructor(struct kvm_io_device *dev)
{
- dev->destructor(dev);
+ if (dev->destructor)
+ dev->destructor(dev);
}
/*
@@ -453,6 +455,7 @@ struct kvm {
struct list_head vm_list;
struct file *filp;
struct kvm_io_bus mmio_bus;
+ struct kvm_io_bus pio_bus;
};
struct descriptor_table {
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index 1736662..b9f6c47 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -367,6 +367,7 @@ static struct kvm *kvm_create_vm(void)
list_add(&kvm->vm_list, &vm_list);
spin_unlock(&kvm_lock);
kvm_io_bus_init(&kvm->mmio_bus);
+ kvm_io_bus_init(&kvm->pio_bus);
for (i = 0; i < KVM_MAX_VCPUS; ++i) {
struct kvm_vcpu *vcpu = &kvm->vcpus[i];
@@ -475,6 +476,7 @@ static void kvm_destroy_vm(struct kvm *kvm)
spin_lock(&kvm_lock);
list_del(&kvm->vm_list);
spin_unlock(&kvm_lock);
+ kvm_io_bus_destroy(&kvm->pio_bus);
kvm_io_bus_destroy(&kvm->mmio_bus);
kvm_free_vcpus(kvm);
kvm_free_physmem(kvm);
@@ -1110,6 +1112,12 @@ static struct kvm_io_device
*vcpu_find_mmio_dev(struct kvm_vcpu *vcpu,
return kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr);
}
+static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu,
+ gpa_t addr)
+{
+ return kvm_io_bus_find_dev(&vcpu->kvm->pio_bus, addr);
+}
+
static int emulator_read_emulated(unsigned long addr,
void *val,
unsigned int bytes,
@@ -1832,6 +1840,20 @@ static int complete_pio(struct kvm_vcpu *vcpu)
return 0;
}
+void kernel_pio(struct kvm_io_device *pio_dev, struct kvm_vcpu *vcpu)
+{
+ /* TODO: String I/O for in kernel device */
+
+ if (vcpu->pio.in)
+ kvm_iodevice_read(pio_dev, vcpu->pio.port,
+ vcpu->pio.size,
+ vcpu->pio_data);
+ else
+ kvm_iodevice_write(pio_dev, vcpu->pio.port,
+ vcpu->pio.size,
+ vcpu->pio_data);
+}
+
int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
int size, unsigned long count, int string, int down,
gva_t address, int rep, unsigned port)
@@ -1840,6 +1862,7 @@ int kvm_setup_pio(struct kvm_vcpu *vcpu, struct
kvm_run *run, int in,
int i;
int nr_pages = 1;
struct page *page;
+ struct kvm_io_device *pio_dev;
vcpu->run->exit_reason = KVM_EXIT_IO;
vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT;
@@ -1851,17 +1874,27 @@ int kvm_setup_pio(struct kvm_vcpu *vcpu, struct
kvm_run *run, int in,
vcpu->pio.cur_count = count;
vcpu->pio.size = size;
vcpu->pio.in = in;
+ vcpu->pio.port = port;
vcpu->pio.string = string;
vcpu->pio.down = down;
vcpu->pio.guest_page_offset = offset_in_page(address);
vcpu->pio.rep = rep;
+ pio_dev = vcpu_find_pio_dev(vcpu, port);
if (!string) {
kvm_arch_ops->cache_regs(vcpu);
memcpy(vcpu->pio_data, &vcpu->regs[VCPU_REGS_RAX], 4);
kvm_arch_ops->decache_regs(vcpu);
+ if (pio_dev) {
+ kernel_pio(pio_dev, vcpu);
+ complete_pio(vcpu);
+ return 1;
+ }
return 0;
}
+ /* TODO: String I/O for in kernel device */
+ if (pio_dev)
+ printk(KERN_ERR "kvm_setup_pio: no string io
support\n");
if (!count) {
kvm_arch_ops->skip_emulated_instruction(vcpu);
[-- Attachment #2: pio-all.patch.2 --]
[-- Type: application/octet-stream, Size: 3791 bytes --]
commit e78536763720956bd719dbdf69cf0a4b637f4882
Author: root <root@vt32-pae.(none)>
Date: Mon Jun 18 17:51:14 2007 +0800
Add in-kernel piohandlers to enable kernel pio device.
Signed-off-by: Yaozu (Eddie) Dong <eddie.dong@intel.com>
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
index 31846b1..a7c5e6b 100644
--- a/drivers/kvm/kvm.h
+++ b/drivers/kvm/kvm.h
@@ -241,6 +241,7 @@ struct kvm_pio_request {
struct page *guest_pages[2];
unsigned guest_page_offset;
int in;
+ int port;
int size;
int string;
int down;
@@ -303,7 +304,8 @@ static inline int kvm_iodevice_inrange(struct kvm_io_device *dev, gpa_t addr)
static inline void kvm_iodevice_destructor(struct kvm_io_device *dev)
{
- dev->destructor(dev);
+ if (dev->destructor)
+ dev->destructor(dev);
}
/*
@@ -453,6 +455,7 @@ struct kvm {
struct list_head vm_list;
struct file *filp;
struct kvm_io_bus mmio_bus;
+ struct kvm_io_bus pio_bus;
};
struct descriptor_table {
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index 1736662..b9f6c47 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -367,6 +367,7 @@ static struct kvm *kvm_create_vm(void)
list_add(&kvm->vm_list, &vm_list);
spin_unlock(&kvm_lock);
kvm_io_bus_init(&kvm->mmio_bus);
+ kvm_io_bus_init(&kvm->pio_bus);
for (i = 0; i < KVM_MAX_VCPUS; ++i) {
struct kvm_vcpu *vcpu = &kvm->vcpus[i];
@@ -475,6 +476,7 @@ static void kvm_destroy_vm(struct kvm *kvm)
spin_lock(&kvm_lock);
list_del(&kvm->vm_list);
spin_unlock(&kvm_lock);
+ kvm_io_bus_destroy(&kvm->pio_bus);
kvm_io_bus_destroy(&kvm->mmio_bus);
kvm_free_vcpus(kvm);
kvm_free_physmem(kvm);
@@ -1110,6 +1112,12 @@ static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu,
return kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr);
}
+static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu,
+ gpa_t addr)
+{
+ return kvm_io_bus_find_dev(&vcpu->kvm->pio_bus, addr);
+}
+
static int emulator_read_emulated(unsigned long addr,
void *val,
unsigned int bytes,
@@ -1832,6 +1840,20 @@ static int complete_pio(struct kvm_vcpu *vcpu)
return 0;
}
+void kernel_pio(struct kvm_io_device *pio_dev, struct kvm_vcpu *vcpu)
+{
+ /* TODO: String I/O for in kernel device */
+
+ if (vcpu->pio.in)
+ kvm_iodevice_read(pio_dev, vcpu->pio.port,
+ vcpu->pio.size,
+ vcpu->pio_data);
+ else
+ kvm_iodevice_write(pio_dev, vcpu->pio.port,
+ vcpu->pio.size,
+ vcpu->pio_data);
+}
+
int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
int size, unsigned long count, int string, int down,
gva_t address, int rep, unsigned port)
@@ -1840,6 +1862,7 @@ int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
int i;
int nr_pages = 1;
struct page *page;
+ struct kvm_io_device *pio_dev;
vcpu->run->exit_reason = KVM_EXIT_IO;
vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT;
@@ -1851,17 +1874,27 @@ int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
vcpu->pio.cur_count = count;
vcpu->pio.size = size;
vcpu->pio.in = in;
+ vcpu->pio.port = port;
vcpu->pio.string = string;
vcpu->pio.down = down;
vcpu->pio.guest_page_offset = offset_in_page(address);
vcpu->pio.rep = rep;
+ pio_dev = vcpu_find_pio_dev(vcpu, port);
if (!string) {
kvm_arch_ops->cache_regs(vcpu);
memcpy(vcpu->pio_data, &vcpu->regs[VCPU_REGS_RAX], 4);
kvm_arch_ops->decache_regs(vcpu);
+ if (pio_dev) {
+ kernel_pio(pio_dev, vcpu);
+ complete_pio(vcpu);
+ return 1;
+ }
return 0;
}
+ /* TODO: String I/O for in kernel device */
+ if (pio_dev)
+ printk(KERN_ERR "kvm_setup_pio: no string io support\n");
if (!count) {
kvm_arch_ops->skip_emulated_instruction(vcpu);
[-- Attachment #3: Type: text/plain, Size: 286 bytes --]
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
[-- Attachment #4: Type: text/plain, Size: 186 bytes --]
_______________________________________________
kvm-devel mailing list
kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
https://lists.sourceforge.net/lists/listinfo/kvm-devel
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: support for in-kernel piohandlers
[not found] ` <10EA09EFD8728347A513008B6B0DA77A01A01C9E-wq7ZOvIWXbNpB2pF5aRoyrfspsVTdybXVpNB7YpNyf8@public.gmane.org>
@ 2007-06-18 11:34 ` Gregory Haskins
2007-06-19 15:05 ` Avi Kivity
1 sibling, 0 replies; 3+ messages in thread
From: Gregory Haskins @ 2007-06-18 11:34 UTC (permalink / raw)
To: Dong, Eddie; +Cc: kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
[-- Attachment #1: Type: text/plain, Size: 5289 bytes --]
Hi Eddie,
Patch looks good.
In case it helps, I have attached a patch I wrote a while back for
implementing a pair of cascaded i8259s as an irqdevice. The code is a
little out of date w.r.t. the current incarnation of irqdevice, but its
a start.
As far as design is concerned, I was going to use this as follows:
1) Implement a "isa" irqdevice model, which would contain an ioapic
model, and a cascaded i8259 model.
2) All input pins would map to both the ioapic and cascaded_8259
3) 8259s outputs would map to the isa output
4) ioapic would connect to the apicbus logic
5) new isa would be installed on kvm->isa_irq when "level-2" mode was
enabled.
Feel free to use or ignore at your discretion.
Regards,
-Greg
On Mon, 2007-06-18 at 17:55 +0800, Dong, Eddie wrote:
> This patch add in-kernel piohandlers on top of Greg's in-kernel
> mmiohandlers as a preparation of in kernel PIC patch.
>
> Eddie
>
> Signed-off-by: Yaozu (Eddie) Dong <eddie.dong-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
>
>
> diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
> index 31846b1..a7c5e6b 100644
> --- a/drivers/kvm/kvm.h
> +++ b/drivers/kvm/kvm.h
> @@ -241,6 +241,7 @@ struct kvm_pio_request {
> struct page *guest_pages[2];
> unsigned guest_page_offset;
> int in;
> + int port;
> int size;
> int string;
> int down;
> @@ -303,7 +304,8 @@ static inline int kvm_iodevice_inrange(struct
> kvm_io_device *dev, gpa_t addr)
>
> static inline void kvm_iodevice_destructor(struct kvm_io_device *dev)
> {
> - dev->destructor(dev);
> + if (dev->destructor)
> + dev->destructor(dev);
> }
>
> /*
> @@ -453,6 +455,7 @@ struct kvm {
> struct list_head vm_list;
> struct file *filp;
> struct kvm_io_bus mmio_bus;
> + struct kvm_io_bus pio_bus;
> };
>
> struct descriptor_table {
> diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
> index 1736662..b9f6c47 100644
> --- a/drivers/kvm/kvm_main.c
> +++ b/drivers/kvm/kvm_main.c
> @@ -367,6 +367,7 @@ static struct kvm *kvm_create_vm(void)
> list_add(&kvm->vm_list, &vm_list);
> spin_unlock(&kvm_lock);
> kvm_io_bus_init(&kvm->mmio_bus);
> + kvm_io_bus_init(&kvm->pio_bus);
> for (i = 0; i < KVM_MAX_VCPUS; ++i) {
> struct kvm_vcpu *vcpu = &kvm->vcpus[i];
>
> @@ -475,6 +476,7 @@ static void kvm_destroy_vm(struct kvm *kvm)
> spin_lock(&kvm_lock);
> list_del(&kvm->vm_list);
> spin_unlock(&kvm_lock);
> + kvm_io_bus_destroy(&kvm->pio_bus);
> kvm_io_bus_destroy(&kvm->mmio_bus);
> kvm_free_vcpus(kvm);
> kvm_free_physmem(kvm);
> @@ -1110,6 +1112,12 @@ static struct kvm_io_device
> *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu,
> return kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr);
> }
>
> +static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu,
> + gpa_t addr)
> +{
> + return kvm_io_bus_find_dev(&vcpu->kvm->pio_bus, addr);
> +}
> +
> static int emulator_read_emulated(unsigned long addr,
> void *val,
> unsigned int bytes,
> @@ -1832,6 +1840,20 @@ static int complete_pio(struct kvm_vcpu *vcpu)
> return 0;
> }
>
> +void kernel_pio(struct kvm_io_device *pio_dev, struct kvm_vcpu *vcpu)
> +{
> + /* TODO: String I/O for in kernel device */
> +
> + if (vcpu->pio.in)
> + kvm_iodevice_read(pio_dev, vcpu->pio.port,
> + vcpu->pio.size,
> + vcpu->pio_data);
> + else
> + kvm_iodevice_write(pio_dev, vcpu->pio.port,
> + vcpu->pio.size,
> + vcpu->pio_data);
> +}
> +
> int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
> int size, unsigned long count, int string, int down,
> gva_t address, int rep, unsigned port)
> @@ -1840,6 +1862,7 @@ int kvm_setup_pio(struct kvm_vcpu *vcpu, struct
> kvm_run *run, int in,
> int i;
> int nr_pages = 1;
> struct page *page;
> + struct kvm_io_device *pio_dev;
>
> vcpu->run->exit_reason = KVM_EXIT_IO;
> vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT;
> @@ -1851,17 +1874,27 @@ int kvm_setup_pio(struct kvm_vcpu *vcpu, struct
> kvm_run *run, int in,
> vcpu->pio.cur_count = count;
> vcpu->pio.size = size;
> vcpu->pio.in = in;
> + vcpu->pio.port = port;
> vcpu->pio.string = string;
> vcpu->pio.down = down;
> vcpu->pio.guest_page_offset = offset_in_page(address);
> vcpu->pio.rep = rep;
>
> + pio_dev = vcpu_find_pio_dev(vcpu, port);
> if (!string) {
> kvm_arch_ops->cache_regs(vcpu);
> memcpy(vcpu->pio_data, &vcpu->regs[VCPU_REGS_RAX], 4);
> kvm_arch_ops->decache_regs(vcpu);
> + if (pio_dev) {
> + kernel_pio(pio_dev, vcpu);
> + complete_pio(vcpu);
> + return 1;
> + }
> return 0;
> }
> + /* TODO: String I/O for in kernel device */
> + if (pio_dev)
> + printk(KERN_ERR "kvm_setup_pio: no string io
> support\n");
>
> if (!count) {
> kvm_arch_ops->skip_emulated_instruction(vcpu);
> -------------------------------------------------------------------------
> This SF.net email is sponsored by DB2 Express
> Download DB2 Express C - the FREE version of DB2 express and take
> control of your XML. No limits. Just data. Click to get it now.
> http://sourceforge.net/powerbar/db2/
> _______________________________________________ kvm-devel mailing list kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org https://lists.sourceforge.net/lists/listinfo/kvm-devel
[-- Attachment #2: 8259.patch --]
[-- Type: text/x-patch, Size: 13778 bytes --]
commit c042a320c2006e14d15d0f5b1c06128a0f50d91b
Author: Gregory Haskins <ghaskins-Et1tbQHTxzrQT0dZR+AlfA@public.gmane.org>
Date: Wed Apr 18 17:38:10 2007 -0400
commit cc4f93dc648f7e9ca269a700974c215c2b807e98
KVM: Add i8259 device model
Signed-off-by: Gregory Haskins <ghaskins-Et1tbQHTxzrQT0dZR+AlfA@public.gmane.org>
diff --git a/drivers/kvm/Makefile b/drivers/kvm/Makefile
index 1aad737..2196005 100644
--- a/drivers/kvm/Makefile
+++ b/drivers/kvm/Makefile
@@ -2,7 +2,7 @@
# Makefile for Kernel-based Virtual Machine module
#
-kvm-objs := kvm_main.o mmu.o x86_emulate.o userint.o lapic.o kernint.o
+kvm-objs := kvm_main.o mmu.o x86_emulate.o userint.o lapic.o kernint.o i8259.o
obj-$(CONFIG_KVM) += kvm.o
kvm-intel-objs = vmx.o
obj-$(CONFIG_KVM_INTEL) += kvm-intel.o
diff --git a/drivers/kvm/i8259.c b/drivers/kvm/i8259.c
new file mode 100644
index 0000000..4b08365
--- /dev/null
+++ b/drivers/kvm/i8259.c
@@ -0,0 +1,596 @@
+/*
+ * In-kernel 8259 PIC emulation
+ *
+ * Copyright (C) 2007 Novell
+ *
+ * Based on i8259 from QEMU, Copyright (c) 2003-2004 Fabrice Bellard
+ *
+ * Authors:
+ * Gregory Haskins <ghaskins-Et1tbQHTxzrQT0dZR+AlfA@public.gmane.org>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "kvm.h"
+
+/*----------------------------------------------------------------------
+ * Implements a single i8259
+ *---------------------------------------------------------------------
+*/
+struct kvm_i8259
+{
+ spinlock_t lock;
+ struct kvm_irqdevice *dev;
+ u8 last_irr; /* edge detection */
+ u8 irr; /* interrupt request register */
+ u8 imr; /* interrupt mask register */
+ u8 isr; /* interrupt service register */
+ u8 priority_add; /* highest irq priority */
+ u8 irq_base;
+ u8 read_reg_select;
+ u8 poll;
+ u8 special_mask;
+ u8 init_state;
+ u8 auto_eoi;
+ u8 rotate_on_auto_eoi;
+ u8 special_fully_nested_mode;
+ u8 init4; /* true if 4 byte init */
+ u8 elcr; /* PIIX edge/trigger selection*/
+ u8 elcr_mask;
+};
+
+struct kvm_i8259_address
+{
+ int ioaddr;
+ int elcraddr;
+};
+
+/*
+ * return the highest priority found in mask (highest = smallest
+ * number). Return 8 if no irq
+ */
+static inline int get_priority(struct kvm_i8259 *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 __get_irq(struct kvm_i8259 *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)
+ 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;
+ }
+}
+
+static int get_irq(struct kvm_i8259 *s)
+{
+ int ret;
+
+ spin_lock(&s->lock);
+ ret = __get_irq(s);
+ spin_unlock(&s->lock);
+
+ return ret;
+}
+
+static int i8259_ack(struct kvm_irqdevice *this, int *vector)
+{
+ struct kvm_i8259 *s = (struct kvm_i8259*)this->private;
+ int irq;
+ int ret = 0;
+
+ spin_lock(&s->lock);
+
+ if (vector) {
+ irq = __get_irq(s);
+ if (irq >= 0) {
+ 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);
+
+ ret |= KVM_IRQACK_VALID;
+ *vector = s->irq_base + irq;
+ } else
+ *vector = -1;
+ }
+
+ if (__get_irq(s) != -1)
+ ret |= KVM_IRQACK_AGAIN;
+
+ spin_unlock(&s->lock);
+
+ return ret;
+}
+
+static int _i8259_set_pin(struct kvm_i8259* s, int irq, int level)
+{
+ int mask;
+ int forward = 0;
+
+ spin_lock(&s->lock);
+
+ 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;
+ }
+ forward = 1;
+ } else {
+ /*
+ * edge triggered
+ */
+ if (level) {
+ if ((s->last_irr & mask) == 0) {
+ s->irr |= mask;
+ forward = 1;
+ }
+ s->last_irr |= mask;
+ } else {
+ s->last_irr &= ~mask;
+ }
+ }
+
+ spin_unlock(&s->lock);
+
+ if (forward)
+ kvm_irqdevice_set_intr(s->dev,
+ kvm_irqpin_localint,
+ 1, /* We are always level-sensitve */
+ level);
+
+ return 0;
+}
+
+static int i8259_set_pin(struct kvm_irqdevice* this, int irq, int level)
+{
+ struct kvm_i8259 *s = (struct kvm_i8259*)this->private;
+
+ return _i8259_set_pin(s, irq, level);
+}
+
+/*
+ * Invoked whenever a cascaded slave asserts its external interrupt pin.
+ * This will result in the current controller to inject IRQ2 since this
+ * is the pin the interrupt would be connected to in real life
+ */
+static void i8259_master_interrupt(struct kvm_irqsink *this,
+ struct kvm_irqdevice *dev,
+ kvm_irqpin_t pin, int level, int val)
+{
+ struct kvm_i8259 *s = (struct kvm_i8259*)this->private;
+
+ _i8259_set_pin(s, 2, val);
+}
+
+static int i8259_summary(struct kvm_irqdevice* this, void *data)
+{
+ struct kvm_i8259 *s = (struct kvm_i8259*)this->private;
+
+ /* FIXME */
+
+ return 0;
+}
+
+static void i8259_destructor(struct kvm_irqdevice *this)
+{
+ kfree(this->private);
+}
+
+static void i8259_reset(struct kvm_i8259 *s)
+{
+ 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;
+ /* Note: ELCR is not reset */
+}
+
+static void i8259_pio_write(struct kvm_io_device *this,
+ gpa_t addr,
+ int len,
+ unsigned long val)
+{
+ struct kvm_i8259 *s = (struct kvm_i8259*)this->private;
+ int priority, cmd, irq;
+ int update = 0;
+
+#ifdef DEBUG_PIC
+ printf("pic_write: addr=0x%02x val=0x%02x\n", addr, val);
+#endif
+ spin_lock(&s->lock);
+
+ addr &= 1;
+ if (addr == 0) {
+ if (val & 0x10) {
+ /* init */
+ i8259_reset(s);
+ update = 1;
+ s->init_state = 1;
+ s->init4 = val & 1;
+ if (val & 0x02)
+ printk("single mode not supported\n");
+ if (val & 0x08)
+ printk("level sensitive irq not supported\n");
+ } 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;
+ update = 1;
+ }
+ break;
+ case 3:
+ irq = val & 7;
+ s->isr &= ~(1 << irq);
+ update = 1;
+ break;
+ case 6:
+ s->priority_add = (val + 1) & 7;
+ update = 1;
+ break;
+ case 7:
+ irq = val & 7;
+ s->isr &= ~(1 << irq);
+ s->priority_add = (irq + 1) & 7;
+ update = 1;
+ break;
+ default:
+ /* no operation */
+ break;
+ }
+ }
+ } else {
+ switch(s->init_state) {
+ case 0:
+ /* normal mode */
+ s->imr = val;
+ update = 1;
+ 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;
+ }
+ }
+
+ spin_unlock(&s->lock);
+
+ if (update) {
+ int val = (get_irq(s) != -1);
+ kvm_irqdevice_set_intr(s->dev,
+ kvm_irqpin_localint,
+ 1, /* level */
+ val);
+ }
+}
+
+static unsigned long i8259_pio_read(struct kvm_io_device *this,
+ gpa_t addr,
+ int len)
+{
+ struct kvm_i8259 *s = (struct kvm_i8259*)this->private;
+ int ret, update = 0;
+
+ spin_lock(&s->lock);
+
+ if (s->poll) {
+ ret = __get_irq(s);
+ if (ret >= 0) {
+ s->irr &= ~(1 << ret);
+ s->isr &= ~(1 << ret);
+ } else
+ ret = 0x07;
+
+ update = 1;
+ s->poll = 0;
+ } else {
+ if (!(addr & 1)) {
+ if (s->read_reg_select)
+ ret = s->isr;
+ else
+ ret = s->irr;
+ } else {
+ ret = s->imr;
+ }
+ }
+
+ spin_unlock(&s->lock);
+
+ if (update) {
+ int val = (get_irq(s) != -1);
+ kvm_irqdevice_set_intr(s->dev,
+ kvm_irqpin_localint,
+ 1, /* level */
+ val);
+ }
+
+#ifdef DEBUG_PIC
+ printf("pic_read: addr=0x%02x val=0x%02x\n", addr, ret);
+#endif
+
+ return ret;
+}
+
+int kvm_i8259_init(struct kvm_irqdevice *dev,
+ const struct kvm_i8259_address *addr)
+{
+ struct kvm_i8259 *s;
+
+ s = kzalloc(sizeof(*s), GFP_KERNEL);
+ if (!s)
+ return -ENOMEM;
+
+ spin_lock_init(&s->lock);
+
+ dev->ack = i8259_ack;
+ dev->set_pin = i8259_set_pin;
+ dev->summary = i8259_summary;
+ dev->destructor = i8259_destructor;
+
+ dev->private = s;
+ s->dev = dev;
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------
+ * Implements dual cascaded i8259s
+ *---------------------------------------------------------------------*/
+
+struct kvm_i8259_cascaded
+{
+ spinlock_t lock;
+ struct kvm_irqdevice chip[2];
+ struct kvm_irqdevice *dev;
+};
+
+#define for_each_chip(pos) for(pos=0; pos < 2; pos++)
+
+static int i8259_cascaded_ack(struct kvm_irqdevice *this, int *vector)
+{
+ struct kvm_i8259_cascaded *s = (struct kvm_i8259_cascaded*)this->private;
+ int ret = 0;
+ int i, r;
+
+ spin_lock(&s->lock);
+
+ if (vector) {
+ int irq;
+
+ irq = get_irq(s->chip[0].private);
+ if (irq > -1) {
+ /*
+ * First read the master to ack the int
+ */
+ r = kvm_irqdevice_ack(&s->chip[0], vector);
+ BUG_ON(r < 0);
+ BUG_ON(!(r & KVM_IRQACK_VALID));
+ ret |= r;
+
+ if (irq == 2) {
+ /*
+ * If this is a cascaded interrupt, read the
+ * slave to get the real vector
+ */
+ r = kvm_irqdevice_ack(&s->chip[1], vector);
+ BUG_ON(r < 0);
+ BUG_ON(!(r & KVM_IRQACK_VALID));
+ ret |= r;
+ }
+
+ ret |= KVM_IRQACK_VALID;
+ } else {
+ *vector = -1;
+ ret &= ~KVM_IRQACK_VALID;
+ }
+ }
+
+ for_each_chip(i) {
+ r = kvm_irqdevice_ack(&s->chip[i], NULL);
+ BUG_ON(r < 0);
+ ret |= r;
+ }
+
+ spin_unlock(&s->lock);
+
+ return ret;
+}
+
+static int i8259_cascaded_set_pin(struct kvm_irqdevice* this,
+ int irq,
+ int level)
+{
+ struct kvm_i8259_cascaded *s = (struct kvm_i8259_cascaded*)this->private;
+ int ret = -1;
+ struct kvm_irqdevice *dev;
+
+ BUG_ON(irq == 2); /* This pin is wired to the slave */
+
+ spin_lock(&s->lock);
+
+ if ((irq >= 0) && (irq <= 7))
+ dev = &s->chip[0];
+ else if ((irq >= 8) && (irq <= 15)) {
+ irq -= 8;
+ dev = &s->chip[1];
+ }
+ else
+ BUG();
+
+ ret = kvm_irqdevice_set_pin(dev, irq, level);
+
+ spin_unlock(&s->lock);
+
+ return ret;
+}
+
+static int i8259_cascaded_summary(struct kvm_irqdevice* this, void *data)
+{
+ struct kvm_i8259_cascaded *s = (struct kvm_i8259_cascaded*)this->private;
+
+ /* FIXME */
+
+ return 0;
+}
+
+static void i8259_cascaded_destructor(struct kvm_irqdevice *this)
+{
+ struct kvm_i8259_cascaded *s = this->private;
+ int i;
+
+ for_each_chip(i) {
+ struct kvm_irqdevice *dev = &s->chip[i];
+ dev->destructor(dev);
+ }
+
+ kfree(this->private);
+}
+
+/*
+ * Invoked whenever a cascaded master asserts its external interrupt pin.
+ */
+static void i8259_cascaded_interrupt(struct kvm_irqsink *this,
+ struct kvm_irqdevice *dev,
+ kvm_irqpin_t pin, int level, int val)
+{
+ struct kvm_i8259_cascaded *s = this->private;
+
+ /* Forward the request on to whomever is above us */
+ kvm_irqdevice_set_intr(s->dev, kvm_irqpin_localint, level, val);
+}
+
+int kvm_i8259_cascaded_init(struct kvm_irqdevice *dev)
+{
+ struct kvm_i8259_cascaded *s;
+ int i;
+
+ s = kzalloc(sizeof(*s), GFP_KERNEL);
+ if (!s)
+ return -ENOMEM;
+
+ spin_lock_init(&s->lock);
+
+ {
+ struct kvm_irqsink sink = {
+ .set_intr = i8259_cascaded_interrupt,
+ .private = s
+ };
+ struct kvm_i8259_address addr = {
+ .ioaddr = 0x20,
+ .elcraddr = 0x4d0
+ };
+
+ kvm_i8259_init(&s->chip[0], &addr);
+ kvm_irqdevice_register_sink(&s->chip[0], &sink);
+ }
+
+ {
+ struct kvm_irqsink sink = {
+ .set_intr = i8259_master_interrupt,
+ .private = s
+ };
+ struct kvm_i8259_address addr = {
+ .ioaddr = 0xA0,
+ .elcraddr = 0x4d1
+ };
+
+ kvm_i8259_init(&s->chip[1], &addr);
+ kvm_irqdevice_register_sink(&s->chip[1], &sink);
+ }
+
+ s->dev = dev;
+
+ dev->ack = i8259_cascaded_ack;
+ dev->set_pin = i8259_cascaded_set_pin;
+ dev->summary = i8259_cascaded_summary;
+ dev->destructor = i8259_cascaded_destructor;
+
+ dev->private = s;
+
+ return 0;
+}
[-- Attachment #3: Type: text/plain, Size: 286 bytes --]
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
[-- Attachment #4: Type: text/plain, Size: 186 bytes --]
_______________________________________________
kvm-devel mailing list
kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
https://lists.sourceforge.net/lists/listinfo/kvm-devel
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: support for in-kernel piohandlers
[not found] ` <10EA09EFD8728347A513008B6B0DA77A01A01C9E-wq7ZOvIWXbNpB2pF5aRoyrfspsVTdybXVpNB7YpNyf8@public.gmane.org>
2007-06-18 11:34 ` Gregory Haskins
@ 2007-06-19 15:05 ` Avi Kivity
1 sibling, 0 replies; 3+ messages in thread
From: Avi Kivity @ 2007-06-19 15:05 UTC (permalink / raw)
To: Dong, Eddie; +Cc: kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
Dong, Eddie wrote:
> This patch add in-kernel piohandlers on top of Greg's in-kernel
> mmiohandlers as a preparation of in kernel PIC patch.
>
>
Applied, thanks.
--
error compiling committee.c: too many arguments to function
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2007-06-19 15:05 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-06-18 9:55 support for in-kernel piohandlers Dong, Eddie
[not found] ` <10EA09EFD8728347A513008B6B0DA77A01A01C9E-wq7ZOvIWXbNpB2pF5aRoyrfspsVTdybXVpNB7YpNyf8@public.gmane.org>
2007-06-18 11:34 ` Gregory Haskins
2007-06-19 15:05 ` Avi Kivity
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox