Xen-Trap
xen的虚拟化实现有一个很重要的机制就是tarp,中文可以暂且叫做陷入。在ARMv8中,trap就是异常等级的一个切换。
当发生trap的时候,就会进入设定好的异常向量表中,硬件自动判断属于哪种类型的异常。
一、异常处理
ARM v8有4个异常级别,每一个异常级别对应一个 VBAR(Vector Base Address Register) 寄存器,用来指向异常向量表的基地址,每一个异常向量表的大小为128个字节,也即可以存放32条指令(ARM v8指令集里一条指令的位宽是32bit的,而不是64bit);同时每一个异常向量表会分为4组,每一组包含4 种异常,如图所示:
这里的图对应上面的hyp_traps_vector
整理了一下,xen对于发生的异常,最后会调用如下函数进行处理:
function | action |
---|---|
do_trap_hyp_sync | brk指令处理、当前异常等级产生的数据abort(用于由数据访问产生的 MMU 故障、由堆栈指针未对齐引起的对齐故障以及同步外部中止,包括同步奇偶校验或 ECC 错误)、当前异常等级产生的指令abort(用于指令访问和同步外部中止生成的 MMU 故障) |
do_trap_hyp_serror | 在EL2,发生了Serror是不安全的,直接输出panic信息 |
do_trap_guest_sync | WFI/WFE指令、cp15/cp14/cp10协处理访问、SVE相关指令、SMC指令、HVC指令、访问系统寄存器、从低异常等级产生的数据&指令abort |
do_trap_guest_serror | 通过置位HCR_EL2的VSE(bit 8)来产生Virtual SError interrupt,由EL1的异常向量表做进一步处理 |
do_trap_irq | 处理中断 |
二、trap处理的事情(挑重点)
1. guest os的同步异常 — do_trap_guest_sync(关注点)
①SMC调用
function | action |
---|---|
do_trap_smc: | 处理来自EL1的SMC指令(由于xen修改了dom的dts,所以os的开核方式不是使用smc) |
monitor_smc | |
vsmccc_handle_call(handle SMC/HVC call according to ARM SMCCC) | handle_existing_apis —> do_vpsci_0_1_call |
handle_sssc —> do_vpsci_0_2_call |
②HVC调用
function | action |
---|---|
do_trap_hvc_smccc: | 执行vsmccc_handle_call(handle SMC/HVC call according to ARM SMCCC),xen修改了dts,让每个dom的psci开核方法为hvc:method = “hvc”; |
handle_existing_apis | do_vpsci_0_1_call |
handle_arch | |
handle_hypervisor | |
handle_sssc | do_vpsci_0_2_call:PSCI_0_2_FN64_CPU_ON |
platform_smc | |
do_trap_hypercall: | |
do_memory_op | XENMEM_increase_reservation对应balloon的放气,增加guest的内存 |
XENMEM_decrease_reservation对应balloon的吹气,减少guest的内存 | |
XENMEM_populate_physmap,给page分配mfn | |
XENMEM_exchange,内存交换 | |
XENMEM_maximum_ram_page,获取最大的页数 | |
XENMEM_current_reservation,获取当前预留内存总页数 | |
XENMEM_maximum_reservation,获取预留内存最大总页数 | |
XENMEM_maximum_gpfn,获取最大guest pfn数 | |
XENMEM_add_to_physmap,增加页面映射 | |
XENMEM_add_to_physmap_batch,增加页面映射,不支持iommu? | |
XENMEM_remove_from_physmap,删除页面映射 | |
XENMEM_access_op,内存访问权限设置&获取 | |
XENMEM_claim_pages,检查页的权限等信息 | |
XENMEM_get_vnumainfo,获取vNUMA的拓扑信息 | |
XENMEM_reserved_device_memory_map,获取外设预留的内存情况?看代码arm并没有实现相关的函数 | |
XENMEM_acquire_resource,获取内存资源情况 | |
do_domctl | XEN_DOMCTL_setvcpucontext,设置vcpu的上下文 |
XEN_DOMCTL_pausedomain,暂停domain,调用domain_pause | |
XEN_DOMCTL_unpausedomain,取消暂停domain,调用domain_unpause | |
XEN_DOMCTL_resumedomain,恢复domain,也会调用domain_pause和domain_unpause,涉及vcpu的操作 | |
XEN_DOMCTL_createdomain,创建domain | |
XEN_DOMCTL_max_vcpus,设置vcpu数量为max_vcpus | |
XEN_DOMCTL_soft_reset,domain软复位 | |
XEN_DOMCTL_destroydomain,销毁domain | |
XEN_DOMCTL_setnodeaffinity,设置与guest具有亲和力的 NUMA 节点 | |
XEN_DOMCTL_getnodeaffinity,获取与guest具有亲和力的 NUMA 节点 | |
XEN_DOMCTL_setvcpuaffinity,设置vpu的亲和度 | |
XEN_DOMCTL_getvcpuaffinity,获取vcpu的亲和度 | |
XEN_DOMCTL_scheduler_op,调整domain的调度参数 | |
XEN_DOMCTL_getdomaininfo,获取domain的相关信息 | |
XEN_DOMCTL_getvcpucontext,获取vcpu的上下文信息 | |
XEN_DOMCTL_getvcpuinfo,获取vcpu的信息 | |
XEN_DOMCTL_max_mem,设置max_pages最大内存数 | |
XEN_DOMCTL_setdomainhandle,设置domain操作句柄 | |
XEN_DOMCTL_setdebugging,设置debugger_attached标志位,判断guest是否被dom0调试中 | |
XEN_DOMCTL_irq_permission,设置domain对于给定irq的访问权限 | |
XEN_DOMCTL_iomem_permission,设置domain对应给定io内存的访问权限 | |
XEN_DOMCTL_memory_mapping,映射memory | |
XEN_DOMCTL_settimeoffset,设置domain的timeoffset(CNTVOFF_EL2?) | |
XEN_DOMCTL_set_target,设置该guest对给定guest的特权 | |
XEN_DOMCTL_subscribe,设置suspend_evtchn | |
XEN_DOMCTL_set_access_required,设置p2m表的访问权限 | |
XEN_DOMCTL_set_virq_handler,设置虚拟中断的中断服务函数 | |
XEN_DOMCTL_setvnumainfo,设置vNUMA的拓扑信息 | |
XEN_DOMCTL_monitor_op,启用/禁用监视各种 VM 事件 | |
do_sched_op | 调度相关的操作(yeiled、shutdown等操作),这里不一一列举了,直接看代码 |
do_console_io | CONSOLEIO_write,guest对于console的写操作 |
CONSOLEIO_read,guest对于console的读操作 | |
do_xen_version | 获取xen版本 |
do_xsm_op | xen的Xen Security Modules(安全模块)相关操作,是个钩子 |
do_event_channel_op | xen事件通道的相关操作 |
do_physdev_op | 这是是对于一些物理外设的具体操作,目前只实现了pci_physdev_op:pci_device_add、pci_device_remove |
do_sysctl | XEN_SYSCTL_readconsole,读取console |
XEN_SYSCTL_tbuf_op,trace buffers上的 sysctl 操作 | |
XEN_SYSCTL_sched_id,获取当前调度程序的 ID | |
XEN_SYSCTL_getdomaininfolist,获取所有domain的信息 | |
XEN_SYSCTL_debug_keys,设置debug_key,模拟在xen按下按键,产生对应的调试信息 | |
XEN_SYSCTL_getcpuinfo,获取cpu信息 | |
XEN_SYSCTL_availheap,获取可用的heap内存信息 | |
XEN_SYSCTL_page_offline_op,设置page的状态,online或者offline | |
XEN_SYSCTL_cpupool_op,做 cpupool 相关的 sysctl 操作 | |
XEN_SYSCTL_scheduler_op,调度相关的sysctl操作 | |
XEN_SYSCTL_physinfo,获取当前的一些物理信息:cpu数量、内存node数量、总页数等等 | |
XEN_SYSCTL_numainfo,获取numa的相关信息 | |
XEN_SYSCTL_cputopoinfo,获取xen_sysctl_cputopo结构体信息 | |
XEN_SYSCTL_coverage_op,@TODO,没看懂 | |
XEN_SYSCTL_livepatch_op,@TODO,没看懂 | |
XEN_SYSCTL_overlay,在给定的设备树目标节点做add或者remove节点操作 | |
do_hvm_op | HVMOP_set_param,设置xen_hvm_param结构体参数 |
HVMOP_get_param,获取xen_hvm_param结构体参数 | |
do_grant_table_op (Xen通过提供grant_table_op一系列hypercall以供DomU使用来实现内存共享) | GNTTABOP_map_grant_ref,映射一个gref |
GNTTABOP_unmap_grant_ref,取消gref的映射 | |
GNTTABOP_unmap_and_replace,撤销对gref的映射,并替换为其他的映射 | |
GNTTABOP_setup_table,建立grant table | |
GNTTABOP_transfer,移交一个页 | |
GNTTABOP_copy,拷贝一些页/gref对应的页 | |
GNTTABOP_query_size,查询grant table的当前/最大大小 | |
GNTTABOP_set_version,设置grant table的版本 | |
GNTTABOP_get_status_frames,获取用于存储dom授权状态的帧列表 | |
GNTTABOP_get_version,获取grant table的版本 | |
GNTTABOP_swap_grant_ref,交换gref | |
GNTTABOP_cache_flush,刷cache(gref对应的mfn) | |
do_multicall | 调用arch_do_multicall_call来执行多次hypcall |
do_platform_op | 目前只实现了XENPF_settime64,设置墙上时钟(wall clock) |
do_vcpu_op | VCPUOP_initialise,初始化vcpu |
VCPUOP_up,上线vcpu | |
VCPUOP_down,下线vpcu | |
VCPUOP_is_up,判断vpcu是否上线 | |
VCPUOP_get_runstate_info,获取vcpu的运行状态信息 | |
VCPUOP_set_periodic_timer,设置周期定时器 | |
VCPUOP_stop_periodic_timer,停止周期定时器 | |
VCPUOP_set_singleshot_timer,设置单次定时器 | |
VCPUOP_stop_singleshot_timer,停止单次定时器 | |
VCPUOP_register_vcpu_info,在客户地址空间中为vcpu_info结构注册一个内存位置 | |
VCPUOP_register_runstate_memory_area,注册一个共享内存区域 |
③访问系统寄存器
function | action |
---|---|
do_sysreg | HSR_SYSREG_ACTLR_EL1:EL1阶段访问ACTLR_EL1寄存器 |
HSR_SYSREG_DCISW:EL1阶段访问DCISW、DCCSW、DCCISW寄存器(三个都是和cache相关的) | |
EL1阶段访问SCTLR_EL1、TTBR0_EL1、TTBR1_EL1、TCR_EL1、ESR_EL1、FAR_EL1、AFSR0_EL1、AFSR1_EL1、MAIR_EL1、AMAIR_EL1、CONTEXTIDR_EL1寄存器 | |
HSR_SYSREG_MDRAR_EL1:EL1阶段访问MDRAR_EL1寄存器:Monitor Debug ROM Address Register | |
HSR_SYSREG_OSLAR_EL1:EL1阶段访问OSLAR_EL1寄存器:OS Lock Access Register | |
HSR_SYSREG_OSDLR_EL1:EL1阶段访问OSDLR_EL1寄存器:OS Double Lock Register | |
HSR_SYSREG_OSLSR_EL1:EL1阶段访问OSLSR_EL1寄存器:OS Lock Status Register | |
HSR_SYSREG_MDSCR_EL1:EL1阶段访问MDSCR_EL1寄存器:Monitor Debug System Control Register | |
HSR_SYSREG_MDCCSR_EL0:EL0阶段访问MDCCSR_EL0寄存器:Monitor DCC Status Register | |
下面是关于性能监视器相关的寄存器: | |
HSR_SYSREG_PMINTENSET_EL1:EL1阶段访问PMINTENSET_EL1寄存器:Performance Monitors Interrupt Enable Set register | |
HSR_SYSREG_PMINTENCLR_EL1:EL1阶段访问PMINTENCLR_EL1寄存器:Performance Monitors Interrupt Enable Clear register | |
HSR_SYSREG_PMUSERENR_EL0:EL0阶段访问PMUSERENR_EL0寄存器:Performance Monitors User Enable Register | |
HSR_SYSREG_PMCR_EL0:EL0阶段访问PMCR_EL0寄存器:Performance Monitors Control Register | |
HSR_SYSREG_PMCNTENSET_EL0:EL0阶段访问PMCNTENSET_EL0寄存器:Performance Monitors Count Enable Set register | |
HSR_SYSREG_PMCNTENCLR_EL0:EL0阶段访问PMCNTENCLR_EL0寄存器:Performance Monitors Count Enable Clear register | |
HSR_SYSREG_PMOVSCLR_EL0:EL0阶段访问PMOVSCLR_EL0寄存器:Performance Monitors Overflow Flag Status Clear Register | |
HSR_SYSREG_PMSWINC_EL0:EL0阶段访问PMSWINC_EL0寄存器:Performance Monitors Software Increment register | |
HSR_SYSREG_PMSELR_EL0:EL0阶段访问PMSELR_EL0寄存器:Performance Monitors Event Counter Selection Register | |
HSR_SYSREG_PMCEID0_EL0:EL0阶段访问PMCEID0_EL0寄存器:Performance Monitors Common Event Identification register 0 | |
HSR_SYSREG_PMCEID1_EL0:EL0阶段访问PMCEID1_EL0寄存器:Performance Monitors Common Event Identification register 1 | |
HSR_SYSREG_PMCCNTR_EL0:EL0阶段访问PMCCNTR_EL0寄存器:Performance Monitors Cycle Count Register | |
HSR_SYSREG_PMXEVTYPER_EL0:EL0阶段访问PMXEVTYPER_EL0寄存器:Performance Monitors Selected Event Type Register | |
HSR_SYSREG_PMXEVCNTR_EL0:EL0阶段访问PMXEVCNTR_EL0寄存器:Performance Monitors Selected Event Count Register | |
HSR_SYSREG_PMOVSSET_EL0:EL0阶段访问PMOVSSET_EL0寄存器:Performance Monitors Overflow Flag Status Set register | |
下面是和定时器相关的寄存器: | |
HSR_SYSREG_CNTP_CTL_EL0:EL0阶段访问CNTP_CTL_EL0寄存器:Counter-timer Physical Timer Control register | |
HSR_SYSREG_CNTP_TVAL_EL0:EL0阶段访问CNTP_TVAL_EL0寄存器:Counter-timer Physical Timer TimerValue register | |
HSR_SYSREG_CNTP_CVAL_EL0:EL0阶段访问CNTP_CVAL_EL0寄存器:Counter-timer Physical Timer CompareValue register | |
下面是和GIC中断控制器相关的寄存器: | |
HSR_SYSREG_ICC_SGI1R_EL1:EL1阶段访问ICC_SGI1R_EL1寄存器:Interrupt Controller Software Generated Interrupt Group 1 Register Generates Group 1 SGIs for the current Security state | |
HSR_SYSREG_ICC_ASGI1R_EL1:EL1阶段访问ICC_ASGI1R_EL1寄存器:Interrupt Controller Alias Software Generated Interrupt Group 1 Generates Group 1 SGIs for the Security state that is not the current Security state | |
HSR_SYSREG_ICC_SGI0R_EL1:EL1阶段访问ICC_SGI0R_EL1寄存器:Interrupt Controller Software Generated Interrupt Group 0 Register Generates Secure Group 0 SGIs | |
HSR_SYSREG_ICC_SRE_EL1:EL1阶段访问ICC_SRE_EL1寄存器:Interrupt Controller System Register Enable register (EL1) | |
下面是guest os用来识别处理器功能的大多数Identification寄存器: | |
ID_PFR0_EL1 ~ ID_PFR2_EL1:AArch32 Processor Feature Register 0、1、2 | |
ID_DFR0_EL1、ID_DFR1_EL1:AArch32 Debug Feature Register 0、1 | |
ID_AFR0_EL1:AArch32 Auxiliary Feature Register 0 | |
ID_MMFR0_EL1 ~ ID_MMFR5_EL1:AArch32 Memory Model Feature Register 0、1、2、3、4、5 | |
ID_ISAR0_EL1 ~ ID_ISAR6_EL1:AArch32 Instruction Set Attribute Register 0、1、2、3、4、5、6 | |
MVFR0_EL1 ~ MVFR2_EL1: AArch32 Media and VFP Feature Register 0、1、2 | |
ID_AA64PFR0_EL1、ID_AA64PFR1_EL1:AArch64 Processor Feature Register 0、1 | |
ID_AA64DFR0_EL1、ID_AA64DFR1_EL1:AArch64 Debug Feature Register 0、1 | |
ID_AA64ISAR0_EL1、ID_AA64ISAR1_EL1:AArch64 Instruction Set Attribute Register 0、1 | |
ID_AA64MMFR0_EL1 ~ ID_AA64MMFR2_EL1:AArch64 Memory Model Feature Register 0、1、2 | |
ID_AA64AFR0_EL1、ID_AA64AFR1_EL1:AArch64 Auxiliary Feature Register 0 | |
ID_AA64ZFR0_EL1:AArch64 SVE Feature ID register 0 | |
EL1访问 group 3 ID registers: | |
④低异常等级产生的数据&指令abort
function | action |
---|---|
do_trap_stage2_abort_guest(数据&指令abort都是调用这个函数) | FSC_FLT_PERM:0b0011xx:L1/L2/L3页表访问权限错误 |
p2m_mem_access_check,这里会去配置页表项,设置权限位 | |
FSC_FLT_TRANS:0b0001xx:L0/L1/L2/L3页表翻译错误,IPA —> PA的页表没有正确配置(VA —> IPA的翻译已经在guest os的EL1处理了) | |
check_p2m —> p2m_resolve_translation_faul或者try_map_mmio | |
try_decode_instruction —> 指令abort | |
try_handle_mmio(IO trap or Device emulation,解决多个guest os访问一个外设的情况) |
2. hypervisor同步异常 — do_trap_hyp_sync
function | action |
---|---|
do_trap_hyp_sync | HSR_EC_BRK:断点指令异常,调试用 |
HSR_EC_DATA_ABORT_CURR_EL:同异常等级产生的数据abort:dump_hyp_walk。xen的页表错误 | |
HSR_EC_INSTR_ABORT_CURR_EL:同异常等级产生的指令abort:dump_hyp_walk |