天天看点

android qemu-kvm i8259 中断控制器虚拟设备初始化elcr的读写8259寄存器的读写如何通知CPU来了一个中断?apic,iopic,lapic是啥?结尾

8259主片的IRQ0~7对应INT 8~INT F,从片的IRQ8~IRQ15对应INT 70~INT 77。

8259是在pc_init1中初始化的,cpu_irq是8259的parent_irq:

qemu_allocate_irqs用来申请并设置qemu_irq结构体的:

i8259_init是8259的初始化函数,初始化了主从两片8259,iobase分别为0x20,0xa0,length都是2,宽度都是8bit。

elcr地址分别为0x4d0,0x4d1,分别对应两片8259,每一位对应一个irq,是控制边沿触发还是电平触发的,置1时是电平触发,elcr_mask是因为有些irq不支持电平触发,所以需要mask。

最后申请了GFD_MAX_IRQ个,也就是16个qemu_irq结构体:

pic_init1用来真正初始化每一片8259的,绑定了寄存器和读写函数,qemu_register_reset把寄存器的复位函数放到链表里:

elcr的读写函数非常简单,稍微注意下mask的使用就行了:

8259的写函数为pic_ioport_write,因为每片就两个寄存器,addr不是0就是1,所以addr &= 1。

ICW1地址为0,ICW2~4地址为1;OCW2~3地址为0,OCW1地址为1。

需要注意地址的复用如何处理,ICW的指令是用于初始化的,先往地址0写ICW1,然后往地址1写剩下的几个ICW指令,具体写的是哪个,由状态机init_state来确定。

初始化完毕后才可以写入OCW指令。

ICW1,OCW2,OCW3复用地址0,是根据val中的特殊位来区分的。初始化完毕后,地址1仅仅对应OCW1。

OCW2需要详细说明下:

1、中断优先级:每片8259由irq0~irq7共计8个中断输入,默认情况下irq0优先级最高,irq7优先级最低,同时发生中断请求时,优先级高的先处理,在嵌套模式下,优先级高的还可以打断优先级低的中断服务程序的执行。

2、循环优先级:这次优先级最高的是0,下一次中断时,优先机最高的轮到1,然后轮到2......,到7,然后再到0。

3、SL用来设置一个偏移量的,加上这个偏移并对8取模后再比较优先级。

寻找这片8259的优先级最高的中断,mask就是isr,需要考虑优先级循环和SL设置的偏移对优先级的影响。

没有中断时返回8。

priority_add综合了自动循环和SL设置的东西的因素,对优先级进行调整。

更新中断的状态,如果有中断请求,那么qemu_irq_raise请求parent_irq,也就是cpu_irq,去对CPU产生中断请求

irr中断请求,isr中断服务。经过irr后才能到isr。irr表示请求中断,isr表示正在处理的中断。

设置中断请求寄存器irr

8259的读函数为pic_ioport_read

qemu_set_irq用来设置中断请求,会调用申请qemu_irq时设置的handler函数,对于cpu_irq来说,handler是pic_irq_request;对于8259来说,handler是i8259_set_irq

pic_irq_request会设置cpu->interrupt_request |= CPU_INTERRUPT_HARD。

i8259_set_irq最终也会调用到pic_irq_request函数。

cpu_interrupt注入的中断,会在kvm_arch_pre_run中进行处理。根据cpu->interrupt_request的设置,会调用kvm_vcpu_ioctl(cpu, KVM_INTERRUPT, &intr):

kvm_arch_pre_run会在kvm_cpu_exec的循环中执行的,每次退出kvm内核态,重新kvm_run之前会调用这个。所以中断的注入并不是实时的,需要等kvm退出后,才能够进行真正的注入:

APIC(Advanced Programmable Interrupt Controller)取代了8259,成为目前标准的中断控制器,包括了两部分: iopic和lapic,iopic接设备,每个cpu都有lapic。iopic把中断请求发给lapic。

APIC方式下,支持更多的中断,无需使用中断共享。

android goldfish platform bus的中断控制器在guest为x86时不启用的。

现在qemu的8259都是使用了QOM模型了,这个模型太TMD的复杂了。另外hw/i386/kvm/timer/i8259.c中提供了kvm版本的8259,使用kvm提供的内核态的8259的模拟,中断的处理和IO的读写都在内核态,不需要退出kvm了,速度要更快些,有提供了内核态的apic的模拟。类似的,8254之类的也有kvm内核态的实现,所以说android emulator的性能还是有提升空间的。

继续阅读