Re: In kernel PIC support: kernel patch

Avi Kivity
2007-06-22T10:50:02Z

Dong, Eddie wrote:

First, sorry for the delayed review.

> +#include "virq.h"
> +#include <linux/mm.h>
>

Includes from <linux/> before includes from local directory please.

> +
> +/* set irq level. If an edge is detected, then the IRR is set to 1 */
>

Kernel comments like this:

/*
* blah blah blah
*/

This comment applies to the rest of the patch.

> diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
> index a7c5e6b..1e2d3ba 100644
> --- a/drivers/kvm/kvm.h
> +++ b/drivers/kvm/kvm.h
> @@ -456,8 +456,15 @@ struct kvm {
> struct file *filp;
> struct kvm_io_bus mmio_bus;
> struct kvm_io_bus pio_bus;
> + void *vpic;
>

Why void?

> };
>
> +#define kernel_pic(kvm) ((kvm)->vpic)
>

Please, no function-like macros. In this case, just put kvm->vpic
everywhere.

> spin_lock(&kvm_lock);
> list_del(&kvm->vm_list);
> spin_unlock(&kvm_lock);
> + if (kernel_pic(kvm))
> + kfree(kernel_pic(kvm));
>

kfree() knows about null pointers, no need for the check.

> + case KVM_CREATE_PIC:
> + r = -ENOMEM;
> + kernel_pic(kvm) = create_pic(kvm);
>

Ow!

> + if (kernel_pic(kvm)) {
> + r = 0;
> + }
>

No {} for single-line if statements in the kernel.

> + break;
> + case KVM_SET_ISA_IRQ_LEVEL: {
> + struct kvm_irq_level irq_event;
>

blank line here.

> +#include "kvm.h"
> +#include "virq.h"
> +
> +/*
> + * check if there is pending interrupt without
> + * intack.
> + */
> +int cpu_has_interrupt(struct kvm_vcpu *v)
> +{
> + struct pic_state2 *s = kernel_pic(v->kvm);
> +
>

Isn't the PIC connected to just one cpu?

> + /* PIC */
> + if (int_output(s))
> + return 1;
> + /* TODO: APIC */
> + return 0;
> +}
> +
> +EXPORT_SYMBOL_GPL(cpu_has_interrupt);
>

exported symbols (or even non-static symbols) should begin with kvm_.

> +
> +/*
> + * Read pending interrupt vector and intack.
> + */
> +int cpu_get_interrupt(struct kvm_vcpu *v)
> +{
> + struct pic_state2 *s = kernel_pic(v->kvm);
> + int vector;
> +
> + int_output(s) = 0;
> + vector = pic_read_irq(s);
> + if (vector != -1)
> + return vector;
> + /* TODO: APIC */
> + return -1;
> +}
> +
> +EXPORT_SYMBOL_GPL(cpu_get_interrupt);
>

kvm_.

> +
> +typedef void SetIRQFunc(void *opaque, int irq_num, int level);
> +typedef void IRQRequestFunc(void *opaque, int level);
>

Lower case names.

> +
> +struct PicState2;
> +struct pic_state {
> + 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 pic_state2 *pics_state;
> +};
>

Use u8, not uint8_t in kernel code.

> +
> +struct pic_state2 {
> + /* 0 is master pic, 1 is slave pic */
> + struct pic_state pics[2];
> + IRQRequestFunc *irq_request;
> + void *irq_request_opaque;
> + /* IOAPIC callback support */
> + SetIRQFunc *alt_irq_func;
> + void *alt_irq_opaque;
> + int output; /* intr from master PIC */
> + struct kvm_io_device dev;
> +};
>

Prefix structure name with kvm_.

> +
> +#define int_output(s) (((struct pic_state2 *)s)->output)
>

This is a dangerous macro! It takes anything and treats it as a pic_state2.

Please remove.

> +struct pic_state2 *create_pic(struct kvm *kvm);
> +void pic_set_irq_new(void *opaque, int irq, int level);
> +int pic_read_irq(struct pic_state2 *s);
> +int cpu_get_interrupt(struct kvm_vcpu *v);
> +int cpu_has_interrupt(struct kvm_vcpu *v);
>

Prefix globally visible names with kvm_.

>
> +void enable_irq_window(struct kvm_vcpu *vcpu)
> +{
> + u32 cpu_based_vm_exec_control;
> +
> + cpu_based_vm_exec_control =
> vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
> + cpu_based_vm_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING;
> + vmcs_write32(CPU_BASED_VM_EXEC_CONTROL,
> cpu_based_vm_exec_control);
> +}
>

static.
> +
> +void do_intr_assist(struct kvm_vcpu *vcpu)
> +{
> + u32 idtv_info_field, intr_info_field;
> + int has_ext_irq, interrupt_window_open;
> + /* TODO: Move IDT_Vectoring here */
> +
> + has_ext_irq = cpu_has_interrupt(vcpu);
> + intr_info_field = vmcs_read32(VM_ENTRY_INTR_INFO_FIELD);
> + idtv_info_field = vmcs_read32(IDT_VECTORING_INFO_FIELD);
> + if (intr_info_field & INTR_INFO_VALID_MASK) {
> + if (idtv_info_field & INTR_INFO_VALID_MASK) {
> + /* TODO: fault when IDT_Vectoring */
> + printk(KERN_ERR "Fault when IDT_Vectoring\n");
> + }
> + if (has_ext_irq)
> + enable_irq_window(vcpu);
> + return;
> + }
> + if (unlikely(idtv_info_field & INTR_INFO_VALID_MASK)) {
> + vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field);
> + vmcs_write32(VM_ENTRY_INSTRUCTION_LEN,
> + vmcs_read32(VM_EXIT_INSTRUCTION_LEN));
> +
> + if ( unlikely(idtv_info_field & 0x800) ) /* valid error
> code */
> + vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE,
> + vmcs_read32(IDT_VECTORING_ERROR_CODE));
> + if ( unlikely(has_ext_irq) )
> + enable_irq_window(vcpu);
> + return;
> + }
>

This isn't Xen. No spaces inside if () condition.

>
> +/* for KVM_SET_IRQ_LEVEL */
> +struct kvm_irq_level {
> + __u32 irq;
> + __u32 level;
> +};
>

As discussed, we might want to make this a list, and add a chip ID so
this can be used for the ioapic too.

> +
> enum kvm_exit_reason {
> KVM_EXIT_UNKNOWN = 0,
> KVM_EXIT_EXCEPTION = 1,
> @@ -282,6 +288,9 @@ struct kvm_signal_mask {
> #define KVM_CREATE_VCPU _IO(KVMIO, 0x41)
> #define KVM_GET_DIRTY_LOG _IOW(KVMIO, 0x42, struct
> kvm_dirty_log)
> #define KVM_SET_MEMORY_ALIAS _IOW(KVMIO, 0x43, struct
> kvm_memory_alias)
> +/* Device model IOC */
> +#define KVM_CREATE_PIC _IO(KVMIO, 0x60)
> +#define KVM_SET_ISA_IRQ_LEVEL _IO(KVMIO, 0x61)
>
>

Need to add a way to detect if this functionality is available, via
KVM_CHECK_EXTENSION.

--
Do not meddle in the internals of kernels, for they are subtle and quick to panic.