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的性能還是有提升空間的。