• 虚拟机中断


    root@srv6:~# cat /proc/interrupts
               CPU0       CPU1       CPU2       CPU3       CPU4       CPU5       CPU6       CPU7       
      1:          0          0          0          0          0          0          9          0   IO-APIC   1-edge      i8042
      4:        442          0          0          0        319          0          0          0   IO-APIC   4-edge      ttyS0
      6:          0          3          0          0          0          0          0          0   IO-APIC   6-edge      floppy
      8:          0          0          0          0          0          0          0          0   IO-APIC   8-edge      rtc0
      9:          0          0          0          0          0          0          0          0   IO-APIC   9-fasteoi   acpi
     10:          0          4          0          0          0          0          0     317582   IO-APIC  10-fasteoi   virtio2
     11:          0          0          0          0         32          0          0          0   IO-APIC  11-fasteoi   uhci_hcd:usb1
     12:          0          0          0         65          0         16          0          0   IO-APIC  12-edge      i8042
     14:          0          0          0          0          0          0          0          0   IO-APIC  14-edge      ata_piix
     15:          0          0          0          0          0          0          0          0   IO-APIC  15-edge      ata_piix
     24:          0          0          0          0          0          0          0          0   PCI-MSI 49152-edge      virtio0-config
     25:          0          0          0    4891421          0          0          0          0   PCI-MSI 49153-edge      virtio0-input.0
     26:          0          0          0          0          2          1          0          0   PCI-MSI 49154-edge      virtio0-output.0
     27:          0          0          0          0          0          0          0          0   PCI-MSI 65536-edge      virtio1-config
     28:          0          0          0          0          0          0     179869          0   PCI-MSI 65537-edge      virtio1-req.0
    NMI:          0          0          0          0          0          0          0          0   Non-maskable interrupts
    LOC:   17533085   83660013    3207952    3922778    3037160    2753279    2791938    3814434   Local timer interrupts
    SPU:          0          0          0          0          0          0          0          0   Spurious interrupts
    PMI:          0          0          0          0          0          0          0          0   Performance monitoring interrupts
    IWI:          0          0          0          0          1          0          1          0   IRQ work interrupts
    RTR:          0          0          0          0          0          0          0          0   APIC ICR read retries
    RES:     450707     460430    1035940    1314558    1113145    1272738    1196648    1030938   Rescheduling interrupts
    CAL:      28063      34379      43082      31749      49105      50540      15045      36975   Function call interrupts
    TLB:         89         34        234         56        162        113         43         46   TLB shootdowns
    TRM:          0          0          0          0          0          0          0          0   Thermal event interrupts
    THR:          0          0          0          0          0          0          0          0   Threshold APIC interrupts
    DFR:          0          0          0          0          0          0          0          0   Deferred Error APIC interrupts
    MCE:          0          0          0          0          0          0          0          0   Machine check exceptions
    MCP:      10203      10203      10203      10203      10203      10203      10203      10203   Machine check polls
    HYP:          0          0          0          0          0          0          0          0   Hypervisor callback interrupts
    ERR:          0
    MIS:          0
    PIN:          0          0          0          0          0          0          0          0   Posted-interrupt notification event
    NPI:          0          0          0          0          0          0          0          0   Nested posted-interrupt event
    PIW:          0          0          0          0          0          0          0          0   Posted-interrupt wakeup event
    root@srv6:~# 

    目前操作系统使用的中断有io apic,MSI,还有就是NMI,LOC等。 继续执行cat /proc/ioports | grep pic

    root@srv6:~# cat /proc/ioports | grep pic
      0020-0021 : pic1
      00a0-00a1 : pic2

    实际上,主板上来连接这两颗pic设备,也就是两个i8259,分别是i8259 master和i8259 slave。对它们的访问使用pio(port io)即可。当guest访问8259的时候,vm会发生exit,虚拟的i8259响应guest的操作即可。 继续执行/proc/iomem | grep -i apic

    root@srv6:~# cat /proc/iomem | grep -i apic
    fec00000-fec003ff : IOAPIC 0
    fee00000-fee00fff : Local APIC
    root@srv6:~# 

    apic设备的访问可以使用mmio(memory mapped io)的方式进行。同时,如果支持x2apic也可以使用msr访问apic。 那么中断设备的关系如下:

    i8259每个pic可以产生8中irq,所以master产生的irq是从0-7,slave是8-15。 以i8042 kbd为例,在qemu-kvm的场景下,它会产生irq 1,所以它是由i8259 master产生的。 I8042 mouse,产生的irq是12,所以是i8259 slave产生的。 vda是virtio-blk,它是一个pci设备,它的中断是msi信号。 net0也是pci设备,中断也是msi信号。 2,irq routing 物理环境上,irq是由硬件产生的。在虚拟化下,却是由虚拟出来的。 kvm提供了set irq line这ioctl给user-mode调用,也提供了kvm_vm_ioctl_irq_line这样的函数在kernel-mode使用。 以键盘i8042 kbd为例,如果模拟一个键盘中断,即set irq 1.

    虚拟触发了irq 1,那么需要经过irq routing: irq 1在0-7的范围内,所以会路由到i8259 master,随后i8259 master会向vCPU注入中断。 同时,irq 1也会路由到io apic一份,io apic也会向lapic继续delivery。lapic继续向vCPU注入中断。 linux在启动阶段,检查到io apic后,会选择使用io apic。尽管经过irq routing产生了i8259 master和io apic两个中断,但是Linux选择io apic上的中断。 同理,如果是virtio-blk产生了中断,则路由到msi处理。

    3,apicv vcpu在setup阶段,如果支持apicv技术,将会配置EOI exit bitmap和posted interrupt等寄存器。在posted interrupt技术下,可以在不发生vm exit的情况注入中断,提高虚拟机的性能。 相关文档在intel的开发文档中《29.6 POSTED-INTERRUPT PROCESSING》中,对应的代码在linux-4.4/arch/x86/kvm/vmx.c中。

    4,pv eoi 经过posted interrupt技术优化后,注入irq不发生vm exit。但是guest在应答irq的时候,还是要发生vm exit。 所以有了pv eoi技术: a,guest和host通过msr寄存器,协商出来一个地址,用作eoi使用。前提是host和guest都支持pv eoi。 b,guest的pa,和host的va,通过映射计算,就是在操作同一块内存。 那么就不用发生vm exit的情况下,达到guest和host内外通信的目的。同样原理的还有kvm clock、steal time等。

    5,i8254 i8254就是irq 0的timer。在qemu-kvm中,可以通过用户态qemu实现,也可以通过内核态实现。默认使用内核态的实现。在host上执行ps,就可以看到[kvm-pit/1234]类似的进程,后面的数字是qemu进程的pid。kvm-pit线程是一个kthread worker线程,周期性的执行set irq 0,就可以在guest中周期性的发生中断。 Linux如果检测到LOC timer,就会选择停止i8254。停止i8254,kvm-pit停止周期性的注入中断,但是并不会退出。所以看到kvm-pit内核线程,但是它并不一定是在工作的。 如果在内核中加log,就会发现有趣的现象:在vm启动阶段,会有大量的注入中断的log;linux启动过程中,log就停止了。

     

     

    qemu通过kvm的ioctl命令KVM_CREATE_IRQCHIP调用到kvm内核模块中,在内核模块中创建和初始化PIC/IOAPIC设备(创建设备对应的数据结构并将设备注册到总线上)。

    kvm_arch_vm_ioctl(s, KVM_CREATE_IRQCHIP)
        |--> kvm_pic_init                    /* i8259 初始化 */
        |--> kvm_ioapic_init                 /* ioapic 初始化 */
        |--> kvm_setup_default_irq_routing   /* 初始化缺省的IRE */
    

    qemu在kvm内核中创建完成PIC和IOAPIC后将全局变量kvm_kernel_irqchip置为true,kvm模块则将kvm->arch.irqchip_mode 赋值为 KVM_IRQCHIP_KERNEL,这样后面的kvm_irqchip_in_kernel返回true表示pic芯片放到kvm内核模块中实现,kvm_ioapic_in_kernel也返回true表示ioapic放到kvm中来模拟。

    中断处理的逻辑放在kvm内核模块中进行实现,但设备的模拟呈现还是需要qemu设备模拟器来搞定,最后qemu和kvm一起配合完成快速中断处理的流程。

    i8259的设备创建流程(pic还是传统的isa设备,中断是边沿触发的,master的i/o port为0x20,0x21 slave的i/o port为0xa0,0xa1):

    machine_run_board_init
        |--> pc_init1
            |--> if (kvm_pic_in_kernel())
                |--> kvm_i8259_init
                    |--> isadev = isa_create(bus, name)
    

    ioapic的设备创建流程:

    machine_run_board_init
        |--> pc_init1
            |--> if (pcmc->pci_enabled)
                |--> ioapic_init_gsi(gsi_state, "i440fx")
                    |--> if kvm_ioapic_in_kernel()
                        |--> dev = qdev_create(NULL, "kvm-ioapic")
    

    PIC由2个i8259进行“级联”,一个为master一个为slave,每个i8259有8个PIN(salve的INT输出线连接到master的IRQ2引脚上,所以实际可用的IRQ数目为15)。目前kvm只为虚拟机创建一个ioapic设备(现在多路服务器可能有多个ioapic设备),ioapic设备提供24个PIN给外部中断使用。在IRQ路由上 0-15号GSI为PIC和IOAPIC共用的,16-23号GSI则都分配给ioapic。

    几个概念要理清楚:IRQ号,中断向量和GSI。

    • IRQ号是PIC时代引入的概念,由于ISA设备通常是直接连接到到固定的引脚,所以对于IRQ号描述了设备连接到了PIC的哪个引脚上,同IRQ号直接和中断优先级相关,例如IRQ0比IRQ3的中断优先级更高。
    • GSI号是ACPI引入的概念,全称是Global System Interrupt,用于为系统中每个中断源指定一个唯一的中断编号。注:ACPI Spec规定PIC的IRQ号必须对应到GSI0-GSI15上。kvm默认支持最大1024个GSI。
    • 中断向量是针对逻辑CPU的概念,用来表示中断在IDT表的索引号,每个IRQ(或者GSI)最后都会被定向到某个Vecotor上。对于PIC上的中断,中断向量 = 32(start vector) + IRQ号。在IOAPIC上的中断被分配的中断向量则是由操作系统分配。

    PIC主要针对与传统的单核处理器体系结构,在SMP系统上则是通过IOAPIC和每个CPU内部的LAPIC来构成整个中断系统的。

    如上图所描述,IOAPIC 负责接受中断并将中断格式化化成中断消息,并按照一定规则转发给LAPIC。LAPIC内部有IRR(Interrupt Reguest Register)和ISR(Interrupt Service Register)等2个重要寄存器。系统在处理一个vector的同时缓存着一个相同的vector,vector通过2个256-bit寄存器标志,对应位置位则表示上报了vector请求或者正在处理中。另外LAPIC提供了TPR(Task Priority Register),PPR(Processor Priority Register)来设置LAPIC的task优先级和CPU的优先级,当IOAPIC转发的终端vector优先级小于LAPIC设置的TPR时,此中断不能打断当前cpu上运行的task;当中断vector的优先级小于LAPIC设置的PPR时此cpu不处理这个中断。操作系统通过动态设置TPR和PPR来实现系统的实时性需求和中断负载均衡。

  • 相关阅读:
    SQL server中自定义排序
    安装nodejs版本模块报错notsup Unsupported platform for n
    vue项目中一些标签直接放在<template>下会报错Failed to compile with 1 errors
    vue中使用element-ui出现Couldn't find preset "es2015" relative to directory
    解决两个相邻的span,或者input和button中间有间隙,在css中还看不到
    VsCode中代码折叠快捷键
    npm 操作代码
    vue项目打包成html,在本地点击直接能打开
    地图只显示部分区域,其他地区不显示
    vs里颜色显示块怎样显示
  • 原文地址:https://www.cnblogs.com/dream397/p/13722928.html
Copyright © 2020-2023  润新知