[置顶] arm 处理器虚拟化模式初始化 笔记版(尚未完成) 转载请注明出处[email protected]



zImage


从Hyper态返回SVC态
//reg—暂存寄存器
.macro safe_svcmode_maskall reg:req
#if __LINUX_ARM_ARCH__ >= 6
    //读取cpsr到暂存寄存器reg
mrs \reg , cpsr
    /*以下两条指令区分当前cpsr是否处在HYP_MODE,若处在HYP_MODE模式,标志位置零*/
eor \reg, \reg, #HYP_MODE
tst \reg, #MODE_MASK
bic \reg , \reg , #MODE_MASK
    //在暂存寄存器里存放SVC控制位
orr \reg , \reg , #PSR_I_BIT | PSR_F_BIT | SVC_MODE
THUMB( orr \reg , \reg , #PSR_T_BIT )
    /*若当前寄存器处于hyper模式,返回SVC模式走一个杜撰的HVC异常返回。*/
bne 1f
orr \reg, \reg, #PSR_A_BIT
    /*设置返回到SVC态的地址是标号2,即该宏调用的后一条指令。*/ 
adr lr, BSYM(2f)
    //退出hyper后的cpsr寄存器
msr spsr_cxsf, \reg
    //放到ELR_hyp中
__MSR_ELR_HYP(14)
    //返回到SVC态
__ERET
    //当前处理器不在hyper状态,强制切换到SVC态
1: msr cpsr_c, \reg
2:


Uboot在arm hyper状态引导因zImage。zImage除了需要支持传统的解压、定位工作,还要处理好hyper的状态维护工作。这里的工作分为三个部分
在hyper状态下设置zImage特有的hyper异常表“__hyp_stub_vectors”, 
在SVC状态下完成zImage的解压定位工作。
通过hyper异常表“__hyp_stub_vectors”的hyper异常,设置新的hyper异常表:“__hyp_reentry_vectors”并由此进入kernel。


zImage在获得控制权之后第一件事要设置hyper状态的异常表,并返回SVC态,这通过“__hyp_stub_install”来完成:


ENTRY(__hyp_stub_install)

adr r7, __hyp_stub_vectors
mcr p15, 4, r7, c12, c0, 0 @ set hypervisor vector base (HVBAR)






zImage使用的第一个hyper异常表,在工作时守护在hyper态:


__hyp_stub_vectors:

__hyp_stub_trap: W(b) __hyp_stub_do_trap



可见,该异常表为zIamge提供了一个hyper模式入口:


//该函数为SVC模式提供两种选择,读取HVBAR或设置HVBAR
__hyp_stub_do_trap:
    //检查功能选择,若设置HVBAR,r0携带者HVBAR地址
cmp r0, #-1
   //读取HVBAR


mrceq p15, 4, r0, c12, c0, 0 @ get HVBAR
    //设置HVBAR
mcrne p15, 4, r0, c12, c0, 0 @ set HVBAR
    //返回到SVC状态
__ERET
ENDPROC(__hyp_stub_do_trap)


若zImage若需改动HVBAR可通过如下函数进行


//读HVBAR
ENTRY(__hyp_get_vectors)
    //r0携带-1
mov r0, #-1
//设置HVBAR,这之前r0已经赋予异常表地址
ENDPROC(__hyp_get_vectors)
ENTRY(__hyp_set_vectors)
    //调用hyper异常 
__HVC(0)
mov pc, lr




head.s


kernel

static void cpu_init_hyp_mode(void *dummy)
{


    //设置hyper态的新的异常表:“__kvm_hyp_init”
__hyp_set_vectors(kvm_get_idmap_vector());
    
boot_pgd_ptr = kvm_mmu_get_boot_httbr();
pgd_ptr = kvm_mmu_get_httbr();
stack_page = __this_cpu_read(kvm_arm_hyp_stack_page);
hyp_stack_ptr = stack_page + PAGE_SIZE;
vector_ptr = (unsigned long)__kvm_hyp_vector;
    //hvc调用“__do_hyp_init”
__cpu_init_hyp_mode(boot_pgd_ptr, pgd_ptr, hyp_stack_ptr, vector_ptr);
}



static inline void __cpu_init_hyp_mode(phys_addr_t boot_pgd_ptr,
      phys_addr_t pgd_ptr,
      unsigned long hyp_stack_ptr,
      unsigned long vector_ptr)
{



kvm_call_hyp(NULL, 0, boot_pgd_ptr);


kvm_call_hyp((void*)hyp_stack_ptr, vector_ptr, pgd_ptr);
}




Hyper态的页表页目录




int kvm_mmu_init(void)
{
int err;
    
    /* hyp_idmap_start 与hyp_idmap_end 是“kvm/init.S”起始物理地址“PA”*/
hyp_idmap_start = kvm_virt_to_phys(__hyp_idmap_text_start);
hyp_idmap_end = kvm_virt_to_phys(__hyp_idmap_text_end);
hyp_idmap_vector = kvm_virt_to_phys(__kvm_hyp_init);



    // hyp_pgd,hyper态的主页表页目录
hyp_pgd = kzalloc(PTRS_PER_PGD * sizeof(pgd_t), GFP_KERNEL);
    //hyper初始化代码“kvm/init.S”使用的页表页目录
boot_hyp_pgd = kzalloc(PTRS_PER_PGD * sizeof(pgd_t), GFP_KERNEL);



/*在boot_hyp_pgd映射“kvm/init.S”所在物理地址 */
err = __create_hyp_mappings(boot_hyp_pgd,
     hyp_idmap_start, hyp_idmap_end,
     __phys_to_pfn(hyp_idmap_start),
     PAGE_HYP);





/* 在boot_hyp_pgd映射“kvm/init.S”所在物理地址  */
err = __create_hyp_mappings(boot_hyp_pgd,
     TRAMPOLINE_VA, TRAMPOLINE_VA + PAGE_SIZE,
     __phys_to_pfn(hyp_idmap_start),
     PAGE_HYP);



/* Map the same page again into the runtime page tables */
err = __create_hyp_mappings(hyp_pgd,
     TRAMPOLINE_VA, TRAMPOLINE_VA + PAGE_SIZE,
     __phys_to_pfn(hyp_idmap_start),
     PAGE_HYP);



return 0;
out:
free_hyp_pgds();
return err;
}

你可能感兴趣的:(android,虚拟机,dalvik)