xen-gic初始化流程

xen-gic初始化流程

调试平台使用的是gic-600,建议参考下面的文档来阅读代码,搞清楚相关寄存器的功能。

  1. 《corelink_gic600_generic_interrupt_controller_technical_reference_manual_100336_0106_00_en》

  2. 《IHI0069H_gic_architecture_specification》

一、xen-gic代码分析

1. core0流程

start_xen......init_traps();WRITE_SYSREG(HCR_AMO | HCR_FMO | HCR_IMO, HCR_EL2);	/* 让A/F/I异常都在EL2去执行,每个cpu都会这样设置 */......
--->init_IRQ(); /* 初始化每个中断号的中断描述符信息 */for ( irq = 0; irq < NR_LOCAL_IRQS; irq++ ) /* NR_LOCAL_IRQS = 32,这里的local irq是包含了SGI以及PPI */local_irqs_type[irq] = IRQ_TYPE_INVALID;init_local_irq_data /* 初始化每个local irq的desc结构体(从处理流程上看,对于gic的每个中断源,系统分配一个irq_desc数据结构与之对应) */struct irq_desc *desc = irq_to_desc(irq);for ( irq = 0; irq < NR_LOCAL_IRQS; irq++ ){init_one_irq_desc(desc);desc->status = IRQ_DISABLED; /* 初始化中断状态 */desc->handler = &no_irq_type; /* 初始化中断处理函数 */cpumask_setall(desc->affinity);	/* 初始化中断亲和度 */desc->arch.type = IRQ_TYPE_INVALID; /* 初始化中断类型 */desc->irq = irq; /* 初始化中断号 */desc->action  = NULL;desc->arch.type = local_irqs_type[irq]; /* 初始化中断类型,统一设置为IRQ_TYPE_INVALID */}init_irq_data /* 初始化流程与init_local_irq_data类似 *//* NR_LOCAL_IRQS = 32,NR_IRQ = 1024,初始化中断号为32~1024的desc结构体 */for ( irq = NR_LOCAL_IRQS; irq < NR_IRQS; irq++ ){init_one_irq_desc(desc);desc->irq = irq;desc->action  = NULL;}......
--->gic_preinit(); /* gic初始化的前期准备 */gic_dt_preinit(); /* Find the interrupt controller and set up the callback to translate device tree */device_init(node, DEVICE_GIC, NULL);return desc->init(dev, data); /* 调试环境用的是gicv3,因此这里执行gicv3_dt_preinit */gicv3_info.hw_version = GIC_V3;gicv3_info.node = node; /* gicv3 dtb节点 */register_gic_ops(&gicv3_ops);dt_irq_xlate = gic_irq_xlate;....../* Set the GIC as the primary interrupt controller */dt_interrupt_controller = node;dt_device_set_used_by(node, DOMID_XEN); /* 该gic节点被xen使用 */......
--->gic_init();--->gic_hw_ops->init(); /* 执行gicv3_init */--->gicv3_dt_init();dt_device_get_address(node, 0, &dbase, NULL); /* 获取设备树中关于distributor的mmio地址,存放在dbase */gicv3_ioremap_distributor(dbase); /* 映射distributor的mmio地址 */gicv3.map_dbase = ioremap_nocache(dist_paddr, SZ_64K);if ( !dt_property_read_u32(node, "#redistributor-regions", &gicv3.rdist_count) )gicv3.rdist_count = 1;	/* sunxi的设备树没有“#redistributor-regions”属性,所以这里默认就是1 */for ( i = 0; i < gicv3.rdist_count; i++ ){dt_device_get_address(node, 1 + i, &rdist_base, &rdist_size); /* 获取gicv3的redistributor的mmio地址 */rdist_regs[i].base = rdist_base;rdist_regs[i].size = rdist_size;}gicv3.rdist_stride = 0; /* sunxi的设备树没有“redistributor-stride”属性,所以这里默认就是0 */gicv3.rdist_regions= rdist_regs; /* 保存redistributor的地址信息 */res = platform_get_irq(node, 0); /* 获取gicv3的Maintenence中断号(经过translate) */gicv3_info.maintenance_irq = res;/* sunxi的phy cpu interface以及virt cpu interface都是使用系统寄存器的方式来实现,不走mmio,所以下面的代码逻辑无效 */res = dt_device_get_address(node, 1 + gicv3.rdist_count, &cbase, &csize);if ( !res )dt_device_get_address(node, 1 + gicv3.rdist_count + 2, &vbase, &vsize);--->for ( i = 0; i < gicv3.rdist_count; i++ )/* 映射redistributor的mmio地址 */gicv3.rdist_regions[i].map_base = ioremap_nocache(gicv3.rdist_regions[i].base,  gicv3.rdist_regions[i].size);/* 读取Interrupt Controller Type Register的bit23~19(Interrupt identifier bits) */--->reg = readl_relaxed(GICD + GICD_TYPER);--->intid_bits = GICD_TYPE_ID_BITS(reg); /* The maximum number of INTIDs that the GIC implementation supports. */--->vgic_v3_setup_hw(dbase, gicv3.rdist_count, gicv3.rdist_regions, intid_bits); /* 初始化vgic_v3_hw结构体 */vgic_v3_hw.dbase = dbase;......--->gicv3_dist_init();writel_relaxed(0, GICD + GICD_CTLR); /* Disable the distributor */type = readl_relaxed(GICD + GICD_TYPER);/*获取GICD_TYPER的bit4~0(ITLineNumber, Number of SPIs divided by 32表示最大支持的spi数量:max num = 32*(N+1)*/nr_lines = 32 * ((type & GICD_TYPE_LINES) + 1);if ( type & GICD_TYPE_LPIS )gicv3_lpi_init_host_lpis(GICD_TYPE_ID_BITS(type));/* Only 1020 interrupts are supported */nr_lines = min(1020U, nr_lines);gicv3_info.nr_lines = nr_lines;printk("GICv3: %d lines, (IID %8.8x).\n", nr_lines, readl_relaxed(GICD + GICD_IIDR));/* (XEN) GICv3: 288 lines, (IID 0201643b). *//* 设置所有的spi中断为低电平触发 *//* 每个中断有2个bits设置,1个寄存器包含16个中断的配置 */for ( i = NR_GIC_LOCAL_IRQS; i < nr_lines; i += 16 )writel_relaxed(0, GICD + GICD_ICFGR + (i / 16) * 4);/* 配置默认的中断优先级为0xa0每个中断有8个bits设置,1个寄存器包含4个中断的配置#define GIC_PRI_LOWEST     0xf0#define GIC_PRI_IRQ        0xa0#define GIC_PRI_IPI        0x90#define GIC_PRI_HIGHEST    0x80 /* Higher priorities belong to Secure-World */*/for ( i = NR_GIC_LOCAL_IRQS; i < nr_lines; i += 4 ){priority = (GIC_PRI_IRQ << 24 | GIC_PRI_IRQ << 16 | GIC_PRI_IRQ << 8 | GIC_PRI_IRQ);writel_relaxed(priority, GICD + GICD_IPRIORITYR + (i / 4) * 4);}/* 禁用/停用所有spi中断 */for ( i = NR_GIC_LOCAL_IRQS; i < nr_lines; i += 32 ){/* If written, disables forwarding of the corresponding interrupt */writel_relaxed(0xffffffff, GICD + GICD_ICENABLER + (i / 32) * 4);/* If written, deactivates the corresponding interrupt */writel_relaxed(0xffffffff, GICD + GICD_ICACTIVER + (i / 32) * 4);}/* 将 SPI 配置为非安全组 1(non-secure Group-1) */for ( i = NR_GIC_LOCAL_IRQS; i < nr_lines; i += 32 )writel_relaxed(GENMASK(31, 0), GICD + GICD_IGROUPR + (i / 32) * 4);gicv3_dist_wait_for_rwp(); /* 判断前面的寄存器值是否完成写入 *//* 使能distributor模块 */writel_relaxed(GICD_CTL_ENABLE | GICD_CTLR_ARE_NS | GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1, GICD + GICD_CTLR);/* Route all global IRQs to this CPU *//* MPIDR_EL1(Multi-Processor Affinity Register),通常aff0代表在cluster内部的core ID,aff1代表cluster ID */affinity = gicv3_mpidr_to_affinity(smp_processor_id()); /* 读取核号(Core ID) *//*Interrupt_Routing_Mode, bit [31]0b0 	Interrupts routed to the PE specified by a.b.c.d. In this routing, a, b, c, and d are thevalues of fields Aff3, Aff2, Aff1, and Aff0 respectively0b1 	Interrupts routed to any PE defined as a participating node设置中断只路由到对应的PE*/affinity &= ~GICD_IROUTER_SPI_MODE_ANY;/* 配置GICD_IROUTER寄存器,让中断路由到当前core ID对应的核 */for ( i = NR_GIC_LOCAL_IRQS; i < nr_lines; i++ )writeq_relaxed(affinity, GICD + GICD_IROUTER + i * 8);--->gicv3_cpu_init();--->gicv3_populate_rdist();uint64_t mpidr = cpu_logical_map(smp_processor_id()); /* 读取当前core的mpidr寄存器 *//* 转换mpidr的affinity值为一个32bit数据 */aff = (MPIDR_AFFINITY_LEVEL(mpidr, 3) << 24 |MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16 |MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8 |MPIDR_AFFINITY_LEVEL(mpidr, 0));for ( i = 0; i < gicv3.rdist_count; i++ ){void __iomem *ptr = gicv3.rdist_regions[i].map_base; /* redistributor映射后的虚拟地址 */readl_relaxed(ptr + GICR_PIDR2) & GIC_PIDR2_ARCH_MASK;do {typer = readq_relaxed(ptr + GICR_TYPER);/* GICR_TYPER的bits [63:32]与aff进行比较,一致则代表当前core与该redistributor是一组的 */if ( (typer >> 32) == aff ){this_cpu(rbase) = ptr; /* 设置per_cpu__rbase变量 */if ( typer & GICR_TYPER_PLPIS ){rdist_addr = gicv3.rdist_regions[i].base;rdist_addr += ptr - gicv3.rdist_regions[i].map_base;procnum = (typer & GICR_TYPER_PROC_NUM_MASK);procnum >>= GICR_TYPER_PROC_NUM_SHIFT;gicv3_set_redist_address(rdist_addr, procnum);this_cpu(lpi_redist).redist_addr = address;this_cpu(lpi_redist).redist_id = redist_id;gicv3_lpi_init_rdist(ptr);gicv3_lpi_allocate_pendtable(&table_reg); /* 分配lpi中断的pending table */writeq_relaxed(table_reg, rdist_base + GICR_PENDBASER);gicv3_lpi_set_proptable(rdist_base);}}}}    --->gicv3_enable_redist();s_time_t deadline = NOW() + MILLISECS(1000);/* 唤醒当前cpu的redistributor */val = readl_relaxed(GICD_RDIST_BASE + GICR_WAKER);/*0b0 	This PE is not in, and is not entering, a low power state 0b1 	The PE is either in, or is in the process of entering, a low power state*/val &= ~GICR_WAKER_ProcessorSleep;writel_relaxed(val, GICD_RDIST_BASE + GICR_WAKER);do {val = readl_relaxed(GICD_RDIST_BASE + GICR_WAKER);/*判断连接的PE是否处于静默状态0b0 	An interface to the connected PE might be active.0b1		All interfaces to the connected PE are quiescen*/if ( !(val & GICR_WAKER_ChildrenAsleep) )break;if ( NOW() > deadline ){timeout = true;break;}cpu_relax();udelay(1);} while ( timeout );/* 设置PPI(IPI)中断的优先级为0x90 */--->priority = (GIC_PRI_IPI << 24 | GIC_PRI_IPI << 16 | GIC_PRI_IPI << 8 | GIC_PRI_IPI);for (i = 0; i < NR_GIC_SGI; i += 4)writel_relaxed(priority, GICD_RDIST_SGI_BASE + GICR_IPRIORITYR0 + (i / 4) * 4);/* 设置SGI中断的优先级为0xa0 */priority = (GIC_PRI_IRQ << 24 | GIC_PRI_IRQ << 16 | GIC_PRI_IRQ << 8 | GIC_PRI_IRQ);for (i = NR_GIC_SGI; i < NR_GIC_LOCAL_IRQS; i += 4)writel_relaxed(priority, GICD_RDIST_SGI_BASE + GICR_IPRIORITYR0 + (i / 4) * 4);/* 设置所有的SGI以及PPI中断为de-activated */writel_relaxed(0xffffffff, GICD_RDIST_SGI_BASE + GICR_ICACTIVER0);/* disable所有PPI中断,使能所有SGI中断 */writel_relaxed(0xffff0000, GICD_RDIST_SGI_BASE + GICR_ICENABLER0); /* Interrupt Clear-Enable Register 0 */writel_relaxed(0x0000ffff, GICD_RDIST_SGI_BASE + GICR_ISENABLER0); /* Interrupt Set-Enable Register 0 *//* 设置所有的SGI以及PPI中断为非安全组1 */writel_relaxed(GENMASK(31, 0), GICD_RDIST_SGI_BASE + GICR_IGROUPR0);gicv3_enable_sre();/* System Register Enable (SRE) *//* 允许在EL2访问CPU & Virtual interface的系统寄存器 */WRITE_SYSREG(val, ICC_SRE_EL2);/* 设置为没有优先级分组 */WRITE_SYSREG(0, ICC_BPR1_EL1);/*设置Interrupt Priority Mask寄存器的bit[7:0]为0xff如果中断的优先级比这里设置的值要大的话,则cpu或者vcpu interface会拉起irq line,通知PE(作用类似于一个滤波器)*/WRITE_SYSREG(DEFAULT_PMR_VALUE, ICC_PMR_EL1);/*设置EOI mode,需要操作EOI以及DIR寄存器来完成一次中断响应:EOI:优先级降权DIR:中断无效*/WRITE_SYSREG(GICC_CTLR_EL1_EOImode_drop, ICC_CTLR_EL1);/* 使能group1的中断 */WRITE_SYSREG(1, ICC_IGRPEN1_EL1);--->gicv3_hyp_init();vtr = READ_SYSREG(ICH_VTR_EL2); /* gic虚拟化特性 */gicv3_info.nr_lrs  = (vtr & ICH_VTR_NRLRGS) + 1; /* 获取支持的LR registers的数量 */gicv3.nr_priorities = ((vtr >> ICH_VTR_PRIBITS_SHIFT) & ICH_VTR_PRIBITS_MASK) + 1; /* 获取实现的虚拟优先级位数 *//*ICH_VMCR_EOI(bit9) 0b1 Virtual EOI mode,需要操作EOI以及DIR寄存器来完成一次中断响应ICV_EOIR0_EL1 and ICV_EOIR1_EL1 provide priority drop functionality only. ICV_DIR_EL1 provides interrupt deactivation functionalityICH_VMCR_VENG1(bit1): 0b1 Virtual Group 1 interrupts are enabled*/WRITE_SYSREG(ICH_VMCR_EOI | ICH_VMCR_VENG1, ICH_VMCR_EL2); /* 具体含义参照下图 *//*Enable. Global enable bit for the virtual CPU interface0b0 	Virtual CPU interface operation disabled0b1 	Virtual CPU interface operation enable*/WRITE_SYSREG(GICH_HCR_EN, ICH_HCR_EL2); /* 使能vcpu interface */--->clear_cpu_lr_mask(); /* Clear LR mask for cpu0 */this_cpu(lr_mask) = 0ULL;......
--->init_maintenance_interrupt(); /* 注册gic controller的中断服务函数 */request_irq(gic_hw_ops->info->maintenance_irq, 0, maintenance_interrupt, "irq-maintenance", NULL);......
--->local_irq_enable();/* DAIFClr D, A, I, F Directly clears any of the PSTATE.{D, A, I, F} bits to 0 *//* 清除PSTATE的相关中断mask bit */asm volatile ( "msr daifclr, #2\n" ::: "memory" )

在这里插入图片描述

2. smp流程

start_xen......for_each_present_cpucpu_up(i)__cpu_up(cpu);arch_cpu_up(cpu);smp_enable_ops[cpu].prepare_cpu(cpu); //多核启动使用psci的方式,这里执行call_psci_cpu_on--->arm_smccc_smc(psci_cpu_on_nr, cpu_logical_map(cpu), __pa(virt_boot_xen((vaddr_t)init_secondary)), &res); 
init_secondarystart_secondaryinit_traps();WRITE_SYSREG(HCR_AMO | HCR_FMO | HCR_IMO, HCR_EL2); /* 让A/F/I异常都在EL2去执行,每个cpu都会这样设置 */......gic_init_secondary_cpu();gic_hw_ops->secondary_init(); /* 执行gicv3_secondary_cpu_init */--->gicv3_secondary_cpu_initgicv3_cpu_init();gicv3_hyp_init();clear_cpu_lr_mask(); /* Clear LR mask for secondary cpus */init_secondary_IRQ();init_local_irq_data();local_irq_enable();

smp初始化gic的流程和core0的是一致的,具体参考上一章节即可。

3. 问题

questionanswer
1.在xen代码的gicv3_dist_init中,把所有的spi中断都路由到了core0,那其他的core怎么响应中断呢?在注册对应中断的时候会调用gicv3_irq_set_affinity接口重新设置中断路由(目前irq_set_affinity使用时设置的cpu都是随机的,没有考虑指定cpu)

二、dom-gic代码分析

1. dom create分支

create_domUs
--->dt_for_each_child_node(chosen, node){struct domain *d;--->d = domain_create(++max_init_domid, &d_cfg, flags);arch_domain_create(d, config, flags);......domain_vgic_register(d, &count)vgic_v3_init(d, mmio_count);register_vgic_ops(d, &v3_ops);domain_vgic_init(d, config->arch.nr_spis); /* nr_spis = gic_hw_ops->info->nr_lines - 32 *//* Limit the number of virtual SPIs supported to (1020 - 32) = 988  */if ( nr_spis > (1020 - NR_LOCAL_IRQS) )return -EINVAL;d->arch.vgic.nr_spis = nr_spis;d->arch.vgic.shared_irqs = xzalloc_array(struct vgic_irq_rank, DOMAIN_NR_RANKS(d));d->arch.vgic.pending_irqs = xzalloc_array(struct pending_irq, d->arch.vgic.nr_spis);for (i=0; i<d->arch.vgic.nr_spis; i++)vgic_init_pending_irq(&d->arch.vgic.pending_irqs[i], i + 32); /* 从32开始赋值给vgic.pending_irqs[i]->irq *//* SPIs are routed to VCPU0 by default */for ( i = 0; i < DOMAIN_NR_RANKS(d); i++ )vgic_rank_init(&d->arch.vgic.shared_irqs[i], i + 1, 0);d->arch.vgic.handler->domain_init(d); /* 执行vgic_v3_domain_init *//* Allocate memory for Re-distributor regions */rdist_count = vgic_v3_max_rdist_count(d);rdist_regions = xzalloc_array(struct vgic_rdist_region, rdist_count);d->arch.vgic.nr_regions = rdist_count;d->arch.vgic.rdist_regions = rdist_regions;radix_tree_init(&d->arch.vgic.pend_lpi_tree);if ( domain_use_host_layout(d) ) /* 目前使用的是Direct-mapped,走这个分支 */{d->arch.vgic.dbase = vgic_v3_hw.dbase; /* 设置vgic的Distributor基地址 */for ( i = 0; i < vgic_v3_hw.nr_rdist_regions; i++ ){d->arch.vgic.rdist_regions[i].base = vgic_v3_hw.regions[i].base; /* 设置vgic的Redistributor基地址 *//* Set the first CPU handled by this region */d->arch.vgic.rdist_regions[i].first_cpu = first_cpu;}d->arch.vgic.intid_bits = vgic_v3_hw.intid_bits;}else......vgic_v3_its_init_domain(d);/* 为Distributor注册mmio处理函数 */register_mmio_handler(d, &vgic_distr_mmio_handler, d->arch.vgic.dbase, SZ_64K, NULL);/* 为Redistributor注册mmio处理函数 */for ( i = 0; i < d->arch.vgic.nr_regions; i++ ){struct vgic_rdist_region *region = &d->arch.vgic.rdist_regions[i];register_mmio_handler(d, &vgic_rdistr_mmio_handler, region->base, region->size, region);}

2. domain construct分支

create_domUs......--->construct_domU(d, node);......prepare_dtb_domU(d, &kinfo);--->domain_handle_dtb_bootmodule(d, kinfo);--->if ( dt_node_cmp(name, "gic") == 0 ) /* 不存在,后续由xen创建虚拟gic节点 */{kinfo->phandle_gic = fdt_get_phandle(pfdt, node_next);continue;}--->if ( dt_node_cmp(name, "passthrough") == 0 )scan_pfdt_node(kinfo, pfdt, node_next, DT_ROOT_NODE_ADDR_CELLS_DEFAULT, DT_ROOT_NODE_SIZE_CELLS_DEFAULT, true);--->handle_prop_pfdt(kinfo, pfdt, nodeoff, address_cells, size_cells, scan_passthrough_prop);--->handle_passthrough_prop(kinfo, xen_reg, xen_path, xen_force, cacheable, address_cells, size_cells);--->handle_device_interrupts(kinfo->d, node, true); /* 核心 */struct dt_raw_irq rirq;nirq = dt_number_of_irq(dev); /* 获取中断数量 */for ( i = 0; i < nirq; i++ ){dt_device_get_raw_irq(dev, i, &rirq);res = platform_get_irq(dev, i); /* 获取中断号,需要调试确认该值!!!! */map_irq_to_domain(d, res, need_mapping, dt_node_name(dev));irq_permit_access(d, irq);vgic_reserve_virq(d, irq);route_irq_to_guest(d, irq, irq, devname); /* 将IRQ路由到指定的guest OS */}--->make_gic_domU_node(kinfo);make_gicv3_domU_node(kinfo); /* 给dom的设备树创建gic节点 */vgic_dist_base(&d->arch.vgic);return vgic->vgic_dist_base;dt_child_set_range(&cells, GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_CELLS, vgic_dist_base(&d->arch.vgic), GUEST_GICV3_GICD_SIZE);for ( i = 0; i < d->arch.vgic.nr_regions; i++)dt_child_set_range(&cells, GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_CELLS, d->arch.vgic.rdist_regions[i].base, d->arch.vgic.rdist_regions[i].size);}

3. distributor的mmio处理

/* xen/arch/arm/vgic-v3.c */
static int vgic_v3_distr_mmio_write(struct vcpu *v, mmio_info_t *info, register_t r, void *priv)int gicd_reg = (int)(info->gpa - v->domain->arch.vgic.dbase);switch ( gicd_reg ){case VREG32(GICD_CTLR):{vreg_reg32_update(&ctlr, r, info);vreg_reg_update/* Only EnableGrp1A can be changed *//*Enable Non-secure Group 1 interrupts0b1 	Non-secure Group 1 interrupts are enabled*/if ( ctlr & GICD_CTLR_ENABLE_G1A )v->domain->arch.vgic.ctlr |= GICD_CTLR_ENABLE_G1A;elsev->domain->arch.vgic.ctlr &= ~GICD_CTLR_ENABLE_G1A;                }......case VRANGE32(GICD_IGROUPR, GICD_IGROUPRN): /* 无效 */case VRANGE32(GICD_ISENABLER, GICD_ISENABLERN):case VRANGE32(GICD_ICENABLER, GICD_ICENABLERN):case VRANGE32(GICD_ISPENDR, GICD_ISPENDRN):case VRANGE32(GICD_ICPENDR, GICD_ICPENDRN):case VRANGE32(GICD_ISACTIVER, GICD_ISACTIVERN): /* 无效 */case VRANGE32(GICD_ICACTIVER, GICD_ICACTIVERN): /* 无效 */case VRANGE32(GICD_IPRIORITYR, GICD_IPRIORITYRN):case VRANGE32(GICD_ICFGR, GICD_ICFGRN):/* Above registers are common with GICR and GICD Manage in common */return __vgic_v3_distr_common_mmio_write("vGICD", v, info, gicd_reg, r);......case VRANGE64(GICD_IROUTER32, GICD_IROUTER1019):{uint64_t irouter;if ( !vgic_reg64_check_access(dabt) ) goto bad_width;rank = vgic_rank_offset(v, 64, gicd_reg - GICD_IROUTER, DABT_DOUBLE_WORD);if ( rank == NULL )goto write_ignore;vgic_lock_rank(v, rank, flags);irouter = vgic_fetch_irouter(rank, gicd_reg - GICD_IROUTER); /* 获取vaff */vreg_reg64_update(&irouter, r, info);vgic_store_irouter(v->domain, rank, gicd_reg - GICD_IROUTER, irouter);new_vcpu = vgic_v3_irouter_to_vcpu(d, irouter);/** When the Interrupt Route Mode is set, the IRQ targets any vCPUs.* For simplicity, the IRQ is always routed to vCPU0.*/if ( irouter & GICD_IROUTER_SPI_MODE_ANY )return d->vcpu[0];vcpu_id = vaffinity_to_vcpuid(irouter);if ( vcpu_id >= d->max_vcpus )return NULL;return d->vcpu[vcpu_id];old_vcpu = d->vcpu[read_atomic(&rank->vcpu[offset])];/* Only migrate the IRQ if the target vCPU has changed */if ( new_vcpu != old_vcpu ){if ( vgic_migrate_irq(old_vcpu, new_vcpu, virq) ) /* 当前vcpu和旧的vcpu不一致时,进行中断迁移 */write_atomic(&rank->vcpu[offset], new_vcpu->vcpu_id);}vgic_unlock_rank(v, rank, flags);return 1;}......}

4. redistributor的mmio处理

三、涉及到的寄存器

RegisterDisciption
GICD_TYPERRedistributor Type Register,提供关于此Redistributor的配置信息
GICD_CTLR
GICD_IIDR
GICD_ICFGR
GICD_IPRIORITYRInterrupt Priority Registers,保存相应中断的优先级
GICD_ICENABLERInterrupt Clear-Enable Registers,禁止将相应的中断转发到 CPU 接口
GICD_ICACTIVERInterrupt Clear-Active Registers,取消相应的中断。这些寄存器用于保存和恢复GIC状态
GICD_IGROUPRInterrupt Group Registers,控制对应的中断是在Group-0还是Group-1中
GICD_IROUTERInterrupt Routing Registers,
GICR_PIDR2Peripheral ID2 Register,获取GIC版本
GICR_PENDBASER
GICR_WAKERRedistributor Wake Register,允许软件控制与Redistributor对应的WakeRequest电源管理信号的行为
ICH_VTR_EL2Interrupt Controller VGIC Type Register,记录了支持的GIC虚拟化特性
ICH_VMCR_EL2Interrupt Controller Virtual Machine Control Register,允许hypervisor保存和恢复虚拟机的GIC state
ICH_HCR_EL2Interrupt Controller Hyp Control Register,虚拟机环境控制
GICR_PIDR2
GICR_TYPER
GICR_TYPER_PLPIS
GICR_TYPER_VLPIS
GICR_TYPER_LAST
GICR_WAKER
GICR_IPRIORITYR0
GICR_ICACTIVER0
GICR_ICENABLER0
GICR_ISENABLER0
GICR_IGROUPR0
ICC_SRE_EL2
ICC_BPR1_EL1
ICC_PMR_EL1
ICC_CTLR_EL1
ICC_IGRPEN1_EL1
ICH_VTR_EL2
ICH_VMCR_EL2
ICH_HCR_EL2
ICV_EOIR0_EL1
ICV_DIR_EL1

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/81005.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【flink进阶】-- Flink kubernetes operator 版本升级

目录 1、检查当前 flink kubernetes operator 版本 2、停止生产上正在运行的 flink job 3、升级 CRD

linux万字图文学习进程信号

1. 信号概念 信号是进程之间事件异步通知的一种方式&#xff0c;属于软中断。 1.1 linux中我们常用Ctrlc来杀死一个前台进程 1. Ctrl-C 产生的信号只能发给前台进程。一个命令后面加个&可以放到后台运行,这样Shell不必等待进程结束就可以接受新的命令,启动新的进程。2. S…

简单记录一下Splunk ES 升级

1: 背景: 现在有些app 产品对splunk ES (enterprise security) 的版本有要求,这个就要求splunk ES 随着Splunk enterprise 也一起升级,下面先列一下各个版本的兼容: Splunk products version compatibility matrix - Splunk Documentation 下面列出的8.2.11 的版本: 2:…

day38 代码回想录 斐波那契数爬楼梯使用最小花费爬楼梯

大纲 ● 理论基础 ● 509. 斐波那契数 ● 70. 爬楼梯 ● 746. 使用最小花费爬楼梯 509. 斐波那契数 题目&#xff1a;509. 斐波那契数 // 斐波那契数列 // 动规 5部曲 // 1 dp[i]代表i处的斐波那契值 // 2 递归公式&#xff1a;dp[0] 0, dp[1]1, dp[i]dp[i-1]dp[i-2] // 3…

9月16日,每日信息差

今天是2023年09月16日&#xff0c;以下是为您准备的15条信息差 第一、天猫超市首单“茅小凌”已由菜鸟送达&#xff0c;首单已由菜鸟供应链完成履约&#xff0c;18分钟送达消费者手中 第二、软银考虑对OpenAI进行投资。此外&#xff0c;软银还初步拟收购英国人工智能芯片制造…

FE_Vue学习笔记 - 数据代理

Vue中的数据代理是一种机制&#xff0c;通过它&#xff0c;Vue实例&#xff08;vm&#xff09;可以代理其数据对象&#xff08;data&#xff09;中的属性操作。这种代理的原理主要是通过Object.defineProperty()方法&#xff0c;将data对象的每个属性都添加到vm对象上&#xff…

uni-app 实现自定义按 A~Z 排序的通讯录(字母索引导航)

创建 convertPinyin.js 文件 convertPinyin.js 将下面的内容复制粘贴到其中 const pinyin (function() {let Pinyin function(ops) {this.initialize(ops);},options {checkPolyphone: false,charcase: "default"};Pinyin.fn Pinyin.prototype {init: functi…

C语言希尔排序

希尔排序&#xff08;Shell Sort&#xff09;是插入排序的一种&#xff0c;也称缩小增量排序&#xff0c;是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。 希尔排序的基本思想是&#xff1a;先将整个待排序的记录序列分割成为若干子序列&#xff08;由…

解决Agora声网音视频在后台没有声音的问题

前言:本文会介绍 Android 与 iOS 两个平台的处理方式 一、Android高版本在应用退到后台时,系统为了省电会限制应用的后台活动,因此我们需要开启一个前台服务,在前台服务中发送常驻任务栏通知,以此来保证App 退到后台时不会被限制活动. 前台服务代码如下: package com.notify…

Limit分页遇到百万级数据该何去何从

一、Limit分页基础 mysql使用查询语句的时候&#xff0c;经常要返回前几条或者中间某几行数据&#xff0c;也就是我们说的分页&#xff0c;语法如下&#xff1a; SELECT * FROM table LIMIT offset,lengthLIMIT 子句可以被用于强制 SELECT 语句返回指定的记录数。LIMIT 接受一…

TCP详解之滑动窗口

TCP详解之滑动窗口 引入窗口概念的原因 我们都知道 TCP 是每发送一个数据&#xff0c;都要进行一次确认应答。当上一个数据包收到了应答了&#xff0c; 再发送下一个。 这个模式就有点像我和你面对面聊天&#xff0c;你一句我一句。但这种方式的缺点是效率比较低的。 如果你…

git中无法使用方向键的问题

windows下使用git命令行执行react脚本安装&#xff0c;发现无法使用上下键来去选中选项。最后只能换成cmd命令执行&#xff0c;发现可以上下移动以选中需要的选项。 bash命令行&#xff1a;移动光标无法移动选项 cmd命令行

算法宝典1——Java版本(此系列持续更新,这篇文章有20道)(有题目的跳转链接)(此份宝典包含了链表、栈、队列、二叉树的算法题)

注&#xff1a;由于字数的限制&#xff0c;我打算把算法宝典做成一个系列&#xff0c;一篇文章就20题&#xff01;&#xff01;&#xff01; 目录 一、链表的算法题&#xff08;目前10道&#xff09; 1. 移除链表元素&#xff08;力扣&#xff1b;思路&#xff1a;前后指针&…

Linux-Nginx安装

一、Nginx下载 官网下载地址&#xff1a; https://nginx.org/en/download.html 国内镜像地址&#xff1a; https://mirrors.huaweicloud.com/nginx 二、Nginx安装 1. 将下载的Nginx安装包上传到Linux服务器指定安装盘符下&#xff0c;解压zip包 tar -zxvf nginx-1.23.3.ta…

【PHP】麻醉临床信息系统

麻醉临床信息系统以服务围术期临床业务工作的开展为核心&#xff0c;为医护人员、业务管理人员、院级领导提供流程化、信息化、自动化、智能化的临床业务综合管理平台。 麻醉信息系统处理的数据包含病人的手术信息、麻醉信息、病人手术过程中从监护仪上采集到的数据和病人情况等…

【嵌入式】2024届校招岗位汇总

公司岗位博世嵌入式自动化测试工程师博世嵌入式开发&#xff08;软件刷写及启动&#xff09;工程师博世Linux/C软件工程师博世自动驾驶软件开发工程师博世嵌入式软件工程师(BSP)博世嵌入式电子工程师 &#xff08;BMS&电源&#xff09;博世物联网嵌入式开发工程师 &#xf…

vue3-vant4-vite-pinia-axios-less学习日记

代码地址 GitHub&#xff1a;vue3-vant4-vite-pinia-axios-less 效果如图 1.首页为导航栏 2.绑定英雄页 3.注册页 4.英雄列表页 5.后面不截图了&#xff0c;没啥了 模块 1.vant4&#xff1a;按需引入组件样式文档 2.安装该vite-plugin-vue-setup-extend插件可以直接在…

数据结构与算法(一)

文章目录 数据结构与算法(一)1 位运算、算法是什么、简单排序1.1 实现打印一个整数的二进制1.2 给定一个参数N,返回1!+2!+3!+4!+...+N!的结果1.3 简单排序算法2 数据结构大分类、前缀和、对数器2.1 实现前缀和数组2.2 如何用1\~5的随机函数加工出1\~7的随机函数2.3 如何把不…

C++学习笔记--项目知识点集合

一、同步IO、异步IO、阻塞IO、非阻塞IO 首先来看看两种I/O的定义&#xff1a;同步I/O和异步I/O 同步&#xff08;阻塞&#xff09;I/O&#xff1a;在一个线程中&#xff0c;CPU执行代码的速度极快&#xff0c;然而&#xff0c;一旦遇到IO操作&#xff0c;如读写文件、发送网络…

vue+electron一键入门

前言 帮公司弄了一个vueelectron项目&#xff0c;里面用到了axios、element-ui、ue-router、js-md5、sqlite3这些依赖库&#xff0c;其中sqlite3比较难搞下面会详细展开来讲&#xff0c;同时也涉及打包&#xff08;window包、mac包&#xff09; 开始 其实项目整体没啥好讲&a…