【ARM64】【cpu_topology】

本文介绍ARM64架构下CPU拓扑信息的解析过程,包括如何从设备树源文件中读取CPU拓扑信息,并通过代码示例详细解释了cluster、core及CPU层级的解析方法。
static int __init parse_dt_topology(void)
{
    struct device_node *cn, *map;
    int ret = 0;
    int cpu;

    /* (1) 找到dts中cpu topology的根节点"/cpus"" */
    cn = of_find_node_by_path("/cpus");
    if (!cn) {
        pr_err("No CPU information found in DT\n");
        return 0;
    }

    /*
     * When topology is provided cpu-map is essentially a root
     * cluster with restricted subnodes.
     */
    /* (2) 找到"cpu-map"节点 */
    map = of_get_child_by_name(cn, "cpu-map");
    if (!map)
        goto out;

    /* (3) 解析"cpu-map"中的cluster */
    ret = parse_cluster(map, 0);
    if (ret != 0)
        goto out_map;

    /*
     * Check that all cores are in the topology; the SMP code will
     * only mark cores described in the DT as possible.
     */
    for_each_possible_cpu(cpu)
        if (cpu_topology[cpu].cluster_id == -1)
            ret = -EINVAL;

out_map:
    of_node_put(map);
out:
    of_node_put(cn);
    return ret;
}

对应于dts中的文件如下:

    cpus {       
         #address-cells = <2>;
         #size-cells = <0>;
                  
         cpu-map {  
             cluster0 {
                 core0 {
                     cpu = <&CPU0>;
                 }; 
                 core1 {
                     cpu = <&CPU1>;
                 }; 
                 core2 {
                     cpu = <&CPU2>;
                 }; 
                 core3 {
                     cpu = <&CPU3>;
                 }; 
             };   
             cluster1 {
                 core0 {
                     cpu = <&CPU4>;
                 }; 
                 core1 {
                     cpu = <&CPU5>;
                 }; 
                 core2 {
                     cpu = <&CPU6>;
                 }; 
                 core3 {
                     cpu = <&CPU7>;
                 };
             };   
         };   
.....}	

搜索上面这个dts文件,先解析cluster--->core

static int __init parse_cluster(struct device_node *cluster, int depth)
{
    char name[10];
    bool leaf = true;
    bool has_cores = false;
    struct device_node *c;
    static int cluster_id __initdata;
    int core_id = 0;
    int i, ret;

    /*
     * First check for child clusters; we currently ignore any
     * information about the nesting of clusters and present the
     * scheduler with a flat list of them.
     */
    i = 0;
    /* (3.1) 如果有多级cluster,继续递归搜索 */
    do {
        snprintf(name, sizeof(name), "cluster%d", i);
        c = of_get_child_by_name(cluster, name);
        if (c) {
            leaf = false;
            ret = parse_cluster(c, depth + 1);
            of_node_put(c);
            if (ret != 0)
                return ret;
        }
        i++;
    } while (c);

    /* Now check for cores */
    i = 0;
    do {
        /* (3.2) 或者core层次的节点 */
        snprintf(name, sizeof(name), "core%d", i);
        c = of_get_child_by_name(cluster, name);
        if (c) {
            has_cores = true;

            if (depth == 0) {
                pr_err("%s: cpu-map children should be clusters\n",
                       c->full_name);
                of_node_put(c);
                return -EINVAL;
            }

            if (leaf) {
                /* (3.3) 如果是叶子cluster节点,继续遍历core中的cpu节点 */
                ret = parse_core(c, cluster_id, core_id++);
            } else {
                pr_err("%s: Non-leaf cluster with core %s\n",
                       cluster->full_name, name);
                ret = -EINVAL;
            }

            of_node_put(c);
            if (ret != 0)
                return ret;
        }
        i++;
    } while (c);

    if (leaf && !has_cores)
        pr_warn("%s: empty cluster\n", cluster->full_name);

    if (leaf)
        cluster_id++;

    return 0;
}

再从core解析到cpu

         CPU1: cpu@100 {
             device_type = "cpu";
             compatible = "arm,cortex-a55","arm,armv8";
             reg = <0x0 0x100>;
             enable-method = "psci";
             cpu-supply = <&fan53555_dcdc>;
             cpufreq-data-v1 = <&cpufreq_clus0>;
             cpu-idle-states = <&CORE_PD>;
             sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
         };       
         CPU2: cpu@200 {
             device_type = "cpu";
             compatible = "arm,cortex-a55","arm,armv8";
             reg = <0x0 0x200>;
             enable-method = "psci";
             cpu-supply = <&fan53555_dcdc>;
             cpufreq-data-v1 = <&cpufreq_clus0>;
             cpu-idle-states = <&CORE_PD>;
             sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
         };       
         CPU3: cpu@300 {
             device_type = "cpu";
             compatible = "arm,cortex-a55","arm,armv8";
             reg = <0x0 0x300>;
             enable-method = "psci";
             cpu-supply = <&fan53555_dcdc>;
             cpufreq-data-v1 = <&cpufreq_clus0>;
             cpu-idle-states = <&CORE_PD>;
             sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
         };   
         CPU4: cpu@400 {
             device_type = "cpu";
             compatible = "arm,cortex-a55","arm,armv8";
             reg = <0x0 0x400>;
             enable-method = "psci";
             cpu-supply = <&vddcpu>;
             cpufreq-data-v1 = <&cpufreq_clus1>;
             cpu-idle-states = <&CORE_PD>;
             sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>;
         };      
         CPU5: cpu@500 {
             device_type = "cpu";
             compatible = "arm,cortex-a55","arm,armv8";
             reg = <0x0 0x500>;
             enable-method = "psci";
             cpu-supply = <&vddcpu>;
             cpufreq-data-v1 = <&cpufreq_clus1>;
             cpu-idle-states = <&CORE_PD>;
             sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>;
         };      
         CPU6: cpu@600 {
             device_type = "cpu";
             compatible = "arm,cortex-a55","arm,armv8";
             reg = <0x0 0x600>;
             enable-method = "psci";
             cpu-supply = <&vddcpu>;
             cpufreq-data-v1 = <&cpufreq_clus1>;
             cpu-idle-states = <&CORE_PD>;
             sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>;
         };      
         CPU7: cpu@700 {
             device_type = "cpu";
             compatible = "arm,cortex-a55","arm,armv8";
             reg = <0x0 0x700>;
             enable-method = "psci";
             cpu-supply = <&vddcpu>;
             cpufreq-data-v1 = <&cpufreq_clus1>;
             cpu-idle-states = <&CORE_PD>;
             sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>;
         };      
     };   	 

继续解析cpu层级

static int __init parse_core(struct device_node *core, int cluster_id,
                 int core_id)
{
    char name[10];
    bool leaf = true;
    int i = 0;
    int cpu;
    struct device_node *t;

    do {
        /* (3.3.1) 如果存在thread层级,解析thread和cpu层级 */
        snprintf(name, sizeof(name), "thread%d", i);
        t = of_get_child_by_name(core, name);
        if (t) {
            leaf = false;
            cpu = get_cpu_for_node(t);
            if (cpu >= 0) {
                cpu_topology[cpu].cluster_id = cluster_id;
                cpu_topology[cpu].core_id = core_id;
                cpu_topology[cpu].thread_id = i;
            } else {
                pr_err("%s: Can't get CPU for thread\n",
                       t->full_name);
                of_node_put(t);
                return -EINVAL;
            }
            of_node_put(t);
        }
        i++;
    } while (t);

    /* (3.3.2) 否则直接解析cpu层级 */
    cpu = get_cpu_for_node(core);
    if (cpu >= 0) {
        if (!leaf) {
            pr_err("%s: Core has both threads and CPU\n",
                   core->full_name);
            return -EINVAL;
        }

        /* (3.3.3) 得到了cpu的cluster_id/core_id */
        cpu_topology[cpu].cluster_id = cluster_id;
        cpu_topology[cpu].core_id = core_id;
    } else if (leaf) {
        pr_err("%s: Can't get CPU for leaf core\n", core->full_name);
        return -EINVAL;
    }

    return 0;
}

这里没有thread层级,所以直接解析cpu层级

static int __init get_cpu_for_node(struct device_node *node)
{
    struct device_node *cpu_node;
    int cpu;

    cpu_node = of_parse_phandle(node, "cpu", 0);
    if (!cpu_node)
        return -1;

    for_each_possible_cpu(cpu) {
        if (of_get_cpu_node(cpu, NULL) == cpu_node) {
            of_node_put(cpu_node);
            return cpu;
        }
    }

    pr_crit("Unable to find CPU node for %s\n", cpu_node->full_name);

    of_node_put(cpu_node);
    return -1;
}

生成的外部节点信息

1) /sys/devices/system/cpu/cpuX/topology/physical_package_id:

    physical package id of cpuX. Typically corresponds to a physical
    socket number, but the actual value is architecture and platform
    dependent.

2) /sys/devices/system/cpu/cpuX/topology/core_id:

    the CPU core ID of cpuX. Typically it is the hardware platform's
    identifier (rather than the kernel's).  The actual value is
    architecture and platform dependent.

3) /sys/devices/system/cpu/cpuX/topology/book_id:

    the book ID of cpuX. Typically it is the hardware platform's
    identifier (rather than the kernel's).    The actual value is
    architecture and platform dependent.

4) /sys/devices/system/cpu/cpuX/topology/thread_siblings:

    internal kernel map of cpuX's hardware threads within the same
    core as cpuX.

5) /sys/devices/system/cpu/cpuX/topology/thread_siblings_list:

    human-readable list of cpuX's hardware threads within the same
    core as cpuX.

6) /sys/devices/system/cpu/cpuX/topology/core_siblings:

    internal kernel map of cpuX's hardware threads within the same
    physical_package_id.

7) /sys/devices/system/cpu/cpuX/topology/core_siblings_list:

    human-readable list of cpuX's hardware threads within the same
    physical_package_id.

8) /sys/devices/system/cpu/cpuX/topology/book_siblings:

    internal kernel map of cpuX's hardware threads within the same
    book_id.

9) /sys/devices/system/cpu/cpuX/topology/book_siblings_list:

    human-readable list of cpuX's hardware threads within the same
    book_id.

当前手机扫描出来的数据如下:

             core_id    0
       core_siblings    0f
  core_siblings_list    0-3
 physical_package_id    0
     thread_siblings    01
thread_siblings_list    0

             core_id    1
       core_siblings    0f
  core_siblings_list    0-3
 physical_package_id    0
     thread_siblings    02
thread_siblings_list    1

             core_id    2
       core_siblings    0f
  core_siblings_list    0-3
 physical_package_id    0
     thread_siblings    04
thread_siblings_list    2

             core_id    3
       core_siblings    0f
  core_siblings_list    0-3
 physical_package_id    0
     thread_siblings    08
thread_siblings_list    3

             core_id    0
       core_siblings    f0
  core_siblings_list    4-7
 physical_package_id    1
     thread_siblings    10
thread_siblings_list    4

             core_id    1
       core_siblings    f0
  core_siblings_list    4-7
 physical_package_id    1
     thread_siblings    20
thread_siblings_list    5

             core_id    2
       core_siblings    f0
  core_siblings_list    4-7
 physical_package_id    1
     thread_siblings    40
thread_siblings_list    6

             core_id    3
       core_siblings    f0
  core_siblings_list    4-7
 physical_package_id    1
     thread_siblings    80
thread_siblings_list    7

关于core_id\thread_sibling\core_sibling的解析如下:

static void update_siblings_masks(unsigned int cpuid)
{
	struct cpu_topology *cpu_topo, *cpuid_topo = &cpu_topology[cpuid];
	int cpu;

	/* update core and thread sibling masks */
	for_each_possible_cpu(cpu) {
		cpu_topo = &cpu_topology[cpu];

		if (cpuid_topo->cluster_id != cpu_topo->cluster_id)
			continue;
		// 关联的兄弟cpu
		cpumask_set_cpu(cpuid, &cpu_topo->core_sibling);
		if (cpu != cpuid)
			cpumask_set_cpu(cpu, &cpuid_topo->core_sibling);
		// 硬件plat的值
		if (cpuid_topo->core_id != cpu_topo->core_id)
			continue;
		// 关联硬件thread
		cpumask_set_cpu(cpuid, &cpu_topo->thread_sibling);
		if (cpu != cpuid)
			cpumask_set_cpu(cpu, &cpuid_topo->thread_sibling);
	}
}

一切感觉都是在填充topology这个结构体。

arm64架构的cpu拓扑结构存储在cpu_topology[]变量当中:

/*
 * cpu topology table
 */
struct cpu_topology cpu_topology[NR_CPUS];


struct cpu_topology {
    int thread_id;
    int core_id;
    int cluster_id;                 // 本cpu所在的cluster
    unsigned int partno;
    cpumask_t thread_sibling;
    cpumask_t core_sibling;         // 在MutiCore层次(即同一个cluster中),有哪些兄弟cpu
};

这是pcie绑定中断亲和性的函数 static int udrv_pcie_msi_set_affinity(struct irq_data *irq_data, const struct cpumask *dest_mask, bool force) { unsigned long flags; struct udrv_pcie_host *pcie = irq_data_get_irq_chip_data(irq_data); struct cpumask online_mask; unsigned int cpu; uint32_t status; int ret = 0; u64 new_addr, gic_target, mpidr;; // 1. 目标CPU选择 cpumask_and(&online_mask, dest_mask, cpu_online_mask); if (cpumask_empty(&online_mask)) { dev_err(pcie->dev, "No online CPU in affinity mask\n"); return -EINVAL; } cpu = cpumask_first(&online_mask); raw_spin_lock_irqsave(&pcie->msi.lock, flags); ndrv_pcie_host_msi_mask_all(pcie->host_info.pf_handle, 0xFFFFFFFF); ndrv_pcie_host_get_msi_status(pcie->host_info.pf_handle, &status); ndrv_pcie_host_msi_clear(pcie->host_info.pf_handle, status); // ===== 核心修改开始 ===== /* 1. 保留原始地址的有效位 */ new_addr = pcie->msi.msi_addr & 0xFFFFFFFFULL; // 保留低32位 /* 2. 平台无关的目标CPU编码方案 */ #if defined(CONFIG_ARM64) /* ARM64: 直接读取MPIDR_EL1寄存器 */ asm volatile("mrs %0, mpidr_el1" : "=r" (mpidr)); /* 提取目标CPU的Aff0字段 (bit[0:7]) */ gic_target = (mpidr & 0xFFUL); /* ARM GIC规范:目标CPU ID位于bit[47:32] */ new_addr |= gic_target << 32; dev_info(pcie->dev, "CPU%d → MPIDR:0x%llx → GIC target:0x%04x\n", cpu, mpidr, (unsigned int)gic_target); #elif defined(CONFIG_ARM) /* ARM32: 使用固定的偏移映射 */ gic_target = (cpu + 1) & 0xFFFF; new_addr |= gic_target << 32; dev_info(pcie->dev, "CPU%d → GIC target:0x%04x (fixed mapping)\n", cpu, (unsigned int)gic_target); #else /* 通用平台:使用默认偏移映射 */ new_addr |= ((u64)(cpu + 1) * 0x10000) << 16; dev_info(pcie->dev, "CPU%d → Default mapping\n", cpu); #endif // ===== 核心修改结束 ===== // 3. 更新硬件地址和软件状态 ret = ndrv_pcie_host_set_msi_addr(pcie->host_info.pf_handle, new_addr); if (ret) { dev_err(pcie->dev, "Set MSI addr failed: %d\n", ret); goto cleanup; } pcie->msi.dynamic_msi_addr = new_addr; irq_data_update_effective_affinity(irq_data, cpumask_of(cpu)); dev_info(pcie->dev, "MSI affinity set to CPU%d (addr=0x%016llx)\n", cpu, new_addr); cleanup: ndrv_pcie_host_msi_mask_all(pcie->host_info.pf_handle, 0); wmb(); raw_spin_unlock_irqrestore(&pcie->msi.lock, flags); return ret ? ret : IRQ_SET_MASK_OK; } 下面是测试日志 hi309a /lib/udrivers # zcat /proc/config.gz | grep CONFIG_ARM64 CONFIG_ARM64=y CONFIG_ARM64_PAGE_SHIFT=12 CONFIG_ARM64_CONT_PTE_SHIFT=4 CONFIG_ARM64_CONT_PMD_SHIFT=4 CONFIG_ARM64_WORKAROUND_CLEAN_CACHE=y CONFIG_ARM64_ERRATUM_826319=y CONFIG_ARM64_ERRATUM_827319=y CONFIG_ARM64_ERRATUM_824069=y CONFIG_ARM64_ERRATUM_819472=y CONFIG_ARM64_ERRATUM_832075=y CONFIG_ARM64_ERRATUM_834220=y CONFIG_ARM64_ERRATUM_843419=y CONFIG_ARM64_ERRATUM_1024718=y CONFIG_ARM64_WORKAROUND_SPECULATIVE_AT=y CONFIG_ARM64_ERRATUM_1165522=y CONFIG_ARM64_ERRATUM_1319367=y CONFIG_ARM64_ERRATUM_1530923=y CONFIG_ARM64_WORKAROUND_REPEAT_TLBI=y CONFIG_ARM64_ERRATUM_1286807=y CONFIG_ARM64_ERRATUM_1463225=y CONFIG_ARM64_ERRATUM_1542419=y CONFIG_ARM64_ERRATUM_1508412=y CONFIG_ARM64_4K_PAGES=y # CONFIG_ARM64_16K_PAGES is not set # CONFIG_ARM64_64K_PAGES is not set CONFIG_ARM64_VA_BITS_39=y # CONFIG_ARM64_VA_BITS_48 is not set CONFIG_ARM64_VA_BITS=39 CONFIG_ARM64_PA_BITS_48=y CONFIG_ARM64_PA_BITS=48 # CONFIG_ARM64_BOOTPARAM_HOTPLUG_CPU0 is not set # CONFIG_ARM64_CPU_PARK is not set # CONFIG_ARM64_PMEM_LEGACY is not set # CONFIG_ARM64_SW_TTBR0_PAN is not set CONFIG_ARM64_TAGGED_ADDR_ABI=y CONFIG_ARM64_HW_AFDBM=y CONFIG_ARM64_PAN=y CONFIG_ARM64_LSE_ATOMICS=y CONFIG_ARM64_USE_LSE_ATOMICS=y CONFIG_ARM64_VHE=y # CONFIG_ARM64_PMEM is not set CONFIG_ARM64_RAS_EXTN=y CONFIG_ARM64_CNP=y # CONFIG_ARM64_PBHA is not set CONFIG_ARM64_PTR_AUTH=y CONFIG_ARM64_AMU_EXTN=y CONFIG_ARM64_TLB_RANGE=y CONFIG_ARM64_BTI=y CONFIG_ARM64_E0PD=y CONFIG_ARM64_AS_HAS_MTE=y CONFIG_ARM64_MTE=y CONFIG_ARM64_TWED=y CONFIG_ARM64_EPAN=y CONFIG_ARM64_SVE=y CONFIG_ARM64_SME=y CONFIG_ARM64_MODULE_PLTS=y # CONFIG_ARM64_PSEUDO_NMI is not set # CONFIG_ARM64_ACPI_PARKING_PROTOCOL is not set # CONFIG_ARM64_CRYPTO is not set CONFIG_ARM64_ERRATUM_858921=y # CONFIG_ARM64_BRBE is not set # CONFIG_ARM64_RELOC_TEST is not set hi309a /lib/udrivers # cat /proc/irq/100/smp_affinity_list 0-7 hi309a /lib/udrivers # echo 5 > /proc/irq/100/smp_affinity_list [ 310.047716] udrv-pcie b00000000.pcie: Fixed MSI addr: CPU5 → 0x700050 (was 0x700000) [ 310.055671] udrv-pcie b00000000.pcie: MSI affinity set to CPU5 (addr=0x700050) [ 310.062923] udrv-pcie b00000000.pcie: [iWare][Info] msi#1 address_hi 0x0 address_lo 0x700050 hi309a /lib/udrivers # cat /proc/irq/100/smp_affinity_list 5 hi309a /lib/udrivers # grep -i MPIDR /proc/cpuinfo hi309a /lib/udrivers # dmesg | grep "GIC target" [ 11.259940] udrv-pcie b00000000.pcie: CPU0 → MPIDR:0x81080000 → GIC target:0x0000 [ 12.314262] udrv-pcie ba0000000.pcie: CPU0 → MPIDR:0x81090000 → GIC target:0x0000 [ 116.616172] udrv-pcie b00000000.pcie: CPU0 → MPIDR:0x81080000 → GIC target:0x0000 hi309a /lib/udrivers # echo 5 > /proc/irq/100/smp_affinity_list [ 219.636806] udrv-pcie b00000000.pcie: CPU5 → MPIDR:0x81090300 → GIC target:0x0000 [ 219.644676] udrv-pcie b00000000.pcie: MSI affinity set to CPU5 (addr=0x0000000000700000) [ 219.652801] udrv-pcie b00000000.pcie: [iWare][Info] msi#1 address_hi 0x0 address_lo 0x700000 hi309a /lib/udrivers # dmesg | grep "GIC target" [ 11.259940] udrv-pcie b00000000.pcie: CPU0 → MPIDR:0x81080000 → GIC target:0x0000 [ 12.314262] udrv-pcie ba0000000.pcie: CPU0 → MPIDR:0x81090000 → GIC target:0x0000 [ 116.616172] udrv-pcie b00000000.pcie: CPU0 → MPIDR:0x81080000 → GIC target:0x0000 [ 219.636806] udrv-pcie b00000000.pcie: CPU5 → MPIDR:0x81090300 → GIC target:0x0000 hi309a /lib/udrivers # grep -i MPIDR /proc/cpuinfo hi309a /lib/udrivers # ping 192.168.0.10 PING 192.168.0.10 (192.168.0.10): 56 data bytes 64 bytes from 192.168.0.10: seq=0 ttl=128 time=1.287 ms 64 bytes from 192.168.0.10: seq=1 ttl=128 time=1.601 ms ^Z [3]+ Stopped ping 192.168.0.10 hi309a /lib/udrivers # cat /proc/interrupts | grep eth0 100: 100 0 0 0 0 0 0 0 udrv_msi 524288 Edge eth0 hi309a /lib/udrivers # ping 192.168.0.10 PING 192.168.0.10 (192.168.0.10): 56 data bytes 64 bytes from 192.168.0.10: seq=0 ttl=128 time=0.992 ms 64 bytes from 192.168.0.10: seq=1 ttl=128 time=1.486 ms 64 bytes from 192.168.0.10: seq=2 ttl=128 time=1.859 ms 64 bytes from 192.168.0.10: seq=3 ttl=128 time=1.582 ms ^Z [4]+ Stopped ping 192.168.0.10 hi309a /lib/udrivers # cat /proc/interrupts | grep eth0 100: 112 0 0 0 0 0 0 0 udrv_msi 524288 Edge eth0 hi309a /lib/udrivers # cat /proc/irq/100/smp_affinity_list 5 另外这是文档描述 GIC亲和路由设计遵循GIC Specification,但路由关系只有三个层次,GIC亲和路由配置定义如下: AL3,该层次未定义,硬件不使用该字段。 AL2,该值 bit[5:2]等于SCLID,SCLID表示在系统中SCL的编号,指示中断被路由到哪个SCL;该值 bit[1:0]等于ClusterID,ClusterID表示某SCL内的CPU Cluster编号,指示中断被路由到哪个Cluster。 AL1,该值bit[2:0]等于CPUID,CPUID表示在某CPU Cluster内CPU core编号,指示中断被路由到哪个CPU core。 AL0,该层次在SGI和SPI路由配置中定义不同: 在SPI亲和路由配置中,AL0表示Thread Num;目前参照A55格式,AL0 tied to Zero。 在SGI亲和路由配置中,AL0等于TargetList;该值并不构成路由信息,该值[0]bit 指示SGI路由是否有效。 请结合代码帮我分析,需要分析其过程、原理,以及CPU ID掩码的转换和写入地址的得出方法。
09-27
fn setup_vm_components(cfg: &Config) -> Result<VmComponents> { let initrd_image = if let Some(initrd_path) = &cfg.initrd_path { Some( open_file_or_duplicate(initrd_path, OpenOptions::new().read(true)) .with_context(|| format!("failed to open initrd {}", initrd_path.display()))?, ) } else { None }; let pvm_fw_image = if let Some(pvm_fw_path) = &cfg.pvm_fw { Some( open_file_or_duplicate(pvm_fw_path, OpenOptions::new().read(true)) .with_context(|| format!("failed to open pvm_fw {}", pvm_fw_path.display()))?, ) } else { None }; let vm_image = match cfg.executable_path { Some(Executable::Kernel(ref kernel_path)) => VmImage::Kernel( open_file_or_duplicate(kernel_path, OpenOptions::new().read(true)).with_context( || format!("failed to open kernel image {}", kernel_path.display()), )?, ), Some(Executable::Bios(ref bios_path)) => VmImage::Bios( open_file_or_duplicate(bios_path, OpenOptions::new().read(true)) .with_context(|| format!("failed to open bios {}", bios_path.display()))?, ), _ => panic!("Did not receive a bios or kernel, should be impossible."), }; let swiotlb = if let Some(size) = cfg.swiotlb { Some( size.checked_mul(1024 * 1024) .ok_or_else(|| anyhow!("requested swiotlb size too large"))?, ) } else if matches!(cfg.protection_type, ProtectionType::Unprotected) { None } else { Some(64 * 1024 * 1024) }; let (pflash_image, pflash_block_size) = if let Some(pflash_parameters) = &cfg.pflash_parameters { ( Some( open_file_or_duplicate( &pflash_parameters.path, OpenOptions::new().read(true).write(true), ) .with_context(|| { format!("failed to open pflash {}", pflash_parameters.path.display()) })?, ), pflash_parameters.block_size, ) } else { (None, 0) }; #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] let mut cpu_frequencies = BTreeMap::new(); #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] let mut virt_cpufreq_socket = None; #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] if cfg.virt_cpufreq { let host_cpu_frequencies = Arch::get_host_cpu_frequencies_khz()?; for cpu_id in 0..cfg.vcpu_count.unwrap_or(1) { let vcpu_affinity = match cfg.vcpu_affinity.clone() { Some(VcpuAffinity::Global(v)) => v, Some(VcpuAffinity::PerVcpu(mut m)) => m.remove(&cpu_id).unwrap_or_default(), None => { panic!("There must be some vcpu_affinity setting with VirtCpufreq enabled!") } }; // Check that the physical CPUs that the vCPU is affined to all share the same // frequency domain. if let Some(freq_domain) = host_cpu_frequencies.get(&vcpu_affinity[0]) { for cpu in vcpu_affinity.iter() { if let Some(frequencies) = host_cpu_frequencies.get(cpu) { if frequencies != freq_domain { panic!("Affined CPUs do not share a frequency domain!"); } } } cpu_frequencies.insert(cpu_id, freq_domain.clone()); } else { panic!("No frequency domain for cpu:{}", cpu_id); } } virt_cpufreq_socket = if let Some(path) = &cfg.virt_cpufreq_socket { let file = base::open_file_or_duplicate(path, OpenOptions::new().write(true)) .with_context(|| { format!("failed to open virt_cpufreq_socket {}", path.display()) })?; let fd: std::os::fd::OwnedFd = file.into(); let socket: std::os::unix::net::UnixStream = fd.into(); Some(socket) } else { None }; } // if --enable-fw-cfg or --fw-cfg was given, we want to enable fw_cfg let fw_cfg_enable = cfg.enable_fw_cfg || !cfg.fw_cfg_parameters.is_empty(); let (cpu_clusters, cpu_capacity) = if cfg.host_cpu_topology { ( Arch::get_host_cpu_clusters()?, Arch::get_host_cpu_capacity()?, ) } else { (cfg.cpu_clusters.clone(), cfg.cpu_capacity.clone()) }; Ok(VmComponents { #[cfg(target_arch = "x86_64")] ac_adapter: cfg.ac_adapter, #[cfg(target_arch = "x86_64")] break_linux_pci_config_io: cfg.break_linux_pci_config_io, memory_size: cfg .memory .unwrap_or(256) .checked_mul(1024 * 1024) .ok_or_else(|| anyhow!("requested memory size too large"))?, swiotlb, fw_cfg_enable, bootorder_fw_cfg_blob: Vec::new(), vcpu_count: cfg.vcpu_count.unwrap_or(1), vcpu_affinity: cfg.vcpu_affinity.clone(), #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] cpu_frequencies, #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] virt_cpufreq_socket, fw_cfg_parameters: cfg.fw_cfg_parameters.clone(), cpu_clusters, cpu_capacity, no_smt: cfg.no_smt, hugepages: cfg.hugepages, hv_cfg: hypervisor::Config { #[cfg(target_arch = "aarch64")] mte: cfg.mte, protection_type: cfg.protection_type, }, vm_image, android_fstab: cfg .android_fstab .as_ref() .map(|x| { File::open(x) .with_context(|| format!("failed to open android fstab file {}", x.display())) }) .map_or(Ok(None), |v| v.map(Some))?, pstore: cfg.pstore.clone(), pflash_block_size, pflash_image, initrd_image, extra_kernel_params: cfg.params.clone(), acpi_sdts: cfg .acpi_tables .iter() .map(|path| { SDT::from_file(path) .with_context(|| format!("failed to open ACPI file {}", path.display())) }) .collect::<Result<Vec<SDT>>>()?, rt_cpus: cfg.rt_cpus.clone(), delay_rt: cfg.delay_rt, #[cfg(feature = "gdb")] gdb: None, no_i8042: cfg.no_i8042, no_rtc: cfg.no_rtc, #[cfg(target_arch = "x86_64")] smbios: cfg.smbios.clone(), host_cpu_topology: cfg.host_cpu_topology, itmt: cfg.itmt, #[cfg(target_arch = "x86_64")] force_s2idle: cfg.force_s2idle, pvm_fw: pvm_fw_image, #[cfg(target_arch = "x86_64")] pcie_ecam: cfg.pcie_ecam, #[cfg(target_arch = "x86_64")] pci_low_start: cfg.pci_low_start, dynamic_power_coefficient: cfg.dynamic_power_coefficient.clone(), boot_cpu: cfg.boot_cpu, }) }
07-22
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值