xen-gic初始化流程

news2024/12/25 12:24:03

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 the
                    		values of fields Aff3, Aff2, Aff1, and Aff0 respectively

					0b1 	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 functionality
                    ICH_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 interface
                    0b0 	Virtual CPU interface operation disabled
                    0b1 	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_cpu
		cpu_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_secondary
    start_secondary
    	init_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_init
                	gicv3_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 interrupts
                0b1 	Non-secure Group 1 interrupts are enabled
            */
            if ( ctlr & GICD_CTLR_ENABLE_G1A )
                v->domain->arch.vgic.ctlr |= GICD_CTLR_ENABLE_G1A;
            else
                v->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.coloradmin.cn/o/1017992.html

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

相关文章

基于SSM的实验室开放管理系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

「信号与系统」语音信号的语谱图、尺度变化、带限处理、基音提取

「信号与系统」语音信号的语谱图、尺度变化、带限处理、基音提取 本文将简单介绍几种语音信号的处理方法。 1、语谱图 语谱图是一种描述语音信号频率特征的方法&#xff0c;横轴表示时间&#xff0c;纵轴表示频率&#xff0c;颜色深浅表示能量。基本原理是将语音信号分帧&am…

js中this的原理详解(web前端开发javascript语法基础)

欢迎关注作者微信公众号&#xff1a;愤怒的it男 一、问题的由来 学懂 JavaScript 语言&#xff0c;一个标志就是理解下面两种写法&#xff0c;可能有不一样的结果。 var angry_it_man {name : 欢迎关注微信公众号&#xff1a;angry_it_man,say : function(){console.log(thi…

学习SLAM:SLAM进阶(十)暴力更改ROS中的PCL库

话不多说&#xff0c;上活 1.1 为什么要这么做 项目中有依赖。。。。 1.2 安装VTK7.1.1 PCL1.8.0 略 1.3 移植到ROS 删除ROS依赖的vtk6.2和PCL1.8.0的动态链接库&#xff1a; liugongweiubuntu:~$ sudo mv /usr/lib/x86_64-linux-gnu/libvtk* Desktop/lib/ [sudo] password fo…

windows平台 git bash使用

打开所在需要git管理的目录,鼠标右键open Git BASH here 这样就直接进来,不需要windows dos窗口下麻烦的切路径&#xff0c;windows和linux 路径方向不一致 (\ /) 然后git init 建立本地仓库,接下来就是git相关的操作了. 图形化界面查看 打开所在需要git管理的目录,鼠标右键…

DipC 构建基因组 3D 结构(学习笔记)

背景 本文主要记录了 DipC 数据的复现过程、学习笔记及注意事项。 目录 下载 SRA 数据使用 SRA Toolkit 转换 SRA 数据为 Fastq 格式使用 bwa 比对测序数据使用 Hickit 计算样本的基因组 3D 结构使用散点图展示 3D 结构计算 3D 结构重复模拟的稳定性其他 步骤 1. 下载 SRA…

从输入一个网址到浏览器页面展示到底发生了什么

从输入一个网址到浏览器页面展示到底发生了什么 1. HTTP 解析URL 首先浏览器做的第一步工作就是解析URL&#xff0c;从而生产一个发送给服务器的请求信息。 URL是什么呢&#xff0c;见下图&#xff1a; 图中长长的URL实际上是请求服务器里的文件资源。 要是上图中的蓝色部分…

ES6中新增加的Symbol数据类型及其使用场景

聚沙成塔每天进步一点点 ⭐ 专栏简介在这里插入图片描述 ⭐ ES6中的Symbol数据类型⭐ 对象属性名称⭐ 防止属性冲突⭐ 内置Symbols⭐ 迭代器和生成器⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航…

笔记 | 非素数个数(朴素筛查 || 埃式筛查法)

非素数个数 题目描述朴素筛查方法题解 题目描述 求a-b之间的非素数个数 特别的&#xff0c;1也算作素数&#xff0c;区间是[a, b]。 输入输出格式 输入描述: 多组测试数据。 输入两个正整数数a,b&#xff0c;其中a<b<10^7。 输出描述: 输出答案。 输入输出样例 输入样例…

ESDA in PySal (3):Geosilhouettes:集群拟合的地理测量

ESDA in PySal (3):Geosilhouettes:集群拟合的地理测量 Silhouette statistics (Rousseeuw, 1987) 是观测值与给定聚类的拟合优度的非参数度量。 在聚类具有“地理”解释的情况下,例如当它们代表地理区域时,轮廓统计可以结合“空间思维”,以便提供更有用的聚类拟合度量。…

git压缩仓库

git 压缩仓库 git gc命令压缩增量存储单元,节省磁盘空间 du -sh 查看当前文件夹占用多少K 快照的存储: 对于修改的内容,做快照处理并保存. 对于未修改的文件,做引用处理.

千兆以太网硬件设计及链路层 MAC 协议格式

以太网系列文章&#xff1a; &#xff08;1&#xff09;千兆以太网硬件设计及链路层 MAC 协议格式 &#xff08;2&#xff09;千兆以太网网络层 ARP 协议的原理与 FPGA 实现 &#xff08;3&#xff09;CRC校验代码原理 文章目录 前言一、以太网 MAC 层接口介绍1.MII 接口2.GMII…

《C++API设计》读书笔记(3):模式

本章内容 本章涵盖了一些与CAPI设计相关的设计模式和惯用法。 “设计模式(Design Pattern)”表示软件设计问题的一些通用解决方案。该术语来源于《设计模式&#xff1a;可复用面向对象软件的基础》&#xff08;Design Patterns: Elements of Reusable Object-Oriented Softwar…

【查缺补漏 女娲补天】2023平安

秋招了&#xff0c;只根据自己的情况记录&#xff0c;大概率不会很全。标题是我觉得的重点。既搬砖也搬博客。 Telnet协议 远程登录和管理网路设备的标准协议TCP传输层之上&#xff1a;应用层工作模型&#xff1a;C/S模式&#xff08;client/server&#xff09;服务端端口号默…

LeNet-5

目录 一、知识点 二、代码 三、查看卷积层的feature map 1. 查看每层信息 ​2. show_featureMap.py 背景&#xff1a;LeNet-5是一个经典的CNN&#xff0c;由Yann LeCun在1998年提出&#xff0c;旨在解决手写数字识别问题。 一、知识点 1. iter()next() iter()&#xff1a;…

【操作系统】聊聊C10K

什么是C10K问题 C10K 就是 Client 10000 问题&#xff0c;即“在同时连接到服务器的客户端数量超过 10000 个的环境中&#xff0c;即便硬件性能足够&#xff0c; 依然无法正常提供服务。 其实说白了就是并发请求1W个请求 同时进行连接服务端&#xff0c;服务端可以支撑服务。…

Linux系统之安装uptime-kuma服务器监控面板

Linux系统之安装uptime-kuma服务器监控面板 一、uptime-kuma介绍1.1 uptime-kuma简介1.2 uptime-kuma特点 二、本次实践环境介绍2.1 环境规划2.2 本次实践介绍2.3 环境要求 三、检查本地环境3.1 检查本地操作系统版本3.2 检查系统内核版本3.3 检查系统是否安装Node.js 四、部署…

post更新,put相当于删除重新增一条

索引数据 //删除后新增 PUT my_dynamic_temp/_doc/1 { “name”:“test”, “class”:“1204” } //覆盖更新 POST my_dynamic_temp/_update/1 { “doc”: { “name”:“test”, “class”:“1203”, “pernum”:“998” } }

springboot 集成mybatis-plus的使用

一、在spring boot中配置mybatis-plus 1、创建一个spring boot项目&#xff0c;注意勾选mysql 2、在pom.xml文件中添加mybatis-plus的依赖包 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0&qu…

瑞芯微RK3568:烧录系统

烧录系统 文章目录 烧录系统windowsLinuxupgrade_tool 工具烧写烧写 update.img擦除操作使用 rkflash.sh 脚本烧写 编译Linux_SDK后得到多个镜像文件 windows Windows 下通过瑞芯微开发工具&#xff08;RKDevTool&#xff09; 来烧写镜像。 Loader parameter uboot …