当前位置: 首页 > news >正文

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

相关文章:

xen-gic初始化流程

xen-gic初始化流程 调试平台使用的是gic-600&#xff0c;建议参考下面的文档来阅读代码&#xff0c;搞清楚相关寄存器的功能。 《corelink_gic600_generic_interrupt_controller_technical_reference_manual_100336_0106_00_en》 《IHI0069H_gic_architecture_specification》…...

Docker从认识到实践再到底层原理(六-1)|Docker容器基本介绍+命令详解

前言 那么这里博主先安利一些干货满满的专栏了&#xff01; 首先是博主的高质量博客的汇总&#xff0c;这个专栏里面的博客&#xff0c;都是博主最最用心写的一部分&#xff0c;干货满满&#xff0c;希望对大家有帮助。 高质量博客汇总 然后就是博主最近最花时间的一个专栏…...

【Flink】FlinkCDC自定义反序列化器

在我们用FlinkCDC采集mysql数据(或其他数据源)的时候,FlinkCDC输出的格式不标准,不利于我们后续做数据处理,我们通常会使用自定义反序列化器来格式化采集数据方便后续处理 常规的反序列化器如下: public class FlinkDataStreamCDC {public static void main(String[] ar…...

linux基础(2)

目录 一.vi\vim编译器介绍1.三种模式2.vim的使用3.快捷键的使用 二.which&#xff0c;find命令三.grep命令四.wc命令五.管道符六.echo命令1.重定向符 七.tail命令 一.vi\vim编译器介绍 vim\vi是linux中最经典的文本编译器 同图形化界面中的文本编译器是一样的&#xff0c;vi是…...

docker安装zookeeper(单机版)

第一步&#xff1a;拉取镜像 docker pull zookeeper第二步&#xff1a;启动zookeeper docker run -d -e TZ"Asia/Shanghai" -p 2181:2181 -v /home/sunyuhua/docker/zookeeper:/data --name zookeeper --restart always zookeeper...

国际版阿里云/腾讯云免开户:云存储服务:云存储服务能够让你随时随地拜访和同享文件

云存储服务&#xff1a;云存储服务能够让你随时随地拜访和同享文件 云存储服务是一种基于云技术的存储渠道&#xff0c;能够让用户存储、管理和同享各种类型的数据文件&#xff0c;如文档、图片、视频、音频等。这种服务具有许多长处&#xff0c;以下是对其进行的详细分析&…...

【Java】应用层协议HTTP和HTTPS

HTTP和HTTPS协议 HTTPHTTP协议的工作过程HTTP协议格式抓包工具抓包结果 HTTP请求(Request)URL方法GET方法POST请求其他方法 报头(header)HostContent-lengthContent-TypeUser-AgentRefererCookie 正文(body) HTTP响应HTTP状态码响应报头(header)响应正文(body) 通过form表单构造…...

SpringBoot整合Flowable

1. 配置 &#xff08;1&#xff09; 引入maven依赖 <dependency><groupId>org.flowable</groupId><artifactId>flowable-spring-boot-starter</artifactId><version>6.7.2</version></dependency><!-- MySQL连接 -->&l…...

华为云香港S3云服务器性能测评_99元一年租用价格

华为云香港S3云服务器1核2G1M带宽99元一年性能测评&#xff0c;配置为S3云服务器1核2G1M带宽&#xff0c;S系列热卖机型&#xff0c;适用于个人建站、普通web应用等负载较低场景&#xff0c;系统盘为高IO40G系统盘&#xff0c;华为云百科分享华为云香港云服务器配置费用&#x…...

prompt 视频收集

1.ChatGPT Prompt提示词工程 ***** 常用技巧 &#xff08;基本原则&#xff0c;格式&#xff0c;角色扮演&#xff09;_哔哩哔哩_bilibili...

Rust :与C交互

rust调用C端的库函数&#xff0c;有很多方法。今天介绍通过cc库&#xff0c;通过build生成脚本的方式&#xff0c;实现rust调用c端库函数。 1、相关准备&#xff1a; 在ffi目录下&#xff0c;创建了c_part和rust_ffi文件夹。 c_part下放了ctools.c文件&#xff0c;里面有一些…...

模拟实现C语言--memcpy函数和memmove函数

模拟实现C语言–memcpy函数和memmove函数 文章目录 模拟实现C语言--memcpy函数和memmove函数一、memcpy函数和memmove函数1.1 memcpy函数是什么1.1 memmove函数是什么 二、使用示例2.1 从起始位置复制2.2 从任意位置复制 三、模拟实现3.1 模拟实现1--memcpy函数3.2 针对缺点改进…...

Linux目录

根目录 根目录&#xff1a;“/” 在Linux系统中&#xff0c;根目录指的是整个文件系统的最顶级目录&#xff0c;用符号"/"表示。根目录是文件系统的起点&#xff0c;所有其他目录和文件都嵌套在根目录下面。在根目录下通常会有一些常见的子目录&#xff0c;例如/bin…...

全国职业技能大赛云计算--高职组赛题卷①(私有云)

全国职业技能大赛云计算--高职组赛题卷①&#xff08;私有云&#xff09; 第一场次题目&#xff1a;OpenStack平台部署与运维任务1 基础运维任务&#xff08;5分&#xff09;任务2 OpenStack搭建任务&#xff08;15分&#xff09;任务3 OpenStack云平台运维&#xff08;15分&am…...

STM32--PWR电源控制

文章目录 PWR电源电源管理器上电复位&#xff08;POR&#xff09;和掉电复位&#xff08;PDR&#xff09; 可编程电压监测器&#xff08;PVD&#xff09;低功耗模式睡眠模式停止模式待机模式 睡眠模式工程停止模式待机模式 PWR STM32的PWR模块是其电源管理系统的核心部分&…...

vue+element-ui el-descriptions 详情渲染组件二次封装(Vue项目)

目录 1、需求 2.想要的效果就是由图一变成图二 ​编辑 3.组件集成了以下功能 4.参数配置 示例代码 参数说明 5,组件 6.页面使用 1、需求 一般后台管理系统&#xff0c;通常页面都有增删改查&#xff1b;而查不外乎就是渲染新增/修改的数据&#xff08;由输入框变成输…...

Nvme 协议第一章节学习

Nvme Express Base Specification 第一章 简介 1.1概述 NVM ExpressTM&#xff08;NVMeTM&#xff09;接口允许主机软件与非易失性存储器子系统通信。 此接口针对企业和客户端固态驱动器进行了优化&#xff0c;通常作为寄存器级接口连接到PCI Express接口。 注&#xff1a;在…...

三维模型3DTile格式轻量化压缩处理工具常用几款软件介绍

三维模型3DTile格式轻量化压缩处理工具常用几款软件介绍 三维模型3DTile格式的轻量化处理旨在减少模型的存储空间和提高渲染性能。以下是一些推荐的工具软件&#xff0c;可以用于实现这个目的&#xff1a; MeshLab&#xff1a;MeshLab是一个开源的三维模型处理软件&#xff0c…...

【工具篇】高级 TypeScript 案例

本文说明&#xff1a;TypeScript 相关文章&#xff0c;了解更多特性。 网页编辑器&#xff1a; https://www.typescriptlang.org/zh/play 文章目录 TypeScript联合类型交叉类型装饰器混入 mixin泛型Promise 简单应用 TypeScript 联合类型 概念&#xff1a;当某个函数只有一个参…...

利用Python将dataframe格式的所有列的数据类型转换为分类数据类型

一、样例理解 import pandas as pd import numpy as np# 创建测试数据 feature_names [col1 , col2, col3, col4, col5, col6] values np.random.randint(20, size(10,6))dataset pd.DataFrame(data values, columns feature_names)print("转换前的数据为\n",d…...

安全线程的集合

1. CopyOnWriteArrayList package com.kuang.unsafe;import java.util.*; import java.util.concurrent.CopyOnWriteArrayList;//java.util.ConcurrentModificationException 并发修改异常&#xff01; 因为List集合线程不安全&#xff01; public class ListTest {public st…...

用GoConvey编写单元测试的一些总结

一、尽量用Convey将所有测试用例的Convey汇总 用Convey嵌套的方法&#xff0c;将所有测试用例的Convey用一个大的Convey包裹起来&#xff0c;每个测试函数下只有一个大的Convey。比如下面的示例代码&#xff1a; import ("testing". "github.com/smartystreet…...

Linux Arm64修改页表项属性

文章目录 前言一、获取pte1.1 pgd_offset1.2 pud_offset1.3 pmd_offset1.4 pte_offset_kernel 二、修改pte属性2.1 set/clear_pte_bit2.2 pte_wrprotect2.3 pte_mkwrite2.4 pte_mkclean2.5 pte_mkdirty 三、set_pte_at四、__flush_tlb_kernel_pgtable五、demo参考资料 前言 在…...

elasticsearch14-高亮

个人名片&#xff1a; 博主&#xff1a;酒徒ᝰ. 个人简介&#xff1a;沉醉在酒中&#xff0c;借着一股酒劲&#xff0c;去拼搏一个未来。 本篇励志&#xff1a;三人行&#xff0c;必有我师焉。 本项目基于B站黑马程序员Java《SpringCloud微服务技术栈》&#xff0c;SpringCloud…...

HUAWEI华为MateBook X Pro 2021款 i7 集显(MACHD-WFE9Q)原装出厂Win10系统20H2

华为笔记本电脑原厂系统自带指纹驱动、显卡驱动、声卡驱动、网卡驱动等所有驱动、出厂主题壁纸、系统属性华为专属LOGO标志、Office办公软件、华为电脑管家等预装程序 链接&#xff1a;https://pan.baidu.com/s/1oeSM0ciwyyRIKms5tR4SNA?pwdo2gq 提取码&#xff1a;o2gq...

21天学会C++:Day9----初识类与对象

CSDN的uu们&#xff0c;大家好。这里是C入门的第九讲。 座右铭&#xff1a;前路坎坷&#xff0c;披荆斩棘&#xff0c;扶摇直上。 博客主页&#xff1a; 姬如祎 收录专栏&#xff1a;C专题 目录 1. 面向过程与面向对象 2. 类的定义 3. 类中的访问限定符 3.1 访问限定符的…...

【深度学习】 Python 和 NumPy 系列教程(十七):Matplotlib详解:2、3d绘图类型(3)3D条形图(3D Bar Plot)

目录 一、前言 二、实验环境 三、Matplotlib详解 1、2d绘图类型 2、3d绘图类型 0. 设置中文字体 1. 线框图 2. 3D散点图 3. 3D条形图&#xff08;3D Bar Plot&#xff09; 一、前言 Python是一种高级编程语言&#xff0c;由Guido van Rossum于1991年创建。它以简洁、易读…...

基于Spring Boot+vue的酒店管理系统

文章目录 项目介绍主要功能截图:前台后台部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于Spring Boot+vue的酒店管理…...

Python 通过threading模块实现多线程

视频版教程 Python3零基础7天入门实战视频教程 我们可以使用threading模块的Thread类的构造器来创建线程 def _ init _(self, groupNone, targetNone, nameNone, args(), kwargsNone, *, daemonNone): 上面的构造器涉及如下几个参数。 group:指定该线程所属的线程组。目前该…...

用一个RecyclerView实现二级评论

先上个效果图&#xff08;没有UI&#xff0c;将就看吧&#xff09;&#xff0c;写代码的整个过程花了4个小时左右&#xff0c;相比当初自己开发需求已经快了很多了哈。 给产品估个两天时间&#xff0c;摸一天半的鱼不过分吧&#xff08;手动斜眼&#xff09; 需求拆分 这种大家…...

网站开发中所需要的绘图工具/百度账号安全中心

349. 两个数组的交集 给定两个数组 nums1 和 nums2 &#xff0c;返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。 简单难度。使用两个Hashset&#xff0c;首先遍历一个数组加入到第一个set集合&#xff0c;然后遍历第二个数组看是否…...

美国生物等效性如果做的网站/深圳互联网公司排行榜

这篇文章主要介绍了一些Centos Python 生产环境的部署命令&#xff0c;非常不错&#xff0c;具有参考借鉴价值&#xff0c;需要的朋友参考下吧Just notes拿到一台干净的centos之后, 初始化Python环境, 一些命令和问题记录而已可以搞成脚本自动初始化, 当然, 用docker更好基础环…...

网站建设运营的成本/济南百度推广公司电话

如果想查找“_cs”结尾的的账户select * from [user] where loginname like %_cs是不行的&#xff0c;_ 被认为是任意的字符&#xff0c;所以需要转义字符&#xff0c;有两种写法&#xff1a;select * from [user] where loginname like %[_]csselect * from [user] where logi…...

汕头公司做网站/seo分析师

我试图在约束布局的运行时将TextViews添加到另一个之下。但我总是只有一个文本视图&#xff0c;其余的隐藏在它后面。我尝试了几件事情&#xff0c;包括链接视图&#xff0c;但似乎没有任何工作。Android ConstraintLayout&#xff1a;如何将动态视图添加到另一个下方private v…...

国内单页面网站/企业查询

token详解前言什么是token&#xff1f;为什么要使用token&#xff1f;那么如何使用token呢&#xff1f;使用Token进行身份验证和授权的过程具体步骤项目上如何运用的tokentoken过期了什么办&#xff1f;总结升华前言 本篇博客主要从什么是token&#xff1f;为什么要使用token&…...

河口企业网站开发公司/百度网盘官方下载

python怎么打开文件模式python的open打开的是哪里的文件啊python 读取文件&#xff0c;怎么打开&#xff1f;.py文件无法用python打开我系统里装有python 2.7,在双击.py文件时为什么弹应该是没有设置环境变量的缘故&#xff1a; 右击【我的电脑】【属性】-【高级】-【环境变量】…...