Posts Tagged ‘arm64’

kernel: arm64: mm: how user space stack grows

December 28, 2015

This post discusses how user space stack grows.

reference code base
linux 4.3

kernel config assumption
# CONFIG_STACK_GROWSUP is not set

how does user space stack grow
As discussed in kernel: mm: task->mm->mmap_sem, virtual address space is represented by intervals of VMAs. The stack itself corresponding to a VMA whose vm_flags has flag VM_GROWSDOWN set.

If a stack grows below its corresponding VMA’s scope, then a page fault will be triggered. __do_page_fault() calls expand_stack() to extend the corresponding VMA downward. Then, it calls -> handle_mm_fault() to allocate a page and modify page tables.

do_page_fault()
-> __do_page_fault()
   -> expand_stack()
    -> expand_downwards()
   -> handle_mm_fault()
      -> __handle_mm_fault()

__do_page_fault
If vma->vm_start > addr, then __do_page_fault() checks if VM_GROWSDOWN flag is set in vma->vm_flags. If true, then it calls expand_stack(vma, addr) to expand the VMA by 1 page. If successful, it calls handle_mm_fault() to allocate a page and modify page tables.

157 static int __do_page_fault(struct mm_struct *mm, unsigned long addr,
158                            unsigned int mm_flags, unsigned long vm_flags,
159                            struct task_struct *tsk)
160 {
161         struct vm_area_struct *vma;
162         int fault;
163 
164         vma = find_vma(mm, addr);
165         fault = VM_FAULT_BADMAP;
166         if (unlikely(!vma))
167                 goto out;
168         if (unlikely(vma->vm_start > addr))
169                 goto check_stack;
170 
171         /*
172          * Ok, we have a good vm_area for this memory access, so we can handle
173          * it.
174          */
175 good_area:
176         /*
177          * Check that the permissions on the VMA allow for the fault which
178          * occurred. If we encountered a write or exec fault, we must have
179          * appropriate permissions, otherwise we allow any permission.
180          */
181         if (!(vma->vm_flags & vm_flags)) {
182                 fault = VM_FAULT_BADACCESS;
183                 goto out;
184         }
185 
186         return handle_mm_fault(mm, vma, addr & PAGE_MASK, mm_flags);
187 
188 check_stack:
189         if (vma->vm_flags & VM_GROWSDOWN && !expand_stack(vma, addr))
190                 goto good_area;
191 out:
192         return fault;
193 }

conclusion
This post discusses how user space stack grows. While stack is below its lowest address defined by VMA. A page fault is triggered to extend the corresponding VMA downward by 1 page, allocate a page, and modify page tables.