public inbox for kvm@vger.kernel.org
 help / color / mirror / Atom feed
* 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