接着上一次malloc(探秘malloc是如何申请内存的)的dump信息继续分析。
-006|do_anonymous_page(inline)
| vma = 0xFFFFFFE314E27310
| tsk = 0xFFFFFFE300786640
| entry = (pte = 0x00E800026F281F53)
-006|handle_pte_fault(
| vmf = 0xFFFFFF80202A3BF0)
-007|handle_mm_fault(
| vma = 0xFFFFFFE314E27310,
| address = 0x00000076143BC000,
| flags = 0x55)
-008|do_page_fault(
| addr = 0x00000076143BC008,
| esr = 0x92000047,
| regs = 0xFFFFFF80202A3EC0)
| vma = 0xFFFFFFE314E27310
| mm_flags = 0x55
| vm_flags = 0x2
| major = 0x0
| tsk = 0xFFFFFFE300786640
| mm = 0xFFFFFFE2EBB33440
-009|test_ti_thread_flag(inline)
-009|do_translation_fault(
| addr = 0x00000076143BC008,
| esr = 0x92000047,
| regs = 0xFFFFFF80202A3EC0)
-010|do_mem_abort(
| addr = 0x00000076143BC008,
| esr = 0x92000047,
| regs = 0xFFFFFF80202A3EC0)
-011|el0_da(asm)
-->|exception
现在来看下代码的流程
static vm_fault_t do_anonymous_page(struct vm_fault *vmf)
{
struct vm_area_struct *vma = vmf->vma;
struct mem_cgroup *memcg;
struct page *page;
vm_fault_t ret = 0;
pte_t entry;
/* File mapping without ->vm_ops ? */
if (vmf->vma_flags & VM_SHARED)
return VM_FAULT_SIGBUS;
if (pte_alloc(vma->vm_mm, vmf->pmd, vmf->address))
return VM_FAULT_OOM;
/* Use the zero-page for reads */
if (!(vmf->flags & FAULT_FLAG_WRITE) &&
!mm_forbids_zeropage(vma->vm_mm)) {
entry = pte_mkspecial(pfn_pte(my_zero_pfn(vmf->address),
vmf->vma_page_prot));
if (!pte_map_lock(vmf))
return VM_FAULT_RETRY;
if (!pte_none(*vmf->pte))
goto unlock;
ret = check_stable_address_space(vma->vm_mm);
if (ret)
goto unlock;
/*
* Don't call the userfaultfd during the speculative path.
* We already checked for the VMA to not be managed through
* userfaultfd, but it may be set in our back once we have lock
* the pte. In such a case we can ignore it this time.
*/
if (vmf->flags & FAULT_FLAG_SPECULATIVE)
goto setpte;
/* Deliver the page fault to userland, check inside PT lock */
if (userfaultfd_missing(vma)) {
pte_unmap_unlock(vmf->pte, vmf->ptl);
return handle_userfault(vmf, VM_UFFD_MISSING);
}
goto setpte;
}
#define my_zero_pfn(addr) page_to_pfn(ZERO_PAGE(addr))
/*
* ZERO_PAGE is a global shared page that is always zero: used
* for zero-mapped memory areas etc..
*/
extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
#define ZERO_PAGE(vaddr) phys_to_page(__pa_symbol(empty_zero_page))
/* Allocate our own private page. */
if (unlikely(anon_vma_prepare(vma)))
goto oom;
page = alloc_zeroed_user_highpage_movable(vma, vmf->address);
if (!page)
goto oom;
static inline struct page *
alloc_zeroed_user_highpage_movable(struct vm_area_struct *vma,
unsigned long vaddr)
{
#ifndef CONFIG_CMA
return __alloc_zeroed_user_highpage(__GFP_MOVABLE, vma, vaddr);
#else
return __alloc_zeroed_user_highpage(__GFP_MOVABLE|__GFP_CMA, vma,
vaddr);
#endif
}
entry = mk_pte(page, vmf->vma_page_prot);
if (vmf->vma_flags & VM_WRITE)
entry = pte_mkwrite(pte_mkdirty(entry));
if (!pte_map_lock(vmf)) {
ret = VM_FAULT_RETRY;
goto release;
}
if (!pte_none(*vmf->pte))
goto unlock_and_release
inc_mm_counter_fast(vma->vm_mm, MM_ANONPAGES);
__page_add_new_anon_rmap(page, vma, vmf->address, false);
mem_cgroup_commit_charge(page, memcg, false, false);
__lru_cache_add_active_or_unevictable(page, vmf->vma_flags);
setpte:
set_pte_at(vma->vm_mm, vmf->address, vmf->pte, entry);
/* No need to invalidate - it was non-present before */
update_mmu_cache(vma, vmf->address, vmf->pte);
/*
* PTE bits configuration in the presence of hardware Dirty Bit Management
* (PTE_WRITE == PTE_DBM):
*
* Dirty Writable | PTE_RDONLY PTE_WRITE PTE_DIRTY (sw)
* 0 0 | 1 0 0
* 0 1 | 1 1 0
* 1 0 | 1 0 1
* 1 1 | 0 1 x
*
* When hardware DBM is not present, the sofware PTE_DIRTY bit is updated via
* the page fault mechanism. Checking the dirty status of a pte becomes:
*
* PTE_DIRTY || (PTE_WRITE && !PTE_RDONLY)
*/
static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, pte_t pte)
{
pte_t old_pte;
if (pte_present(pte) && pte_user_exec(pte) && !pte_special(pte))
__sync_icache_dcache(pte);
/*
* If the existing pte is valid, check for potential race with
* hardware updates of the pte (ptep_set_access_flags safely changes
* valid ptes without going through an invalid entry).
*/
old_pte = READ_ONCE(*ptep);
if (IS_ENABLED(CONFIG_DEBUG_VM) && pte_valid(old_pte) && pte_valid(pte) &&
(mm == current->active_mm || atomic_read(&mm->mm_users) > 1)) {
VM_WARN_ONCE(!pte_young(pte),
"%s: racy access flag clearing: 0x%016llx -> 0x%016llx",
__func__, pte_val(old_pte), pte_val(pte));
VM_WARN_ONCE(pte_write(old_pte) && !pte_dirty(pte),
"%s: racy dirty state clearing: 0x%016llx -> 0x%016llx",
__func__, pte_val(old_pte), pte_val(pte));
}
set_pte(ptep, pte);
}
那我们0x00000076143BC000地址到底对应的物理地址是多少呢? 我们来计算下:
pdg_index = (0x00000076143BC000 >> 30) & (0x200 - 1) = 0x01D8
pdg = 0xFFFFFFE2E5D8B000+ 0x01D8*8 = 0xFFFFFFE2E5D8BEC0 = rd(0xFFFFFFE2E5D8BEC0 ) = 0xE5E5D003
pmd_index = (0x00000076143BC000 >> 21) & (0x1FF ) = 0xA1
pmd = 0xE5E5D003+ 0xA1 * 8 = 0xE5E5D000+ 0xA1 * 8 = 0xE5E5D508 = rd(C:0xE5E5D508) = E5E5A003
pte_index = (0x00000076143BC000 >> 12) & (0x200 -1 ) = 0x01BC
pte = 0xE5E5A003 + 0x1BC * 8 = 0xE5E5A000 + 0x1BC*8 = 0xE5E5ADE0 = rd(0xE5E5ADE0 ) = 0xE800026F281F53
pfn = (0xE800026F281F53 >> 12)&0xfffffffff = 0x26F281
phy = 0x0x26F281 << 12 + offset = 0x26F281000 + 000 = 0x26F281000