|
From: | ckim |
Subject: | Get_page_addr_code_hostp function returns -1 after turning MMU on |
Date: | Fri, 12 Mar 2021 17:33:08 +0900 |
Hello, all I’m having a trouble while trying to run a bare-metal program on qemu (virt, cortext-a72, running in EL3), so I ask for a help here again. The phenomenon is : right after I set sctlr_el3 register (with MMU enable bit set), the next instruction fetch causes exception, with “cannot access memory at ...” error. I have followed the get_phy_addr function (get_phy_addr_lpae inside) and saw qemu walks the page table almost ok. (almost because I didn’t understand 100% of them). At least it followed all the descriptor addresses, entries, and attributes. The get_phys_addr returned false (meaning translation was successful). The arm-supported bare-metal startup code has a page table that has 1GB block descriptors and a table entry in the first table, and the next level tables had 2MB block entries, which looked like level 1 and level 2 tables according to the Armv8 spec. (the TTBR0_EL3 register points to this first table) (Armv8 spec says level 0 table can’t have block descriptor and level 1 and level 2 block size is 1GB and 2MB, for 64KB granule, which is my case) So I tried adding the level 0 table before the first table and now qemu thinks the final block entry is 2MB size and sets page_size to 2MB. (before it thought the last block was 1GB). But the problem is still persistent. Now I should see the very complex looking tlb_set_page_with_attrs function (they are in arm_cpu_tbl_fill function in target/arm/tlb_helper.c. ) When briefly following it with debugger, I found that in the function below the condition “entry->addr_code & TLB_MMIO” is true and it returns -1. (by the way I set the first 2MB’s to read-only blocks, because they are flash/ROM) Could anyone explain to me what this condition is? Just a brief explanation will be much appreciated. tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, target_ulong addr, void **hostp) { uintptr_t mmu_idx = cpu_mmu_index(env, true); uintptr_t index = tlb_index(env, mmu_idx, addr); CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr); void *p; if (unlikely(!tlb_hit(entry->addr_code, addr))) { .... omitted... } if (unlikely(entry->addr_code & TLB_MMIO)) { <======= returns -1 /* The region is not backed by RAM. */ if (hostp) { *hostp = NULL; } return -1; } p = (void *)((uintptr_t)addr + entry->addend); if (hostp) { *hostp = p; } return qemu_ram_addr_from_host_nofail(p); } Thanks! Chan Kim |
[Prev in Thread] | Current Thread | [Next in Thread] |