• linux虚拟化: svm: 初始化及重要函数分析


    上一篇<>分析了基于内核的虚拟机(KVM)是一种内建于Linux的开源虚拟化技术,每个虚拟资源(虚拟机)可以表示为虚拟用户,kvm通过获取影子(虚拟)物理位,模拟出专用的寄存器,及页回收、用户统计等功能。本篇分析一款主要基于amd、海光芯片的虚拟化技术,svm,全名为支持向量机(support vector machines)。

    svm是一种虚拟机环境,可用于AMD64、海光64或Intel EM64T CPU。这种新型的虚拟机技术可以提高性能和节能,但您需要在使用任何使用它的软件之前启用它。

    支持向量机模式”是允许AMD处理器使用支持向量机指令集的功能。这对于需要同时兼容Intel、AMD和海光处理器的应用程序很有帮助。

    svm通过创建kvm,注册svm_init_ops初始操作结构,完成硬件的一系列初始化及包含功能操作结构的访问方式。

    svm_init_ops结构包括:
       has_svm                                      检查amd 或 海光芯片是否支持svm
       is_disabled                                   检查是否禁用功能
       svm_hardware_setup                   svm硬件相关设置
       svm_check_processor_compat    检查处理器兼容性
       svm_x86_ops                                svm(x86)操作结构
       amd_pmu_ops                              amd性能监控单元操作

    svm硬件相关设置:
       获取待分配页的订单大小,如果启用了NX大页面缓解,则影子分页和NPT都需要NX,分配页,获取页面映射的虚拟地址,填充内存(0xFF,每字节),获取kvm模式特征寄存器列表中的成员,经过偏移运算后写入msrpm_offsets[MSRPM_OFFSETS]列表,获取/设置标志位,并放入kvm_uret_msrs_list列表,检查暂停过滤支持,包括滤波暂停截距、暂停过滤器阈值,KVM的MMU本身不支持使用2级分页,因此如果主机使用2级寻呼,则不支持NPT,因为主机CR4在VMRUN上保持不变,强制VM NPT级别等于主机的分页级别,设置shadow_me_value和shadow_mo_mask,kvm内存管理单元设置掩码和值,sev硬件设置…,svm_hv硬件设置,设置刷新tlb相关函数,向量机cpu初始化…,avic硬件设置(包括LBR虚拟化支持),用于IOMMU驱动调用唤醒vcpu任务,svm设置cpu(寄存器)功能等等。


    目录


    1. 函数分析

    1.1 svm_init

    2. 源码结构

    3. 部分结构定义

    4. 扩展函数/变量


    1. 函数分析

    1.1 svm_init

      svm特征的kvm初始化

      svm 支持向量机(support vector machines)

    static int __init svm_init(void)
    {
            __unused_size_checks(); // 重要结构大小检查
     		// 虚拟控制保存区域
     		// 用户虚拟通讯保存区域
     		// 安全加密虚拟化状态保存区域
     		// 虚拟控制区域
     		// 用户(来宾)虚拟层通信块
    
            return kvm_init(&svm_init_ops, sizeof(struct vcpu_svm),
                            __alignof__(struct vcpu_svm), THIS_MODULE); //  kvm初始化(svm注册及后续使用)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    __unused_size_checks
    svm_init_ops


    2. 源码结构

      svm_init_ops svm初始操作

    static struct kvm_x86_init_ops svm_init_ops __initdata = {
            .cpu_has_kvm_support = has_svm, // 检查amd 或 海光芯片是否支持向量机
            .disabled_by_bios = is_disabled, // 检查是否禁用功能
            // 检查vm_cr设置位 
            // #define MSR_VM_CR                       0xc0010114
            
            .hardware_setup = svm_hardware_setup, // svm硬件相关设置
            .check_processor_compatibility = svm_check_processor_compat, // svm检查处理器兼容性
    
            .runtime_ops = &svm_x86_ops, // svm(x86)操作结构
            .pmu_ops = &amd_pmu_ops, // amd性能监控单元操作
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    svm_hardware_setup
    amd_pmu_ops

      amd_pmu_ops amd性能监控单元操作

      pmu 性能监控单元(performance monitoring unit)

    struct kvm_pmu_ops amd_pmu_ops __initdata = {
    	.hw_event_available = amd_hw_event_available, // 硬件事件可用
    	.pmc_is_enabled = amd_pmc_is_enabled, // 通过将PMC与global_ctrl位进行比较,检查PMC是否已启用
    	// 由于AMD CPU没有global_ctrl MSR,所有PMC都已启用(返回TRUE)
    	
    	.pmc_idx_to_pmc = amd_pmc_idx_to_pmc, 
    	.rdpmc_ecx_to_pmc = amd_rdpmc_ecx_to_pmc,
    	.msr_idx_to_pmc = amd_msr_idx_to_pmc,
    	.is_valid_rdpmc_ecx = amd_is_valid_rdpmc_ecx,
    	.is_valid_msr = amd_is_valid_msr,
    	.get_msr = amd_pmu_get_msr,
    	.set_msr = amd_pmu_set_msr,
    	.refresh = amd_pmu_refresh,
    	.init = amd_pmu_init,
    	.reset = amd_pmu_reset,
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

      svm_direct_access_msrs svm模式特征寄存器访问通道

    static const struct svm_direct_access_msrs {
    	u32 index;   /* MSR索引 */
    	bool always; /* 如果最初清除拦截,则为true */
    } direct_access_msrs[MAX_DIRECT_ACCESS_MSRS] = {
    	{ .index = MSR_STAR,				.always = true  }, // 传统模式SYSCALL目标
    	{ .index = MSR_IA32_SYSENTER_CS,		.always = true  }, // cs
    	{ .index = MSR_IA32_SYSENTER_EIP,		.always = false }, // eip
    	{ .index = MSR_IA32_SYSENTER_ESP,		.always = false }, // esp
    #ifdef CONFIG_X86_64
    	{ .index = MSR_GS_BASE,				.always = true  }, // 64位GS基地址
    	{ .index = MSR_FS_BASE,				.always = true  }, // 64位FS基地址 
    	{ .index = MSR_KERNEL_GS_BASE,			.always = true  }, // SwapGS GS影子
    	{ .index = MSR_LSTAR,				.always = true  }, // 长模式SYSCALL目标
    	{ .index = MSR_CSTAR,				.always = true  }, // 兼容模式SYSCALL目标
    	{ .index = MSR_SYSCALL_MASK,			.always = true  }, // 系统调用的EFLAGS掩码
    #endif
    	{ .index = MSR_IA32_SPEC_CTRL,			.always = false }, // 预测控制
    	{ .index = MSR_IA32_PRED_CMD,			.always = false }, // 预测命令
    	{ .index = MSR_IA32_LASTBRANCHFROMIP,		.always = false }, // 最后分支预测
    	{ .index = MSR_IA32_LASTBRANCHTOIP,		.always = false }, // 最后分支跳转
    	{ .index = MSR_IA32_LASTINTFROMIP,		.always = false }, // 最后分支中断(预测)
    	{ .index = MSR_IA32_LASTINTTOIP,		.always = false }, // 最后分支中断(执行)
    	{ .index = MSR_EFER,				.always = false }, // 读取扩展功能寄存器,32 or 64位
    	{ .index = MSR_IA32_CR_PAT,			.always = false }, // 页属性表控制寄存器
    	{ .index = MSR_AMD64_SEV_ES_GHCB,		.always = true  }, // 安全加密虚拟化状态 用户(来宾)虚拟层通信块
    	{ .index = MSR_TSC_AUX,				.always = false }, // 辅助TSC
    	// TSC  时间戳计数器(Time Stamp Counter)
    	
    	{ .index = X2APIC_MSR(APIC_ID),			.always = false }, apic id
    	// #define X2APIC_MSR(x)	(APIC_BASE_MSR + (x >> 4))
    	// #define APIC_BASE_MSR	0x800
    	// APIC 高级可编程中断控制器(Advanced Programmable Interrupt Controller)
    
    	{ .index = X2APIC_MSR(APIC_LVR),		.always = false }, // 传统I2C虚拟寄存器
    	{ .index = X2APIC_MSR(APIC_TASKPRI),		.always = false }, // 任务优先权
    	{ .index = X2APIC_MSR(APIC_ARBPRI),		.always = false }, // 公断优先权
    	{ .index = X2APIC_MSR(APIC_PROCPRI),		.always = false }, // 处理器优先权
    	{ .index = X2APIC_MSR(APIC_EOI),		.always = false }, // 退出IO
    	{ .index = X2APIC_MSR(APIC_RRR),		.always = false },
    	{ .index = X2APIC_MSR(APIC_LDR),		.always = false }, // ldr 
    	{ .index = X2APIC_MSR(APIC_DFR),		.always = false },
    	{ .index = X2APIC_MSR(APIC_SPIV),		.always = false },
    	{ .index = X2APIC_MSR(APIC_ISR),		.always = false }, // 中断服务寄存器
    	{ .index = X2APIC_MSR(APIC_TMR),		.always = false },
    	{ .index = X2APIC_MSR(APIC_IRR),		.always = false }, // 中断请求寄存器
    	{ .index = X2APIC_MSR(APIC_ESR),		.always = false },
    	{ .index = X2APIC_MSR(APIC_ICR),		.always = false },
    	{ .index = X2APIC_MSR(APIC_ICR2),		.always = false },
    
    	/*
    	 * 注:
    	 * AMD不虚拟化APIC TSC期限计时器模式,但它由KVM模拟
    	 * 当设置APIC LVTT(0x832)寄存器位18时,中航工业硬件将生成GP故障
    	 * 因此,始终拦截MSR 0x832,不要设置direct_access_MSR
    	 */
    	{ .index = X2APIC_MSR(APIC_LVTTHMR),		.always = false },
    	{ .index = X2APIC_MSR(APIC_LVTPC),		.always = false },
    	{ .index = X2APIC_MSR(APIC_LVT0),		.always = false },
    	{ .index = X2APIC_MSR(APIC_LVT1),		.always = false },
    	{ .index = X2APIC_MSR(APIC_LVTERR),		.always = false },
    	{ .index = X2APIC_MSR(APIC_TMICT),		.always = false },
    	{ .index = X2APIC_MSR(APIC_TMCCT),		.always = false },
    	{ .index = X2APIC_MSR(APIC_TDCR),		.always = false },
    	{ .index = MSR_INVALID,				.always = false },
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

      svm_x86_ops svm(x86)操作结构

    static struct kvm_x86_ops svm_x86_ops __initdata = {
    	.name = "kvm_amd",  名称
    
    	.hardware_unsetup = svm_hardware_unsetup, // 硬件移除设置(复原),包括释放页等
    	.hardware_enable = svm_hardware_enable, // 设置硬件状态,并启动/刷新虚拟事件
    	// 清除全局启用位,用更新的PERF_ctr_virt_mask重新编程PERF_CTL寄存器,然后再次设置全局启用位
    	
    	.hardware_disable = svm_hardware_disable, // 关闭当前CPU上的支持向量机,刷新虚拟事件
    	// 我们只屏蔽掉仅主机位,以便在禁用SVM时仅主机计数工作
    	如果有人在SVM被禁用时设置了仅来宾计数器,则仅来宾位仍然被设置,计数器将不计数任何内容
    	
    	.has_emulated_msr = svm_has_emulated_msr, // 判断是不是模拟器特征寄存器
    
    	.vcpu_create = svm_vcpu_create,
    	.vcpu_free = svm_vcpu_free,
    	.vcpu_reset = svm_vcpu_reset,
    
    	.vm_size = sizeof(struct kvm_svm),
    	.vm_init = svm_vm_init,
    	.vm_destroy = svm_vm_destroy,
    
    	.prepare_switch_to_guest = svm_prepare_switch_to_guest,
    	.vcpu_load = svm_vcpu_load,
    	.vcpu_put = svm_vcpu_put,
    	.vcpu_blocking = avic_vcpu_blocking,
    	.vcpu_unblocking = avic_vcpu_unblocking,
    
    	.update_exception_bitmap = svm_update_exception_bitmap,
    	.get_msr_feature = svm_get_msr_feature,
    	.get_msr = svm_get_msr,
    	.set_msr = svm_set_msr,
    	.get_segment_base = svm_get_segment_base,
    	.get_segment = svm_get_segment,
    	.set_segment = svm_set_segment,
    	.get_cpl = svm_get_cpl,
    	.get_cs_db_l_bits = svm_get_cs_db_l_bits,
    	.set_cr0 = svm_set_cr0,
    	.post_set_cr3 = sev_post_set_cr3,
    	.is_valid_cr4 = svm_is_valid_cr4,
    	.set_cr4 = svm_set_cr4,
    	.set_efer = svm_set_efer,
    	.get_idt = svm_get_idt,
    	.set_idt = svm_set_idt,
    	.get_gdt = svm_get_gdt,
    	.set_gdt = svm_set_gdt,
    	.set_dr7 = svm_set_dr7,
    	.sync_dirty_debug_regs = svm_sync_dirty_debug_regs,
    	.cache_reg = svm_cache_reg,
    	.get_rflags = svm_get_rflags,
    	.set_rflags = svm_set_rflags,
    	.get_if_flag = svm_get_if_flag,
    
    	.flush_tlb_all = svm_flush_tlb_current,
    	.flush_tlb_current = svm_flush_tlb_current,
    	.flush_tlb_gva = svm_flush_tlb_gva,
    	.flush_tlb_guest = svm_flush_tlb_current,
    
    	.vcpu_pre_run = svm_vcpu_pre_run,
    	.vcpu_run = svm_vcpu_run,
    	.handle_exit = svm_handle_exit,
    	.skip_emulated_instruction = svm_skip_emulated_instruction,
    	.update_emulated_instruction = NULL,
    	.set_interrupt_shadow = svm_set_interrupt_shadow,
    	.get_interrupt_shadow = svm_get_interrupt_shadow,
    	.patch_hypercall = svm_patch_hypercall,
    	.inject_irq = svm_inject_irq,
    	.inject_nmi = svm_inject_nmi,
    	.inject_exception = svm_inject_exception,
    	.cancel_injection = svm_cancel_injection,
    	.interrupt_allowed = svm_interrupt_allowed,
    	.nmi_allowed = svm_nmi_allowed,
    	.get_nmi_mask = svm_get_nmi_mask,
    	.set_nmi_mask = svm_set_nmi_mask,
    	.enable_nmi_window = svm_enable_nmi_window,
    	.enable_irq_window = svm_enable_irq_window,
    	.update_cr8_intercept = svm_update_cr8_intercept,
    	.set_virtual_apic_mode = avic_set_virtual_apic_mode,
    	.refresh_apicv_exec_ctrl = avic_refresh_apicv_exec_ctrl,
    	.check_apicv_inhibit_reasons = avic_check_apicv_inhibit_reasons,
    	.apicv_post_state_restore = avic_apicv_post_state_restore,
    
    	.get_exit_info = svm_get_exit_info,
    
    	.vcpu_after_set_cpuid = svm_vcpu_after_set_cpuid,
    
    	.has_wbinvd_exit = svm_has_wbinvd_exit,
    
    	.get_l2_tsc_offset = svm_get_l2_tsc_offset,
    	.get_l2_tsc_multiplier = svm_get_l2_tsc_multiplier,
    	.write_tsc_offset = svm_write_tsc_offset,
    	.write_tsc_multiplier = svm_write_tsc_multiplier,
    
    	.load_mmu_pgd = svm_load_mmu_pgd,
    
    	.check_intercept = svm_check_intercept,
    	.handle_exit_irqoff = svm_handle_exit_irqoff,
    
    	.request_immediate_exit = __kvm_request_immediate_exit,
    
    	.sched_in = svm_sched_in,
    
    	.nested_ops = &svm_nested_ops,
    
    	.deliver_interrupt = svm_deliver_interrupt,
    	.pi_update_irte = avic_pi_update_irte,
    	.setup_mce = svm_setup_mce,
    
    	.smi_allowed = svm_smi_allowed,
    	.enter_smm = svm_enter_smm,
    	.leave_smm = svm_leave_smm,
    	.enable_smi_window = svm_enable_smi_window,
    
    	.mem_enc_ioctl = sev_mem_enc_ioctl,
    	.mem_enc_register_region = sev_mem_enc_register_region,
    	.mem_enc_unregister_region = sev_mem_enc_unregister_region,
    	.guest_memory_reclaimed = sev_guest_memory_reclaimed,
    
    	.vm_copy_enc_context_from = sev_vm_copy_enc_context_from,
    	.vm_move_enc_context_from = sev_vm_move_enc_context_from,
    
    	.can_emulate_instruction = svm_can_emulate_instruction,
    
    	.apic_init_signal_blocked = svm_apic_init_signal_blocked,
    
    	.msr_filter_changed = svm_msr_filter_changed,
    	.complete_emulated_msr = svm_complete_emulated_msr,
    
    	.vcpu_deliver_sipi_vector = svm_vcpu_deliver_sipi_vector,
    	.vcpu_get_apicv_inhibit_reasons = avic_vcpu_get_apicv_inhibit_reasons,
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130

    cpu_hw_events
    svm_vcpu_create

      reverse_cpuid 逆向(存储)cpuid

    struct cpuid_reg {  // cpuid 注册
    	u32 function; // 功能
    	u32 index; // 索引
    	int reg; // 寄存器
    };
    
    static const struct cpuid_reg reverse_cpuid[] = {
    	[CPUID_1_EDX]         = {         1, 0, CPUID_EDX},
    	[CPUID_8000_0001_EDX] = {0x80000001, 0, CPUID_EDX},
    	[CPUID_8086_0001_EDX] = {0x80860001, 0, CPUID_EDX},
    	[CPUID_1_ECX]         = {         1, 0, CPUID_ECX},
    	[CPUID_C000_0001_EDX] = {0xc0000001, 0, CPUID_EDX},
    	[CPUID_8000_0001_ECX] = {0x80000001, 0, CPUID_ECX},
    	[CPUID_7_0_EBX]       = {         7, 0, CPUID_EBX},
    	[CPUID_D_1_EAX]       = {       0xd, 1, CPUID_EAX},
    	[CPUID_8000_0008_EBX] = {0x80000008, 0, CPUID_EBX},
    	[CPUID_6_EAX]         = {         6, 0, CPUID_EAX},
    	[CPUID_8000_000A_EDX] = {0x8000000a, 0, CPUID_EDX},
    	[CPUID_7_ECX]         = {         7, 0, CPUID_ECX},
    	[CPUID_8000_0007_EBX] = {0x80000007, 0, CPUID_EBX},
    	[CPUID_7_EDX]         = {         7, 0, CPUID_EDX},
    	[CPUID_7_1_EAX]       = {         7, 1, CPUID_EAX},
    	[CPUID_12_EAX]        = {0x00000012, 0, CPUID_EAX},
    	[CPUID_8000_001F_EAX] = {0x8000001f, 0, CPUID_EAX},
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    3. 部分结构定义

      vmcb_save_area 虚拟控制保存区域

    /* 为遗留和SEV-MEM客户机保存区域定义 */
    struct vmcb_save_area {
    	struct vmcb_seg es; // 虚拟控制段 es
    	struct vmcb_seg cs;
    	struct vmcb_seg ss;
    	struct vmcb_seg ds;
    	struct vmcb_seg fs;
    	struct vmcb_seg gs;
    	struct vmcb_seg gdtr;
    	struct vmcb_seg ldtr;
    	struct vmcb_seg idtr;
    	struct vmcb_seg tr;
    	u8 reserved_1[42];
    	u8 vmpl;
    	u8 cpl;
    	u8 reserved_2[4];
    	u64 efer;
    	u8 reserved_3[112];
    	u64 cr4;
    	u64 cr3;
    	u64 cr0;
    	u64 dr7;
    	u64 dr6;
    	u64 rflags;
    	u64 rip;
    	u8 reserved_4[88];
    	u64 rsp;
    	u64 s_cet;
    	u64 ssp;
    	u64 isst_addr;
    	u64 rax;
    	u64 star;
    	u64 lstar;
    	u64 cstar;
    	u64 sfmask;
    	u64 kernel_gs_base;
    	u64 sysenter_cs;
    	u64 sysenter_esp;
    	u64 sysenter_eip;
    	u64 cr2;
    	u8 reserved_5[32];
    	u64 g_pat;
    	u64 dbgctl;
    	u64 br_from;
    	u64 br_to;
    	u64 last_excp_from;
    	u64 last_excp_to;
    	u8 reserved_6[72];
    	u32 spec_ctrl;		/* SPEC_CTRL在0x2E0的客户版本 */
    } __packed;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    vmcb_seg

      vmcb_seg 虚拟控制段

      vmcb 虚拟机控制块(Virtual Machine Control Block)

    struct vmcb_seg {
    	u16 selector; // 选择器
    	u16 attrib; // 属性
    	u32 limit; // 限制
    	u64 base; // 基地址
    } __packed;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

      svm_cpu_data 向量机cpu数据

      svm 支持向量机(support vector machines)

    struct svm_cpu_data {
    	u64 asid_generation; 通用地址空间标识符
    	// asid  地址空间标识符(address space identifier)
    	
    	u32 max_asid; // 最大值
    	u32 next_asid; // 下一个
    	u32 min_asid; // 最小值
    	struct kvm_ldttss_desc *tss_desc;
    
    	struct page *save_area; // 保存区域
    	unsigned long save_area_pa; 
    
    	struct vmcb *current_vmcb; 当前的虚拟控制块
    	// vmcb 虚拟机控制块(Virtual Machine Control Block)
    
    	/* index = sev_asid, value = vmcb pointer */
    	struct vmcb **sev_vmcbs; // 安全加密虚拟控制块
    	// sev 安全加密虚拟化(Secure Encrypted Virtualization)
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

      cpu_hw_events cpu硬件事件

    struct cpu_hw_events {
    	/*
    	 * 通用x86 PMC位
    	 * PMC 性能监视器计数器(Performance Monitor Counter)
    	 */
    	struct perf_event	*events[X86_PMC_IDX_MAX]; /* order计数 */
    	unsigned long		active_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
    	unsigned long		dirty[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
    	int			enabled;
    
    	int			n_events; /* 下面数组中的事件 */
    	int			n_added;  /* 以下数组中的最后一个事件;它们从未启用过 */
    	int			n_txn;    /* 以下数组中的最后一个事件;添加到当前事务中 */
    	int			n_txn_pair;
    	int			n_txn_metric;
    	int			assign[X86_PMC_IDX_MAX]; /* 事件到计数器分配 */
    	u64			tags[X86_PMC_IDX_MAX];
    
    	struct perf_event	*event_list[X86_PMC_IDX_MAX]; /* 按启用顺序 */
    	struct event_constraint	*event_constraint[X86_PMC_IDX_MAX];
    
    	int			n_excl; /* 独占事件的数量 */
    
    	unsigned int		txn_flags;
    	int			is_fake;
    
    	/*
    	 * 英特尔DebugStore位
    	 */
    	struct debug_store	*ds;
    	void			*ds_pebs_vaddr;
    	void			*ds_bts_vaddr;
    	u64			pebs_enabled;
    	int			n_pebs;
    	int			n_large_pebs;
    	int			n_pebs_via_pt;
    	int			pebs_output;
    
    	/* 当前事件硬件配置的超级集 */
    	u64			pebs_data_cfg;
    	u64			active_pebs_data_cfg;
    	int			pebs_record_size;
    
    	/* Intel固定计数器配置 */
    	u64			fixed_ctrl_val;
    	u64			active_fixed_ctrl_val;
    
    	/*
    	 * Intel LBR位
    	 */
    	int				lbr_users;
    	int				lbr_pebs_users;
    	struct perf_branch_stack	lbr_stack;
    	struct perf_branch_entry	lbr_entries[MAX_LBR_ENTRIES];
    	union {
    		struct er_account		*lbr_sel;
    		struct er_account		*lbr_ctl;
    	};
    	u64				br_sel;
    	void				*last_task_ctx;
    	int				last_log_id;
    	int				lbr_select;
    	void				*lbr_xsave;
    
    	/*
    	 * Intel主机/来宾排除位
    	 */
    	u64				intel_ctrl_guest_mask;
    	u64				intel_ctrl_host_mask;
    	struct perf_guest_switch_msr	guest_switch_msrs[X86_PMC_IDX_MAX];
    
    	/*
    	 * 英特尔检查点掩码
    	 */
    	u64				intel_cp_status;
    
    	/*
    	 * 管理在Intel NHM/WSM/SNB上使用的共享(每核,每cpu)寄存器
    	 */
    	struct intel_shared_regs	*shared_regs;
    	/*
    	 * 管理超线程之间的独占计数器访问
    	 */
    	struct event_constraint *constraint_list; /* 按启用顺序 */
    	struct intel_excl_cntrs		*excl_cntrs;
    	int excl_thread_id; /* 0 or 1 */
    
    	/*
    	 * SKL TSX_FORCE_ABORT shadow
    	 */
    	u64				tfa_shadow;
    
    	/*
    	 * 性能指标
    	 */
    	/* 接受的度量事件数 */
    	int				n_metric;
    
    	/*
    	 * AMD特定位
    	 */
    	struct amd_nb			*amd_nb;
    	int				brs_active; /* 启用BRS */
    
    	/* 要在perf_ctr ctrl寄存器中清除的位的反转掩码 */
    	u64				perf_ctr_virt_mask;
    	int				n_pair; /* 大增量事件 */
    
    	void				*kfree_on_online[X86_PERF_KFREE_MAX];
    
    	struct pmu			*pmu; // 通用性能监视单元
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112

      pmu 通用性能监视单元(generic performance monitoring unit)

    struct pmu {
    	struct list_head		entry; // 列表
    
    	struct module			*module; // 模式
    	struct device			*dev; // 设备
    	const struct attribute_group	**attr_groups; // 属性组
    	const struct attribute_group	**attr_update; // 性能测试相关的属性组
    	const char			*name; // 名称
    	int				type; // 类型
    
    	/*
    	 * 各种常见的per-pmu特性标志
    	 */
    	int				capabilities;
    
    	int __percpu			*pmu_disable_count;
    	struct perf_cpu_context __percpu *pmu_cpu_context;
    	atomic_t			exclusive_cnt; /* < 0: cpu; > 0: tsk */
    	int				task_ctx_nr;
    	int				hrtimer_interval_ms;
    
    	/* 此PMU可以执行的地址筛选器数 */
    	unsigned int			nr_addr_filters;
    
    	/*
    	 * 完全禁用/启用PMU,可以用于防止PMI以及MSRs的惰性/批量写入
    	 */
    	void (*pmu_enable)		(struct pmu *pmu); /* optional */
    	void (*pmu_disable)		(struct pmu *pmu); /* optional */
    
    	/*
    	 * 尝试并初始化此PMU的事件
    	 *
    	 * Returns:
    	 *  -ENOENT	-- @event is not for this PMU
    	 *
    	 *  -ENODEV	-- @event is for this PMU but PMU not present
    	 *  -EBUSY	-- @event is for this PMU but PMU temporarily unavailable
    	 *  -EINVAL	-- @event is for this PMU but @event is not valid
    	 *  -EOPNOTSUPP -- @event is for this PMU, @event is valid, but not supported
    	 *  -EACCES	-- @event is for this PMU, @event is valid, but no privileges
    	 *
    	 *  0		-- @event is for this PMU and valid
    	 *
    	 * Other error return values are allowed.
    	 */
    	int (*event_init)		(struct perf_event *event);
    
    	/*
    	 * 已映射或未映射事件的通知
    	 * 在映射任务的上下文中调用
    	 */
    	void (*event_mapped)		(struct perf_event *event, struct mm_struct *mm); /* optional */
    	void (*event_unmapped)		(struct perf_event *event, struct mm_struct *mm); /* optional */
    
    	/*
    	 * Flags for ->add()/->del()/ ->start()/->stop(). There are
    	 * matching hw_perf_event::state flags.
    	 */
    #define PERF_EF_START	0x01		/* 添加时启动计数器    */
    #define PERF_EF_RELOAD	0x02		/* 启动时重新加载计数器 */
    #define PERF_EF_UPDATE	0x04		/* 停止时更新计数器 */
    
    	/*
    	 * 向PMU中添加/从PMU中删除一个计数器,可以在事务中完成,参见->*_txn()方法
    	 *
    	 * 添加/删除回调将保留服务事件所需的所有硬件资源,这包括任何计数器约束调度等
    	 *
    	 * 在禁用IRQs和禁用CPU上的PMU的情况下调用该事件
    	 *
    	 * 在没有PERF_EF_START的情况下调用的add()
    	 * 应导致与->add() 后 跟->stop()相同的状态
    	 *
    	 * del()必须总是PERF_EF_UPDATE停止一个事件
    	 * 如果它调用->stop(),则必须在没有PERF_EF_UPDATE的情况下处理已经停止的情况
    	 */
    	int  (*add)			(struct perf_event *event, int flags);
    	void (*del)			(struct perf_event *event, int flags);
    
    	/*
    	 * 启动/停止PMU上的计数器
    	 *
    	 * 当perf_event_overflow()返回!0时,PMI处理程序应该停止计数器
    	 * ->start()将用于继续
    	 *
    	 * 也用于更改采样周期
    	 *
    	 * 在事件发生的CPU上禁用IRQ和禁用PMU的情况下调用--将从NMI上下文调用,PMU生成NMI
    	 *
    	 * 带有PERF_EF_UPDATE的stop()将读取计数器并更新周期/计数值,如->read()
    	 *
    	 * 带有PERF_EF_RELOAD的start()将重新编程计数器值
    	 * 前面必须是带有PERF_EFI_UPDATE的->stop()
    	 */
    	void (*start)			(struct perf_event *event, int flags);
    	void (*stop)			(struct perf_event *event, int flags);
    
    	/*
    	 * 更新事件的计数器值
    	 *
    	 * 对于具有采样能力的PMU,这还将更新软件周期hw_perf_event :: period_left字段
    	 */
    	void (*read)			(struct perf_event *event);
    
    	/*
    	 * 组事件调度被视为一个事务,将组事件作为一个整体添加,并执行一个可调度性测试
    	 * 如果测试失败,则回退整个组
    	 *
    	 * 启动事务,之后
    	 * this->add()不需要进行可调度性测试
    	 *
    	 * 可选的
    	 */
    	void (*start_txn)		(struct pmu *pmu, unsigned int txn_flags);
    	/*
    	 * 如果->start_txn()禁用了->add()可调度性测试,则->commit_txn()需要执行一个
    	 * 如果成功,则关闭事务
    	 * 如果出现错误,事务将保持打开状态,直到->cancel_txn()被调用
    	 *
    	 * 可选的
    	 */
    	int  (*commit_txn)		(struct pmu *pmu);
    	/*
    	 * 将取消事务,假设->del()被调用为每个成功的->add()在事务中
    	 *
    	 * 可选的
    	 */
    	void (*cancel_txn)		(struct pmu *pmu);
    
    	/*
    	 * 将返回此事件的perf_event_mmap_page::index的值,如果未提供实现
    	 * 则默认为:event->hw.idx+1
    	 */
    	int (*event_idx)		(struct perf_event *event); /* 可选的 */
    
    	/*
    	 * 上下文切换回调
    	 */
    	void (*sched_task)		(struct perf_event_context *ctx,
    					bool sched_in);
    
    	/*
    	 * PMU特定数据的Kmem缓存
    	 */
    	struct kmem_cache		*task_ctx_cache;
    
    	/*
    	 * 任务性能事件上下文的PMU特定部分(即ctx->task_ctx_data)可以使用此函数进行同步
    	 * 有关用法示例,请参阅Intel LBR调用堆栈支持实现和Perf核心上下文开关处理回调
    	 */
    	void (*swap_task_ctx)		(struct perf_event_context *prev,
    					 struct perf_event_context *next);
    					/* 可选的 */
    
    	/*
    	 * 为AUX区域设置pmu专用数据结构
    	 */
    	void *(*setup_aux)		(struct perf_event *event, void **pages,
    					 int nr_pages, bool overwrite);
    					/* 可选的 */
    
    	/*
    	 * 释放 pmu-private AUX数据结构
    	 */
    	void (*free_aux)		(void *aux); /* 可选的 */
    
    	/*
    	 * 在不接触事件状态的情况下拍摄AUX缓冲区的快照,以便抢占->start() /->stop()回调不会干扰其逻辑
    	 * 在PMI上下文中调用
    	 *
    	 * 返回复制到输出句柄的AUX数据的大小
    	 *
    	 * 可选的
    	 */
    	long (*snapshot_aux)		(struct perf_event *event,
    					 struct perf_output_handle *handle,
    					 unsigned long size);
    
    	/*
    	 * 验证地址范围筛选器:确保硬件支持请求的配置和筛选器数量
    	 * 如果提供的筛选器有效,则返回0,否则返回-errno
    	 *
    	 * 在ioctl()进程的上下文中运行,不会与其他PMU回调一起序列化
    	 */
    	int (*addr_filters_validate)	(struct list_head *filters);
    					/* 可选的 */
    
    	/*
    	 * 同步地址范围筛选器配置:
    	 * 在event::hw::addr_filters中,将hw不可知筛选器转换为硬件配置
    	 *
    	 * 作为过滤器同步序列的一部分运行
    	 * 该序列通过调用perf_event_addr_filters_sync()在->start()回调中完成
    	 *
    	 * 可以(并且应该)遍历event::addr_filters::list,其调用者为其提供必要的序列化
    	 */
    	void (*addr_filters_sync)	(struct perf_event *event);
    					/* 可选的 */
    
    	/*
    	 * 检查事件是否可用于此PMU事件的aux_输出目的
    	 *
    	 * 从perf_event_open()运行
    	 * 对于“不匹配”应返回0,对于“匹配”应为非零
    	 */
    	int (*aux_output_match)		(struct perf_event *event);
    					/* 可选的 */
    
    	/*
    	 * 筛选PMU特定原因的事件
    	 */
    	int (*filter_match)		(struct perf_event *event); /* 可选的 */
    
    	/*
    	 * 检查PERF_EVENT_IOC_period ioctl的周期值
    	 */
    	int (*check_period)		(struct perf_event *event, u64 value); /* 可选的 */
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218

      kvm_only_cpuid_leafs kvm的CPUID叶

    /*
     * 硬件定义的CPUID叶散布在内核中,但需要由KVM直接使用
     * 注意,这些单词值与内核的“bug”上限冲突,但KVM不使用这些
     * /
    enum kvm_only_cpuid_leafs {
    	CPUID_12_EAX	 = NCAPINTS, // 20
    	NR_KVM_CPU_CAPS, // 21
    
    	NKVMCAPINTS = NR_KVM_CPU_CAPS - NCAPINTS, // 1
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

      cpuinfo_x86 每(个)cpu的数据结构

    struct cpuinfo_x86 {
    	__u8			x86;		/* CPU系列 */
    	__u8			x86_vendor;	/* CPU厂商 */
    	__u8			x86_model;  /* 模式 */
    	__u8			x86_stepping; /* 步进 */
    #ifdef CONFIG_X86_64
    	/* DTLB/ITLB中4K页面的总和(以页为单位) */
    	int			x86_tlbsize;
    #endif
    #ifdef CONFIG_X86_VMX_FEATURE_NAMES
    	__u32			vmx_capability[NVMXINTS];
    #endif
    	__u8			x86_virt_bits; /* 虚拟位数 */
    	__u8			x86_phys_bits; /* 物理位数 */
    	/* CPUID返回的核心id位 */
    	__u8			x86_coreid_bits;
    	__u8			cu_id;
    	/* 支持的最大扩展CPUID功能 */
    	__u32			extended_cpuid_level;
    	/* 支持的最大CPUID级别,-1=no CPUID */
    	int			cpuid_level;
    	/*
    	 * 对齐到无符号长的大小,因为x86_capability数组被传递给需要对齐的位操作
    	 * 使用未命名的并集强制数组与无符号long的大小对齐
    	 */
    	union {
    		__u32		x86_capability[NCAPINTS + NBUGINTS];
    		unsigned long	x86_capability_alignment;
    	};
    	char			x86_vendor_id[16];
    	char			x86_model_id[64];
    	/* 以KB为单位-对支持此呼叫的CPUS有效 */
    	unsigned int		x86_cache_size;
    	int			x86_cache_alignment;	/* 以字节为单位 */
    	/* 缓存QoS体系结构值,仅在BSP上有效 */
    	int			x86_cache_max_rmid;	/* 最大指数 */
    	int			x86_cache_occ_scale;	/* 缩放到字节 */
    	int			x86_cache_mbm_width_offset;
    	int			x86_power;
    	unsigned long		loops_per_jiffy;
    	/* 受保护的处理器识别号 */
    	u64			ppin;
    	/* cpuid返回的最大颜色值 */
    	u16			x86_max_cores;
    	u16			apicid;
    	u16			initial_apicid;
    	u16			x86_clflush_size;
    	/* 操作系统显示的颜色数 */
    	u16			booted_cores;
    	/* 物理处理器id */
    	u16			phys_proc_id;
    	/* 逻辑处理器id */
    	u16			logical_proc_id;
    	/* 核心id */
    	u16			cpu_core_id;
    	u16			cpu_die_id;
    	u16			logical_die_id;
    	/* per_cpu列表索引 */
    	u16			cpu_index;
    	/* SMT在此核心上是否活动? */
    	bool			smt_active;
    	u32			microcode;
    	/* 缓存内部使用的地址空间位 */
    	u8			x86_cache_bits;
    	unsigned		initialized : 1;
    } __randomize_layout;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

      cpuid_leafs cpuid叶

    enum cpuid_leafs
    {
    	CPUID_1_EDX		= 0,
    	CPUID_8000_0001_EDX,
    	CPUID_8086_0001_EDX,
    	CPUID_LNX_1,
    	CPUID_1_ECX,
    	CPUID_C000_0001_EDX,
    	CPUID_8000_0001_ECX,
    	CPUID_LNX_2,
    	CPUID_LNX_3,
    	CPUID_7_0_EBX,
    	CPUID_D_1_EAX,
    	CPUID_LNX_4,
    	CPUID_7_1_EAX,
    	CPUID_8000_0008_EBX,
    	CPUID_6_EAX,
    	CPUID_8000_000A_EDX,
    	CPUID_7_ECX,
    	CPUID_8000_0007_EBX,
    	CPUID_7_EDX,
    	CPUID_8000_001F_EAX,
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    4. 扩展函数/变量

      __unused_size_checks 重要结构大小检查

      虚拟控制保存区域
      用户虚拟通讯保存区域
      安全加密虚拟化状态保存区域
      虚拟控制区域
      用户(来宾)虚拟层通信块

    static inline void __unused_size_checks(void)
    {
            BUILD_BUG_ON(sizeof(struct vmcb_save_area)      != EXPECTED_VMCB_SAVE_AREA_SIZE); // 虚拟控制保存区域检查
            // vmcb 虚拟机控制块(Virtual Machine Control Block)
            // #define EXPECTED_VMCB_SAVE_AREA_SIZE		740
            
            BUILD_BUG_ON(sizeof(struct ghcb_save_area)      != EXPECTED_GHCB_SAVE_AREA_SIZE); // 用户虚拟通讯保存区域
            // ghcb   用户(来宾)虚拟层通信块(Guest Hypervisor Communication Block)
            // #define EXPECTED_GHCB_SAVE_AREA_SIZE		1032
            
            BUILD_BUG_ON(sizeof(struct sev_es_save_area)    != EXPECTED_SEV_ES_SAVE_AREA_SIZE); // 安全加密虚拟化状态保存区域
    		// sev 安全加密虚拟化(Secure Encrypted Virtualization)
    		// es  加密状态(Encrypted State)
    		// #define EXPECTED_SEV_ES_SAVE_AREA_SIZE		1648
    		
            BUILD_BUG_ON(sizeof(struct vmcb_control_area)   != EXPECTED_VMCB_CONTROL_AREA_SIZE); // 虚拟控制区域
            // #define EXPECTED_VMCB_CONTROL_AREA_SIZE		1024
            
            BUILD_BUG_ON(sizeof(struct ghcb)                != EXPECTED_GHCB_SIZE); // 用户(来宾)虚拟层通信块
            // #define EXPECTED_GHCB_SIZE			PAGE_SIZE
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    vmcb_save_area

      svm_hardware_setup svm硬件相关设置

      获取待分配页的订单大小
      如果启用了NX大页面缓解,则影子分页和NPT都需要NX
      分配页,获取页面映射的虚拟地址,填充内存(0xFF,每字节)
      获取kvm模式特征寄存器列表中的成员
      经过偏移运算后写入msrpm_offsets[MSRPM_OFFSETS]列表
      获取/设置标志位,并放入kvm_uret_msrs_list列表
      检查暂停过滤支持,包括滤波暂停截距、暂停过滤器阈值

      KVM的MMU本身不支持使用2级分页,因此如果主机使用2级寻呼,
      则不支持NPT,因为主机CR4在VMRUN上保持不变

      强制VM NPT级别等于主机的分页级别,设置shadow_me_value和shadow_mo_mask
      kvm内存管理单元设置掩码和值
      sev硬件设置
      svm_hv硬件设置,设置刷新tlb相关函数
      向量机cpu初始化
      avic硬件设置(包括LBR虚拟化支持),用于IOMMU驱动调用唤醒vcpu任务
      svm设置cpu(寄存器)功能

    static __init int svm_hardware_setup(void)
    {
    	int cpu;
    	struct page *iopm_pages;
    	void *iopm_va;
    	int r;
    	unsigned int order = get_order(IOPM_SIZE); // 获取待分配页的订单大小
    	// #define	IOPM_SIZE PAGE_SIZE * 3
    
    	/*
    	 * 如果启用了NX大页面缓解,则影子分页和NPT都需要NX
    	 */
    	if (!boot_cpu_has(X86_FEATURE_NX)) { // 是否设置禁止运行位
    	// #define X86_FEATURE_NX			( 1*32+20) /* 禁用运行 */
    	// NX (No execute) 禁止运行
    	
    		pr_err_ratelimited("NX (Execute Disable) not supported\n");
    		return -EOPNOTSUPP;
    	}
    
    	kvm_enable_efer_bits(EFER_NX);
    	// #define EFER_NX			(1<<_EFER_NX)
    	// #define _EFER_NX		11 /* 启用不执行 */
    
    	iopm_pages = alloc_pages(GFP_KERNEL, order); // 分配页
    
    	iopm_va = page_address(iopm_pages); // 获取页面映射的虚拟地址
    	memset(iopm_va, 0xff, PAGE_SIZE * (1 << order)); // 填充内存
    	iopm_base = page_to_pfn(iopm_pages) << PAGE_SHIFT;  // 物理页框号左移12位得到基地址
    
    	init_msrpm_offsets(); // 获取kvm模式特征寄存器列表中的成员,经过偏移运算后写入msrpm_offsets[MSRPM_OFFSETS]列表
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    svm_direct_access_msrs

    	kvm_caps.supported_xcr0 &= ~(XFEATURE_MASK_BNDREGS |
    				     XFEATURE_MASK_BNDCSR); // supported_xcr0 移除这两个标志
    
    	...
    	kvm_caps.max_tsc_scaling_ratio = SVM_TSC_RATIO_MAX;
    	kvm_caps.tsc_scaling_ratio_frac_bits = 32;
    
    	tsc_aux_uret_slot = kvm_add_user_return_msr(MSR_TSC_AUX);	// 获取/设置标志位,并放入kvm_uret_msrs_list列表
    
    	/* 检查暂停过滤支持 */
    	if (!boot_cpu_has(X86_FEATURE_PAUSEFILTER)) { // 滤波暂停截距
    		pause_filter_count = 0;
    		pause_filter_thresh = 0;
    	} else if (!boot_cpu_has(X86_FEATURE_PFTHRESHOLD)) { // 暂停过滤器阈值
    		pause_filter_thresh = 0;
    	}
    
    	if (nested) {
    		printk(KERN_INFO "kvm: Nested Virtualization enabled\n");
    		kvm_enable_efer_bits(EFER_SVME | EFER_LMSLE);
    	}
    
    	/*
    	 * KVM的MMU本身不支持使用2级分页,因此如果主机使用2级寻呼,
    	 * 则不支持NPT,因为主机CR4在VMRUN上保持不变
    	 */
    	if (!IS_ENABLED(CONFIG_X86_64) && !IS_ENABLED(CONFIG_X86_PAE))
    		npt_enabled = false;
    
    	if (!boot_cpu_has(X86_FEATURE_NPT))
    		npt_enabled = false;
    
    	/* 强制VM NPT级别等于主机的分页级别 */
    	kvm_configure_mmu(npt_enabled, get_npt_level(),
    			  get_npt_level(), PG_LEVEL_1G);
    
    	/* 设置shadow_me_value和shadow_mo_mask */
    	kvm_mmu_set_me_spte_mask(sme_me_mask, sme_me_mask);
    
    	svm_adjust_mmio_mask(); // kvm内存管理单元设置掩码和值
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    svm_adjust_mmio_mask

    	/*
    	 * SEV设置使用npt_enabled和enable_mmio_catching(可以通过svm_adjust_mmio_mask()修改)
    	 */
    	sev_hardware_setup(); // sev硬件设置
    
    • 1
    • 2
    • 3
    • 4

    sev_hardware_setup

    svm_hv_hardware_setup(); // svm_hv硬件设置
    // 设置刷新tlb相关函数
    
    /*
     * 这是AMD特有的,并指定支持开明TLB刷新
     * 如果用户选择此功能,ASID失效仅刷新gva->hpa映射条目
     * 要刷新从NPT派生的TLB条目,
     * 应使用超级调用(HvFlushGuestPhysicalAddressSpace或HvFlush GuestPhysical AddressList)
     * /
    // #define HV_X64_NESTED_ENLIGHTENED_TLB			BIT(22) 
    
    /* 嵌套的功能. 这些是 HYPERV_CPUID_NESTED_FEATURES.EAX 位. */
    // #define HV_X64_NESTED_DIRECT_FLUSH			BIT(17)
    
    for_each_possible_cpu(cpu) {
    		r = svm_cpu_init(cpu); // 向量机cpu初始化
    		if (r)
    			goto err;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    svm_cpu_data

    if (nrips) { // 启用下一次RIP保存
    		if (!boot_cpu_has(X86_FEATURE_NRIPS))
    			nrips = false;
    	}
    
    enable_apicv = avic = avic && avic_hardware_setup(&svm_x86_ops); // avic硬件设置,用于IOMMU驱动调用唤醒vcpu任务
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    svm_x86_ops
    avic_hardware_setup

    if (vls) {
    // 启用/禁用虚拟VMLOAD VMSAVE 
    // static int vls = true;
    // module_param(vls, int, 0444);
    
    		if (!npt_enabled ||
    		    !boot_cpu_has(X86_FEATURE_V_VMSAVE_VMLOAD) ||
    		    !IS_ENABLED(CONFIG_X86_64)) { // 都有效,执行下面分支
    		// #define X86_FEATURE_V_VMSAVE_VMLOAD	(15*32+15) /* Virtual VMSAVE VMLOAD */
    		
    			vls = false;
    		} else {
    			pr_info("Virtual VMLOAD VMSAVE supported\n");
    		}
    	}
    
    	if (boot_cpu_has(X86_FEATURE_SVME_ADDR_CHK))
    	// #define X86_FEATURE_SVME_ADDR_CHK	(15*32+28) /* SVME地址检查 */
    		svm_gp_erratum_intercept = false;
    
    	if (vgif) {
    		if (!boot_cpu_has(X86_FEATURE_VGIF))
    		// #define X86_FEATURE_VGIF		(15*32+16) /* Virtual GIF */
    		// 启用此功能后,处理器在执行STGI/CLGI指令时使用60h位置的第9位作为虚拟GIF
    		// 即使没有设置GIF,也会打开IRQ窗口,假设在恢复L1 hypervisor时,IRQ将保持挂起状态,直到处理器执行STGI指令
    		// 对于NMI窗口,设置了STGI拦截。这将有助于仅在GIF=1时打开窗口
    		// NMI 不可屏蔽中断(Nonmaskable Interrupt)
    		
    			vgif = false;
    		else
    			pr_info("Virtual GIF supported\n");
    	}
    
    	if (lbrv) {
    		if (!boot_cpu_has(X86_FEATURE_LBRV))
    		// #define X86_FEATURE_LBRV		(15*32+ 1) /* LBR虚拟化支持 */
    		// LBR 最后分支记录(Last Branch Records)
    			lbrv = false;
    		else
    			pr_info("LBR virtualization supported\n");
    	}
    
    	svm_set_cpu_caps(); // svm设置cpu(寄存器)功能
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    svm_set_cpu_caps

    	/*
    	 * 似乎在AMD处理器上,PTE的访问位是由CPU硬件在NPF vmexit之前设置的
    	 * 这不是预期的行为,我们的测试因此失败
    	 * 这里的一个解决方法是禁用对GUEST_MAXPHYADDR < HOST_MAXPHYADDR的支持,如果NPT是启用的
    	 * 在这种情况下,用户空间可以知道是否有支持使用KVM_CAP_SMALLER_MAXPHYADDR扩展,并决定如何处理它
    	 * 如果未来的AMD CPU模型改变上述行为,该变量可以相应改变
    	 */
    	allow_smaller_maxphyaddr = !npt_enabled;
    
    	return 0;
    
    err:
    	svm_hardware_unsetup();
    	return r;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

      svm_adjust_mmio_mask kvm内存管理单元设置掩码和值

    /*
     * 默认MMIO掩码为单个位(不包括当前位),可能与内存加密位冲突
     * 检查内存加密支持,如果启用了内存加密,则覆盖默认MMIO掩码
     * /
    static __init void svm_adjust_mmio_mask(void)
    {
    	unsigned int enc_bit, mask_bit;
    	u64 msr, mask;
    
    	/* 如果不支持内存加密,请使用已有的掩码 */
    	if (cpuid_eax(0x80000000) < 0x8000001f)
    		return;
    
    	/* 如果未启用内存加密,请使用现有掩码 */
    	rdmsrl(MSR_AMD64_SYSCFG, msr);
    
    	enc_bit = cpuid_ebx(0x8000001f) & 0x3f; 
    	mask_bit = boot_cpu_data.x86_phys_bits;
    
    	/* 如果掩码位与加密位相同,则递增掩码位 */
    	if (enc_bit == mask_bit)
    		mask_bit++;
    
    	/*
    	 * 如果掩码位位置低于52,那么将始终保留物理寻址限制以上的一些位,因此使用rsvd_bits()函数生成掩码
    	 */
    	mask = (mask_bit < 52) ? rsvd_bits(mask_bit, 51) | PT_PRESENT_MASK : 0;
    
    	kvm_mmu_set_mmio_spte_mask(mask, mask, PT_WRITABLE_MASK | PT_USER_MASK); // kvm内存管理单元设置掩码和值
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

      sev_hardware_setup sev硬件设置

      检查CPU是否支持解码辅助
      获取SEV CPUID信息
      为SEV-ES用户(来宾)设置加密位位置
      以及同时支持的最大加密用户数
      SEV用户应使用的最小ASID值
      初始化SEV ASID位图
      设置杂项控制组MISC_CG_RES_SEV类型的容量
      设置杂项控制组MISC_CG_RES_SEV_ES类

    void __init sev_hardware_setup(void)
    {
    #ifdef CONFIG_KVM_AMD_SEV
    	unsigned int eax, ebx, ecx, edx, sev_asid_count, sev_es_asid_count;
    	bool sev_es_supported = false;
    	bool sev_supported = false;
    
    	if (!sev_enabled || !npt_enabled)
    		goto out;
    
    	/*
    	 * 显然,硬件必须支持SEV
    	 * 仔细检查CPU是否支持解码辅助,这是SEV用户(来宾)必须支持指令模拟的
    	 */
    	if (!boot_cpu_has(X86_FEATURE_SEV) ||
    	    WARN_ON_ONCE(!boot_cpu_has(X86_FEATURE_DECODEASSISTS)))
    		goto out;
    
    	/* 获取SEV CPUID信息 */
    	cpuid(0x8000001f, &eax, &ebx, &ecx, &edx);
    
    	/* 为SEV-ES用户(来宾)设置加密位位置 */
    	sev_enc_bit = ebx & 0x3f;
    
    	/* 同时支持的最大加密用户数 */
    	max_sev_asid = ecx;
    	if (!max_sev_asid)
    		goto out;
    
    	/* SEV用户应使用的最小ASID值 */
    	min_sev_asid = edx;
    	sev_me_mask = 1UL << (ebx & 0x3f);
    
    	/*
    	 * 初始化SEV ASID位图
    	 * 为位图中的ASID 0分配空间,即使它从未使用过,以便位图由实际的ASID索引
    	 */
    	nr_asids = max_sev_asid + 1;
    	sev_asid_bitmap = bitmap_zalloc(nr_asids, GFP_KERNEL);
    
    	sev_reclaim_asid_bitmap = bitmap_zalloc(nr_asids, GFP_KERNEL);  
    
    	sev_asid_count = max_sev_asid - min_sev_asid + 1; // asid数量
    	if (misc_cg_set_capacity(MISC_CG_RES_SEV, sev_asid_count)) // 设置杂项控制组MISC_CG_RES_SEV类型的容量
    	// static unsigned long misc_res_capacity[MISC_CG_RES_TYPES];
    		goto out;
    
    	pr_info("SEV supported: %u ASIDs\n", sev_asid_count);
    	sev_supported = true; // 安全加密虚拟化
    		
    	/*SEV-ES支持 */
    	if (!sev_es_enabled)
    		goto out;
    
    	/*
    	 * SEV-ES需要MMIO缓存,因为KVM无法访问客户机指令流,
    	 * 即无法响应#NPF进行仿真,而是依赖#NPF(RSVD)作为
    	 * #VC反映到客户机中(然后客户机可以执行#VMGEXIT以请求MMIO仿真)
    	 */
    	if (!enable_mmio_caching)
    		goto out;
    
    	/* CPU是否支持SEV-ES? */
    	if (!boot_cpu_has(X86_FEATURE_SEV_ES))
    		goto out;
    
    	/* 系统是否为SEV-ES分配了ASID? */
    	if (min_sev_asid == 1)
    		goto out;
    
    	sev_es_asid_count = min_sev_asid - 1;
    	if (misc_cg_set_capacity(MISC_CG_RES_SEV_ES, sev_es_asid_count)) // 设置杂项控制组MISC_CG_RES_SEV_ES类型的容量
    		goto out;
    
    	pr_info("SEV-ES supported: %u ASIDs\n", sev_es_asid_count);
    	sev_es_supported = true; // 安全加密虚拟化状态
    
    out:
    	sev_enabled = sev_supported;
    	sev_es_enabled = sev_es_supported;
    #endif
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82

      svm_vcpu_create

    static int svm_vcpu_create(struct kvm_vcpu *vcpu)
    {
    	struct vcpu_svm *svm;
    	struct page *vmcb01_page;
    	struct page *vmsa_page = NULL;
    	int err;
    
    	BUILD_BUG_ON(offsetof(struct vcpu_svm, vcpu) != 0); // struct kvm_vcpu vcpu是vcpu_svm结构的第一个成员
    	svm = to_svm(vcpu); // 偏移到vcpu_svm结构对象
    	// 通过container_of
    
    	err = -ENOMEM;
    	vmcb01_page = alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO); // 分配干净页
    
    	if (sev_es_guest(vcpu->kvm)) {
    		/*
    		 * SEV-ES客户机需要一个单独的VMSA页面,用于包含客户机的加密寄存器状态
    		 */
    		vmsa_page = alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO);
    
    		/*
    		 * SEV-ES客户维护其FPU状态的加密版本,该版本将恢复并保存在VMRUN和VMEXIT上
    		 * 标记vcpu->arch.guest_fpu->fpstate为scratch,因此它不会对其执行xsave/xrstor
    		 */
    		fpstate_set_confidential(&vcpu->arch.guest_fpu);
    		// guest_fpu->fpstate->is_confidential = true;
    	}
    
    	err = avic_init_vcpu(svm); // 
    	// avic 高级虚拟中断控制器(Advanced Virtual Interrupt Controller)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    avic_init_backing_page

      avic_init_backing_page

    static int avic_init_backing_page(struct kvm_vcpu *vcpu)
    {
    	u64 *entry, new_entry;
    	int id = vcpu->vcpu_id; // 虚拟cpu id
    	struct vcpu_svm *svm = to_svm(vcpu);
    
    	if ((avic_mode == AVIC_MODE_X1 && id > AVIC_MAX_PHYSICAL_ID) ||
    	    (avic_mode == AVIC_MODE_X2 && id > X2AVIC_MAX_PHYSICAL_ID)) // 这里模式为AVIC_MODE_NONE
    		return -EINVAL;
    
    	if (!vcpu->arch.apic->regs)
    		return -EINVAL;
    
    	if (kvm_apicv_activated(vcpu->kvm)) {
    		int ret;
    
    		ret = avic_alloc_access_page(vcpu->kvm);
    		if (ret)
    			return ret;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

      avic_hardware_setup avic硬件设置,用于IOMMU驱动调用唤醒vcpu任务

      avic 高级虚拟中断控制器(Advanced Virtual Interrupt Controller)

    bool avic_hardware_setup(struct kvm_x86_ops *x86_ops)
    {
    	if (!npt_enabled)
    		return false;
    
    	if (boot_cpu_has(X86_FEATURE_AVIC)) { // 符合条件
    	// #define X86_FEATURE_AVIC		(15*32+13) /* 虚拟中断控制器 */
    	// extern struct cpuinfo_x86	boot_cpu_data;
    	
    		avic_mode = AVIC_MODE_X1;
    		pr_info("AVIC enabled\n");
    	} else if (force_avic) {
    		/*
    		 * Some older systems does not advertise AVIC support.
    		 * See Revision Guide for specific AMD processor for more detail.
    		 */
    		avic_mode = AVIC_MODE_X1; // x1 高级虚拟中断控制器 (最高支持255个虚拟cpu)
    		pr_warn("AVIC is not supported in CPUID but force enabled");
    		pr_warn("Your system might crash and burn");
    	}
    
    	/* AVIC是x2AVIC的先决条件 */
    	if (boot_cpu_has(X86_FEATURE_X2AVIC)) { // 符合条件
    	// #define X86_FEATURE_X2AVIC		(15*32+18) /* 虚拟x2apic */
    	
    		if (avic_mode == AVIC_MODE_X1) {
    			avic_mode = AVIC_MODE_X2; // x2 高级虚拟中断控制器 (最高支持511个虚拟cpu)
    			pr_info("x2AVIC enabled\n");
    		} else {
    			pr_warn(FW_BUG "Cannot support x2AVIC due to AVIC is disabled");
    			pr_warn(FW_BUG "Try enable AVIC using force_avic option");
    		}
    	}
    
    	if (avic_mode != AVIC_MODE_NONE)
    		amd_iommu_register_ga_log_notifier(&avic_ga_log_notifier); // 注册avic_ga_log_notifier函数 
    		// avic_ga_log_notifier 赋值到iommu_ga_log_notifier
    		// 该函数从IOMMU驱动调用,通知SVM调度特定虚拟机的特定vCPU
    		// 用于唤醒vCPU的任务
    
    	return !!avic_mode;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    kvm_vcpu_wake_up

      kvm_vcpu_wake_up kvm虚拟cpu唤醒任务

      通过kvm_vcpu结构的rcuwait对象
      获取待唤醒的任务结构
      然后通过wake_up_process函数唤醒任务

      通过kvm_vcpu_stat结构的kvm_vcpu_stat_generic对象的成员
      halt_wakeup自增表示已被唤醒

    bool kvm_vcpu_wake_up(struct kvm_vcpu *vcpu)
    {
    	if (__kvm_vcpu_wake_up(vcpu)) {
    		WRITE_ONCE(vcpu->ready, true);
    		++vcpu->stat.generic.halt_wakeup;
    		return true;
    	}
    
    	return false;
    }
    EXPORT_SYMBOL_GPL(kvm_vcpu_wake_up);  
    ||
    \/
    int rcuwait_wake_up(struct rcuwait *w)
    {
    	int ret = 0;
    	struct task_struct *task;
    
    	rcu_read_lock();
    
    	/*
    	 * 订单条件vs@task,这样加载@task之前的所有内容都是可见的
    	 * 这就是为什么用户首先调用rcuwait_wake()的条件
    	 * 与rcuwait_event()中的set_current_state()屏障(A)配对
    	 *
    	 *    WAIT                WAKE
    	 *    [S] tsk = current	  [S] cond = true
    	 *        MB (A)	      MB (B)
    	 *    [L] cond		  [L] tsk
    	 */
    	smp_mb(); /* (B) */
    
    	task = rcu_dereference(w->task);
    	if (task)
    		ret = wake_up_process(task);
    	rcu_read_unlock();
    
    	return ret;
    }
    EXPORT_SYMBOL_GPL(rcuwait_wake_up);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

      svm_set_cpu_caps svm设置cpu(寄存器)功能

    static __init void svm_set_cpu_caps(void)
    {
    	kvm_set_cpu_caps(); // kvm设置cpu(寄存器)功能
    
    • 1
    • 2
    • 3

    kvm_set_cpu_caps

    kvm_caps.supported_xss = 0;
    
    	/* CPUID 0x80000001 and 0x8000000A (SVM features) */
    	if (nested) {
    		kvm_cpu_cap_set(X86_FEATURE_SVM);
    		// #define X86_FEATURE_SVM			( 6*32+ 2) /* 安全虚拟机 */
    		kvm_cpu_cap_set(X86_FEATURE_VMCBCLEAN);
    		// #define X86_FEATURE_VMCBCLEAN		(15*32+ 5) /* "vmcb_clean" VMCB清洁位支持 */
    		if (nrips)
    			kvm_cpu_cap_set(X86_FEATURE_NRIPS);
    			// #define X86_FEATURE_NRIPS		(15*32+ 3) /* "nrip_save" 支持向量机next_rip保存 */
    
    		if (npt_enabled)
    			kvm_cpu_cap_set(X86_FEATURE_NPT);
    			// #define X86_FEATURE_NPT			(15*32+ 0) /* 嵌套页表支持 */
    
    		if (tsc_scaling)
    			kvm_cpu_cap_set(X86_FEATURE_TSCRATEMSR);
    			// #define X86_FEATURE_TSCRATEMSR		(15*32+ 4) /* "tsc_scale" TSC缩放支持 */
    
    		if (vls)
    			kvm_cpu_cap_set(X86_FEATURE_V_VMSAVE_VMLOAD);
    			// #define X86_FEATURE_V_VMSAVE_VMLOAD	(15*32+15) /* Virtual VMSAVE VMLOAD */
    		if (lbrv)
    			kvm_cpu_cap_set(X86_FEATURE_LBRV);
    			// #define X86_FEATURE_LBRV		(15*32+ 1) /* LBR虚拟化支持 */
    
    		if (boot_cpu_has(X86_FEATURE_PAUSEFILTER))
    			kvm_cpu_cap_set(X86_FEATURE_PAUSEFILTER);
    			// #define X86_FEATURE_PAUSEFILTER		(15*32+10) /* 滤波暂停截断 */
    
    		if (boot_cpu_has(X86_FEATURE_PFTHRESHOLD))
    			kvm_cpu_cap_set(X86_FEATURE_PFTHRESHOLD);
    			// #define X86_FEATURE_PFTHRESHOLD		(15*32+12) /* 暂停过滤器阈值 */
    
    		if (vgif)
    			kvm_cpu_cap_set(X86_FEATURE_VGIF);
    			// #define X86_FEATURE_VGIF		(15*32+16) /* 虚拟GIF */
    
    		/* 嵌套的VM可以接收#VMEXIT而不是触发#GP */
    		kvm_cpu_cap_set(X86_FEATURE_SVME_ADDR_CHK);
    		// #define X86_FEATURE_SVME_ADDR_CHK	(15*32+28) /* SVME地址检查 */
    	}
    
    	/* CPUID 0x80000008 */
    	if (boot_cpu_has(X86_FEATURE_LS_CFG_SSBD) ||
    	    boot_cpu_has(X86_FEATURE_AMD_SSBD))
    		kvm_cpu_cap_set(X86_FEATURE_VIRT_SSBD);
    		// #define X86_FEATURE_VIRT_SSBD		(13*32+25) /* 虚拟化预测存储旁路关闭 */
    
    	/* AMD PMU PERFCTR_CORE CPUID */
    	if (enable_pmu && boot_cpu_has(X86_FEATURE_PERFCTR_CORE))
    		kvm_cpu_cap_set(X86_FEATURE_PERFCTR_CORE);
    		// #define X86_FEATURE_PERFCTR_CORE	( 6*32+23) /* 核心性能计数器扩展 */
    
    	/* CPUID 0x8000001F (SME/SEV 特征) */
    	sev_set_cpu_caps(); // 如果特征存在,清除
    	// #define X86_FEATURE_SEV			(19*32+ 1) /* AMD安全加密虚拟化 */
    	// #define X86_FEATURE_SEV_ES		(19*32+ 3) /* AMD安全加密虚拟化-加密状态 */
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

      kvm_set_cpu_caps kvm设置cpu(寄存器)功能

    void kvm_set_cpu_caps(void)
    {
    #ifdef CONFIG_X86_64
    	unsigned int f_gbpages = F(GBPAGES); // X86_FEATURE_GBPAGES
    	// F 检查并返回特征位
    	// #define X86_FEATURE_GBPAGES		( 1*32+26) /* “pdpe1gb”GB页面 */
    	
    	unsigned int f_lm = F(LM); // X86_FEATURE_LM
    	// #define X86_FEATURE_LM			( 1*32+29) /* 长模式 (x86-64, 64-bit support) */
    	
    	unsigned int f_xfd = F(XFD); // X86_FEATURE_XFD	
    	// #define X86_FEATURE_XFD			(10*32+ 4) /* 扩展功能禁用 */
    #else
    	unsigned int f_gbpages = 0;
    	unsigned int f_lm = 0;
    	unsigned int f_xfd = 0;
    #endif
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    F

    	memset(kvm_cpu_caps, 0, sizeof(kvm_cpu_caps));
    
    	BUILD_BUG_ON(sizeof(kvm_cpu_caps) - (NKVMCAPINTS * sizeof(*kvm_cpu_caps)) >
    		     sizeof(boot_cpu_data.x86_capability));  // NKVMCAPINTS 1
    
    	memcpy(&kvm_cpu_caps, &boot_cpu_data.x86_capability,
    	       sizeof(kvm_cpu_caps) - (NKVMCAPINTS * sizeof(*kvm_cpu_caps))); // 拷贝x86_capability数组地址
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    kvm_only_cpuid_leafs
    cpuinfo_x86

    kvm_cpu_cap_mask(CPUID_1_ECX,
    		/*
    		 * 注意:MONITOR(和MWAIT)被模拟为NOP,但*不*通过CPUID通告给客人
    		 */
    		F(XMM3) | F(PCLMULQDQ) | 0 /* DTES64, MONITOR */ |
    		0 /* DS-CPL, VMX, SMX, EST */ |
    		0 /* TM2 */ | F(SSSE3) | 0 /* CNXT-ID */ | 0 /* Reserved */ |
    		F(FMA) | F(CX16) | 0 /* xTPR Update */ | F(PDCM) |
    		F(PCID) | 0 /* Reserved, DCA */ | F(XMM4_1) |
    		F(XMM4_2) | F(X2APIC) | F(MOVBE) | F(POPCNT) |
    		0 /* Reserved*/ | F(AES) | F(XSAVE) | 0 /* OSXSAVE */ | F(AVX) |
    		F(F16C) | F(RDRAND)
    	); // 掩码放入(或运算)kvm_cpu_caps[CPUID_1_ECX]中,表示CPUID_1_ECX寄存器支持功能
    	// 用这个CPU的原始CPUID功能屏蔽leaf(叶)的kvm_cpu_caps
    	// #define X86_FEATURE_XMM3		( 4*32+ 0) /* "pni" SSE-3 */
    	// #define X86_FEATURE_PCLMULQDQ		( 4*32+ 1) /* PCLMULQDQ指令 */
    	// #define X86_FEATURE_SSSE3		( 4*32+ 9) /* 补充的 SSE-3 */
    	// #define X86_FEATURE_FMA			( 4*32+12) /* 积和熔加运算 */
    	// #define X86_FEATURE_CX16		( 4*32+13) /* CMPXCHG16B指令 */
    	// #define X86_FEATURE_PDCM		( 4*32+15) /* 性能/调试能力MSR */
    	// #define X86_FEATURE_PCID		( 4*32+17) /* 进程上下文标识符 */
    	// #define X86_FEATURE_XMM4_1		( 4*32+19) /* "sse4_1" SSE-4.1 */
    	// #define X86_FEATURE_XMM4_2		( 4*32+20) /* "sse4_2" SSE-4.2 */
    	// #define X86_FEATURE_X2APIC		( 4*32+21) /* X2APIC */
    	// #define X86_FEATURE_MOVBE		( 4*32+22) /* MOVBE指令 */
    	// #define X86_FEATURE_POPCNT		( 4*32+23) /* POPCNT指令 */
    	// #define X86_FEATURE_AES			( 4*32+25) /* AES指令 */
    	// #define X86_FEATURE_XSAVE		( 4*32+26) /* XSAVE/XRSTOR/XSETBV/XGETBV指令 */
    	// #define X86_FEATURE_AVX			( 4*32+28) /* 高级矢量扩展指令集 */
    	// #define X86_FEATURE_F16C		( 4*32+29) /* 16-bit FP 转换 */
    	// #define X86_FEATURE_RDRAND		( 4*32+30) /* RDRAND指令 */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    cpuid_leafs
    reverse_cpuid

    	/* KVM在软件中模拟x2apic,而不考虑主机支持 */
    	kvm_cpu_cap_set(X86_FEATURE_X2APIC);
    
    	kvm_cpu_cap_mask(CPUID_1_EDX,
    		F(FPU) | F(VME) | F(DE) | F(PSE) |
    		F(TSC) | F(MSR) | F(PAE) | F(MCE) |
    		F(CX8) | F(APIC) | 0 /* Reserved */ | F(SEP) |
    		F(MTRR) | F(PGE) | F(MCA) | F(CMOV) |
    		F(PAT) | F(PSE36) | 0 /* PSN */ | F(CLFLUSH) |
    		0 /* Reserved, DS, ACPI */ | F(MMX) |
    		F(FXSR) | F(XMM) | F(XMM2) | F(SELFSNOOP) |
    		0 /* HTT, TM, Reserved, PBE */
    	); // 掩码放入kvm_cpu_caps[CPUID_1_EDX]中,表示CPUID_1_EDX寄存器支持功能
    	// #define X86_FEATURE_FPU			( 0*32+ 0) /* 机载(板卡)FPU */
    	// #define X86_FEATURE_VME			( 0*32+ 1) /* 虚拟模式扩展 */
    	// #define X86_FEATURE_DE			( 0*32+ 2) /* 调试扩展 */
    	// #define X86_FEATURE_PSE			( 0*32+ 3) /* 页面大小扩展 */
    	// #define X86_FEATURE_TSC			( 0*32+ 4) /* 时间戳计数器 */
    	// #define X86_FEATURE_MSR			( 0*32+ 5) /* 特定模块寄存器 */
    	// #define X86_FEATURE_PAE			( 0*32+ 6) /* 物理地址扩展 */
    	// #define X86_FEATURE_MCE			( 0*32+ 7) /* 机器检查异常 */
    	// #define X86_FEATURE_CX8			( 0*32+ 8) /* CMPXCHG8指令 */
    	// #define X86_FEATURE_APIC		( 0*32+ 9) /* 机载(板卡)APIC */
    	// #define X86_FEATURE_SEP			( 0*32+11) /* SYSENTER/SYSEXIT */
    	// #define X86_FEATURE_MTRR		( 0*32+12) /* 存储器型态范围寄存器 */
    	// #define X86_FEATURE_PGE			( 0*32+13) /* 页面全局启用 */
    	// #define X86_FEATURE_MCA			( 0*32+14) /* 机器检查体系结构 */
    	// #define X86_FEATURE_CMOV		( 0*32+15) /* CMOV指令 (plus FCMOVcc, FCOMI with FPU) */
    	// #define X86_FEATURE_PAT			( 0*32+16) /* 页属性表 */
    	// #define X86_FEATURE_PSE36		( 0*32+17) /* 36-bit PSEs */
    	// #define X86_FEATURE_CLFLUSH		( 0*32+19) /* CLFLUSH指令 */
    	// #define X86_FEATURE_MMX			( 0*32+23) /* 多媒体扩展 */
    	// #define X86_FEATURE_FXSR		( 0*32+24) /* FXSAVE/FXRSTOR, CR4.OSFXSR */
    	// #define X86_FEATURE_XMM			( 0*32+25) /* "sse" */
    	// #define X86_FEATURE_XMM2		( 0*32+26) /* "sse2" */
    	// #define X86_FEATURE_SELFSNOOP		( 0*32+27) /* "ss"CPU自检 */
    
    	kvm_cpu_cap_mask(CPUID_7_0_EBX,
    		F(FSGSBASE) | F(SGX) | F(BMI1) | F(HLE) | F(AVX2) |
    		F(FDP_EXCPTN_ONLY) | F(SMEP) | F(BMI2) | F(ERMS) | F(INVPCID) |
    		F(RTM) | F(ZERO_FCS_FDS) | 0 /*MPX*/ | F(AVX512F) |
    		F(AVX512DQ) | F(RDSEED) | F(ADX) | F(SMAP) | F(AVX512IFMA) |
    		F(CLFLUSHOPT) | F(CLWB) | 0 /*INTEL_PT*/ | F(AVX512PF) |
    		F(AVX512ER) | F(AVX512CD) | F(SHA_NI) | F(AVX512BW) |
    		F(AVX512VL)); //  CPUID_7_0_EBX
    
    	kvm_cpu_cap_mask(CPUID_7_ECX,
    		F(AVX512VBMI) | F(LA57) | F(PKU) | 0 /*OSPKE*/ | F(RDPID) |
    		F(AVX512_VPOPCNTDQ) | F(UMIP) | F(AVX512_VBMI2) | F(GFNI) |
    		F(VAES) | F(VPCLMULQDQ) | F(AVX512_VNNI) | F(AVX512_BITALG) |
    		F(CLDEMOTE) | F(MOVDIRI) | F(MOVDIR64B) | 0 /*WAITPKG*/ |
    		F(SGX_LC) | F(BUS_LOCK_DETECT)
    	); //  CPUID_7_ECX
    
    	/* 根据硬件能力设置LA57 */
    	if (cpuid_ecx(7) & F(LA57))
    		kvm_cpu_cap_set(X86_FEATURE_LA57);
    		
    	/*
    	 * PKU尚未实现影子分页,需要在主机上设置OSPKE
    	 * 如果情况并非如此,请清除它
    	 */
    	if (!tdp_enabled || !boot_cpu_has(X86_FEATURE_OSPKE))
    		kvm_cpu_cap_clear(X86_FEATURE_PKU);
    
    	kvm_cpu_cap_mask(CPUID_7_EDX,
    		F(AVX512_4VNNIW) | F(AVX512_4FMAPS) | F(SPEC_CTRL) |
    		F(SPEC_CTRL_SSBD) | F(ARCH_CAPABILITIES) | F(INTEL_STIBP) |
    		F(MD_CLEAR) | F(AVX512_VP2INTERSECT) | F(FSRM) |
    		F(SERIALIZE) | F(TSXLDTRK) | F(AVX512_FP16) |
    		F(AMX_TILE) | F(AMX_INT8) | F(AMX_BF16)
    	); // CPUID_7_EDX 
    
    	/* 在软件中模拟TSC_ADJUST和ARCH_CAPABILITIES */
    	kvm_cpu_cap_set(X86_FEATURE_TSC_ADJUST);
    	kvm_cpu_cap_set(X86_FEATURE_ARCH_CAPABILITIES);
    
    	if (boot_cpu_has(X86_FEATURE_IBPB) && boot_cpu_has(X86_FEATURE_IBRS))
    	// #define X86_FEATURE_IBPB		( 7*32+26) /* 间接分支预测障碍 */
    	// #define X86_FEATURE_IBRS		( 7*32+25) /* 间接分支限制预测 */
    		kvm_cpu_cap_set(X86_FEATURE_SPEC_CTRL);
    		// #define X86_FEATURE_SPEC_CTRL		(18*32+26) /* 预测控制 (IBRS + IBPB) */
    		
    	if (boot_cpu_has(X86_FEATURE_STIBP))
    	// #define X86_FEATURE_STIBP		( 7*32+27) /* 单线程间接分支预测器 */
    		kvm_cpu_cap_set(X86_FEATURE_INTEL_STIBP);
    		// #define X86_FEATURE_STIBP		( 7*32+27) /* 单线程间接分支预测器 */
    		
    	if (boot_cpu_has(X86_FEATURE_AMD_SSBD))
    	// #define X86_FEATURE_AMD_SSBD		(13*32+24) /* 预测存储旁路禁用 */
    		kvm_cpu_cap_set(X86_FEATURE_SPEC_CTRL_SSBD);
    		// #define X86_FEATURE_SPEC_CTRL_SSBD	(18*32+31) /* 预测存储旁路关闭 */
    
    	kvm_cpu_cap_mask(CPUID_7_1_EAX,
    		F(AVX_VNNI) | F(AVX512_BF16)
    	); // CPUID_7_1_EAX能力
    	// #define X86_FEATURE_AVX_VNNI		(12*32+ 4) /* AVX VNNI 指令 */
    	// #define X86_FEATURE_AVX512_BF16		(12*32+ 5) /* AVX512 BFLOAT16 指令 */
    
    	kvm_cpu_cap_mask(CPUID_D_1_EAX,
    		F(XSAVEOPT) | F(XSAVEC) | F(XGETBV1) | F(XSAVES) | f_xfd
    	);  // CPUID_D_1_EAX能力
    
    	kvm_cpu_cap_init_scattered(CPUID_12_EAX,
    		SF(SGX1) | SF(SGX2)
    	); // 掩码赋值(=)kvm_cpu_caps[CPUID_12_EAX]中,表示CPUID_12_EAX能力
    	// #define X86_FEATURE_SGX1		(11*32+ 8) /* 基本SGX */
    	// #define X86_FEATURE_SGX2		(11*32+ 9) /* SGX Enclave动态内存管理(EDMM) */
    	
    	kvm_cpu_cap_mask(CPUID_8000_0001_ECX,
    		F(LAHF_LM) | F(CMP_LEGACY) | 0 /*SVM*/ | 0 /* ExtApicSpace */ |
    		F(CR8_LEGACY) | F(ABM) | F(SSE4A) | F(MISALIGNSSE) |
    		F(3DNOWPREFETCH) | F(OSVW) | 0 /* IBS */ | F(XOP) |
    		0 /* SKINIT, WDT, LWP */ | F(FMA4) | F(TBM) |
    		F(TOPOEXT) | 0 /* PERFCTR_CORE */
    	); // CPUID_8000_0001_ECX
    
    	kvm_cpu_cap_mask(CPUID_8000_0001_EDX,
    		F(FPU) | F(VME) | F(DE) | F(PSE) |
    		F(TSC) | F(MSR) | F(PAE) | F(MCE) |
    		F(CX8) | F(APIC) | 0 /* Reserved */ | F(SYSCALL) |
    		F(MTRR) | F(PGE) | F(MCA) | F(CMOV) |
    		F(PAT) | F(PSE36) | 0 /* Reserved */ |
    		F(NX) | 0 /* Reserved */ | F(MMXEXT) | F(MMX) |
    		F(FXSR) | F(FXSR_OPT) | f_gbpages | F(RDTSCP) |
    		0 /* Reserved */ | f_lm | F(3DNOWEXT) | F(3DNOW)
    	); // CPUID_8000_0001_EDX
    
    	if (!tdp_enabled && IS_ENABLED(CONFIG_X86_64))
    		kvm_cpu_cap_set(X86_FEATURE_GBPAGES);
    		// #define X86_FEATURE_GBPAGES		( 1*32+26) /* “pdpe1gb”GB页面 */
    
    	kvm_cpu_cap_mask(CPUID_8000_0008_EBX,
    		F(CLZERO) | F(XSAVEERPTR) |
    		F(WBNOINVD) | F(AMD_IBPB) | F(AMD_IBRS) | F(AMD_SSBD) | F(VIRT_SSBD) |
    		F(AMD_SSB_NO) | F(AMD_STIBP) | F(AMD_STIBP_ALWAYS_ON) |
    		__feature_bit(KVM_X86_FEATURE_PSFD)
    	); // CPUID_8000_0008_EBX
    
    	/*
    	 * AMD为每个SPEC_CTRL位具有单独的位
    	 * arch/x86/kernel/cpu/bugs.c很好地将其记录在cpufeatures中,所以使用它们
    	 */
    	if (boot_cpu_has(X86_FEATURE_IBPB))
    		kvm_cpu_cap_set(X86_FEATURE_AMD_IBPB);
    		// #define X86_FEATURE_AMD_IBPB		(13*32+12) /* 间接分支预测障碍 */
    		
    	if (boot_cpu_has(X86_FEATURE_IBRS))
    		kvm_cpu_cap_set(X86_FEATURE_AMD_IBRS);
    		// #define X86_FEATURE_AMD_IBRS		(13*32+14) /* 间接分支限制预测 */
    		
    	if (boot_cpu_has(X86_FEATURE_STIBP))
    		kvm_cpu_cap_set(X86_FEATURE_AMD_STIBP);
    		// #define X86_FEATURE_AMD_STIBP		(13*32+15) /* 单线程间接分支预测器 */
    		
    	if (boot_cpu_has(X86_FEATURE_SPEC_CTRL_SSBD))
    		kvm_cpu_cap_set(X86_FEATURE_AMD_SSBD);
    		// #define X86_FEATURE_AMD_SSBD		(13*32+24) /* 预测存储旁路禁用 */
    		
    	if (!boot_cpu_has_bug(X86_BUG_SPEC_STORE_BYPASS))
    		kvm_cpu_cap_set(X86_FEATURE_AMD_SSB_NO);
    		// #define X86_FEATURE_AMD_SSB_NO		(13*32+26) /* 预测存储旁路在硬件上是固定的 */
    
    	/*
    	 * 首选使用SPEC CTRL MSR,而不是VIRT_SPEC MSR
    	 */
    	if (boot_cpu_has(X86_FEATURE_LS_CFG_SSBD) &&
    	    !boot_cpu_has(X86_FEATURE_AMD_SSBD))
    		kvm_cpu_cap_set(X86_FEATURE_VIRT_SSBD);
    
    	/*
    	 * 默认情况下隐藏所有SVM特征,SVM将为它模拟的特征和/或暴露的L1设置上限位
    	 */
    	kvm_cpu_cap_mask(CPUID_8000_000A_EDX, 0);
    
    	kvm_cpu_cap_mask(CPUID_8000_001F_EAX,
    		0 /* SME */ | F(SEV) | 0 /* VM_PAGE_FLUSH */ | F(SEV_ES) |
    		F(SME_COHERENT)); // CPUID_8000_001F_EAX
    
    	kvm_cpu_cap_mask(CPUID_C000_0001_EDX,
    		F(XSTORE) | F(XSTORE_EN) | F(XCRYPT) | F(XCRYPT_EN) |
    		F(ACE2) | F(ACE2_EN) | F(PHE) | F(PHE_EN) |
    		F(PMM) | F(PMM_EN)
    	); // CPUID_C000_0001_EDX
    
    	/*
    	 * 隐藏RDTSCP和RDPID,如果其中一个特性被报告为支持,但探测MSR_TSC_AUX失败
    	 * 这纯粹是一个健全检查,不应该发生,但是如果RDTSCP或RDPID被错误报告,客户机可能会崩溃,
    	 * 而且KVM过去曾搞砸过MSR_TSC_AUX模拟
    	 * 例如,如果这个KVM实例在旧的、损坏的KVM上以L1的身份运行,则可能触发完整性检查
    	 */
    	if (WARN_ON((kvm_cpu_cap_has(X86_FEATURE_RDTSCP) ||
    		     kvm_cpu_cap_has(X86_FEATURE_RDPID)) &&
    		     !kvm_is_supported_user_return_msr(MSR_TSC_AUX))) {
    		kvm_cpu_cap_clear(X86_FEATURE_RDTSCP);
    		kvm_cpu_cap_clear(X86_FEATURE_RDPID);
    	}
    }
    EXPORT_SYMBOL_GPL(kvm_set_cpu_caps);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199

      F 检查并返回特征位

    #define F feature_bit 检查并返回特征位
    ||
    \/
    #define feature_bit(name)  __feature_bit(X86_FEATURE_##name)
    ||
    \/
    /*
     * 从X86_FEATURE_*定义中检索位掩码
     * 特性包含硬件定义的位数(存储在位4:0中)和软件定义的“字”(存储在位31:5中)
     * 这个词用于索引到包含每个cpu特性功能的位掩码数组中,例如this_cpu_has()
     * /
    static __always_inline u32 __feature_bit(int x86_feature)
    {
            x86_feature = __feature_translate(x86_feature); // 返回特征,包括SGX1、SGX2和直接返回
            // #define KVM_X86_FEATURE(w, f)           ((w)*32 + (f))
            // CPUID_12_EAX 20
    		// #define KVM_X86_FEATURE_SGX1            KVM_X86_FEATURE(CPUID_12_EAX, 0)
    		// KVM_X86_FEATURE_SGX1 (20 * 32 + 0)
    		// #define KVM_X86_FEATURE_SGX2            KVM_X86_FEATURE(CPUID_12_EAX, 1)
    		// KVM_X86_FEATURE_SGX2 (20 * 32 + 1)
    		
    		/*
    		 * 反向CPUID及其派生只能用于硬件定义的特征字,即其位直接对应于CPUID叶的字
    		 * 从Linux定义的字中检索功能位或屏蔽来宾CPUID是没有意义的
    		 * 因为位号/掩码是任意软件定义的值,KVM无法使用它来查询/控制来宾功能
    		 * 显然,被查询的叶必须在查找表中有一个条目
    		 * /
            reverse_cpuid_check(x86_feature / 32); // 检查特征
            return 1 << (x86_feature & 31);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
  • 相关阅读:
    【通俗易懂】git原理、安装及连接gitlab,github
    【极速审稿】物联网传感器类SCI&EI,仅17天录用,计算机领域SCI快刊盘点
    整数型常量池
    SharpCrafters PostSharp Crack
    LeetCode每日一题——667. 优美的排列 II
    Iphone自带的邮箱 每次发完邮件在已发送里会显示重复发送了两封
    工作不好找,普通打工人如何破局
    AWS 中文入门开发教学 25- 高可用性设计 - 建立 ALB 负载均衡
    【C++】.h文件与.c文件的区别
    Debezium同步之DB2数据同步配置
  • 原文地址:https://blog.csdn.net/a29562268/article/details/127946557