text: /*
   * Copyright (c) 2014 Travis Geiselbrecht
   *
   * Permission is hereby granted, free of charge, to any person obtaining
   * a copy of this software and associated documentation files
   * (the "Software"), to deal in the Software without restriction,
   * including without limitation the rights to use, copy, modify, merge,
   * publish, distribute, sublicense, and/or sell copies of the Software,
   * and to permit persons to whom the Software is furnished to do so,
   * subject to the following conditions:
   *
   * The above copyright notice and this permission notice shall be
   * included in all copies or substantial portions of the Software.
   *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
   * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
   * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
   * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
   * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   */
  #pragma once
  
  .macro push ra, rb, rsp=sp, prealloc=0
      stp     \ra, \rb, [\rsp,#-(16 + \prealloc)]!
  .endm
  
  .macro pop ra, rb, rsp=sp, postfree=0
      ldp     \ra, \rb, [\rsp], #(16 + \postfree)
  .endm
  
  .macro adrl reg, sym
      adrp    \reg, \sym
      add     \reg, \reg, #:lo12:\sym
  .endm
  
  .macro tbzmask, reg, mask, label, shift=0
  .if \shift >= 64
      .error "tbzmask: unsupported mask, \mask"
  .elseif \mask == 1 << \shift
      tbz     \reg, #\shift, \label
  .else
      tbzmask \reg, \mask, \label, "(\shift + 1)"
  .endif
  .endm
  
  .macro tbnzmask, reg, mask, label, shift=0
  .if \shift >= 64
      .error "tbnzmask: unsupported mask, \mask"
  .elseif \mask == 1 << \shift
      tbnz     \reg, #\shift, \label
  .else
      tbnzmask \reg, \mask, \label, "(\shift + 1)"
  .endif
  .endm
  
  .macro calloc_bootmem_aligned, new_ptr, new_ptr_end, tmp, size_shift, phys_offset=0
  .if \size_shift < 4
      .error "calloc_bootmem_aligned: Unsupported size_shift, \size_shift"
  .endif
  
      /* load boot_alloc_end */
      adrp    \tmp, boot_alloc_end
      ldr     \new_ptr, [\tmp, #:lo12:boot_alloc_end]
  
      /* align to page */
  .if \size_shift > 12
      add     \new_ptr, \new_ptr, #(1 << \size_shift)
      sub     \new_ptr, \new_ptr, #1
  .else
      add     \new_ptr, \new_ptr, #(1 << \size_shift) - 1
  .endif
      and     \new_ptr, \new_ptr, #~((1 << \size_shift) - 1)
  
      /* add one page and store boot_alloc_end */
      add     \new_ptr_end, \new_ptr, #(1 << \size_shift)
      str     \new_ptr_end, [\tmp, #:lo12:boot_alloc_end]
  
      /* translate address */
      sub     \new_ptr, \new_ptr, \phys_offset
      sub     \new_ptr_end, \new_ptr_end, \phys_offset
  
      /* clear page */
      mov     \tmp, \new_ptr
  .Lcalloc_bootmem_aligned_clear_loop\@:
      stp     xzr, xzr, [\tmp], #16
      cmp     \tmp, \new_ptr_end
      b.lo    .Lcalloc_bootmem_aligned_clear_loop\@
  .endm
  
  /* Set fault handler for next instruction */
  .macro set_fault_handler, handler
  .Lfault_location\@:
  .pushsection .rodata.fault_handler_table
      .quad    .Lfault_location\@ - .
      .quad    \handler - .
  .popsection
  .endm
  