864 /* NOTE: this function can trigger an exception */
865 /* NOTE2: the returned address is not exactly the physical address: it
866 * is actually a ram_addr_t (in system mode; the user mode emulation
867 * version of this function returns a guest virtual address).
868 */
869 tb_page_addr_t get_page_addr_code(CPUArchState *env, target_ulong addr)
870 {
871 int mmu_idx, index, pd;
872 void *p;
873 MemoryRegion *mr;
874 CPUState *cpu = ENV_GET_CPU(env);
875 CPUIOTLBEntry *iotlbentry;
876 hwaddr physaddr;
877
878 index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
879 mmu_idx = cpu_mmu_index(env, true);
880 if (unlikely(env->tlb_table[mmu_idx][index].addr_code !=
881 (addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK)))) {
882 if (!VICTIM_TLB_HIT(addr_read, addr)) {
883 tlb_fill(ENV_GET_CPU(env), addr, 0, MMU_INST_FETCH, mmu_idx, 0);
884 }
885 }
886 iotlbentry = &env->iotlb[mmu_idx][index];
887 pd = iotlbentry->addr & ~TARGET_PAGE_MASK;
888 mr = iotlb_to_region(cpu, pd, iotlbentry->attrs);
889 if (memory_region_is_unassigned(mr)) {
890 qemu_mutex_lock_iothread();
891 if (memory_region_request_mmio_ptr(mr, addr)) {
892 qemu_mutex_unlock_iothread();
893 /* A MemoryRegion is potentially added so re-run the
894 * get_page_addr_code.
895 */
896 return get_page_addr_code(env, addr);
897 }
898 qemu_mutex_unlock_iothread();
899
900 /* Give the new-style cpu_transaction_failed() hook first chance
901 * to handle this.
902 * This is not the ideal place to detect and generate CPU
903 * exceptions for instruction fetch failure (for instance
904 * we don't know the length of the access that the CPU would
905 * use, and it would be better to go ahead and try the access
906 * and use the MemTXResult it produced). However it is the
907 * simplest place we have currently available for the check.
908 */
909 physaddr = (iotlbentry->addr & TARGET_PAGE_MASK) + addr;
910 cpu_transaction_failed(cpu, physaddr, addr, 0, MMU_INST_FETCH, mmu_idx,
911 iotlbentry->attrs, MEMTX_DECODE_ERROR, 0);
912
913 cpu_unassigned_access(cpu, addr, false, true, 0, 4);
914 /* The CPU's unassigned access hook might have longjumped out
915 * with an exception. If it didn't (or there was no hook) then
916 * we can't proceed further.
917 */
918 report_bad_exec(cpu, addr);
919 exit(1);
920 }
921 p = (void *)((uintptr_t)addr + env->tlb_table[mmu_idx][index].addend);
922 return qemu_ram_addr_from_host_nofail(p);
923 }
这个函数的参数CPUArchState 为当前cpu的状态,记录了当前cpu的寄存器,tlb等状态。 参数addr为一个虚拟地址,这个函数就是要找到该虚拟地址的对应的主机虚拟地址
转化的过程
guest 虚拟地址(GVD) -> guest 物理地址(GPD) -> host 虚拟地址(HVD)
后面都使用GVD,GPD,HVD代表这三种地址
为什么要这么转化呢, 因为真正的数据存在HVD里面,我们要访问到虚拟机的系统里的数据/代码就是通过HVD。(访问到这些数据,代码就能进行翻译执行了)
878-885行首先在tlb中找到虚拟地址对应的索引(tlb的作用就是缓存虚拟地址->物理地址的映射)如果tlb中没有对应页面的索引,则使用tlb_fill进行填充
888 行找到对应的MemoryRegion。
889-898行如果这个MemoryRegion是为定义的区域,则使用memory_region_request_mmio_ptr来创建该区域。区域创建好后重新使用get_page_addr_code来进行地址转换。
899-919行是异常情况,我们不分析
922行 qemu_ram_addr_from_host_nofail 转换gpa到hpa