예제 #1
0
uint32_t *arm_dataabort(uint32_t *regs, uint32_t dfar, uint32_t dfsr)
{
  DFAR struct tcb_s *tcb = (DFAR struct tcb_s *)g_readytorun.head;
  uint32_t *savestate;

  /* Save the saved processor context in current_regs where it can be accessed
   * for register dumps and possibly context switching.
   */

  savestate    = (uint32_t*)current_regs;
  current_regs = regs;

  /* In the NuttX on-demand paging implementation, only the read-only, .text
   * section is paged.  However, the ARM compiler generated PC-relative data
   * fetches from within the .text sections.  Also, it is customary to locate
   * read-only data (.rodata) within the same section as .text so that it
   * does not require copying to RAM. Misses in either of these case should
   * cause a data abort.
   *
   * We are only interested in data aborts due to page translations faults.
   * Sections should already be in place and permissions should already be
   * be set correctly (to read-only) so any other data abort reason is a
   * fatal error.
   */

  pglldbg("DFSR: %08x DFAR: %08x\n", dfsr, dfar);
  if ((dfsr & FSR_MASK) != FSR_PAGE)
    {
      goto segfault;
    }

  /* Check the (virtual) address of data that caused the data abort. When
   * the exception occurred, this address was provided in the DFAR register.
   * (It has not yet been saved in the register context save area).
   */

  pgllvdbg("VBASE: %08x VEND: %08x\n", PG_PAGED_VBASE, PG_PAGED_VEND);
  if (dfar < PG_PAGED_VBASE || dfar >= PG_PAGED_VEND)
    {
      goto segfault;
    }

  /* Save the offending data address as the fault address in the TCB of
   * the currently task.  This fault address is also used by the prefetch
   * abort handling; this will allow common paging logic for both
   * prefetch and data aborts.
   */

  tcb->xcp.dfar = regs[REG_R15];

  /* Call pg_miss() to schedule the page fill.  A consequences of this
   * call are:
   *
   * (1) The currently executing task will be blocked and saved on
   *     on the g_waitingforfill task list.
   * (2) An interrupt-level context switch will occur so that when
   *     this function returns, it will return to a different task,
   *     most likely the page fill worker thread.
   * (3) The page fill worker task has been signalled and should
   *     execute immediately when we return from this exception.
   */

  pg_miss();

  /* Restore the previous value of current_regs.  NULL would indicate that
   * we are no longer in an interrupt handler.  It will be non-NULL if we
   * are returning from a nested interrupt.
   */

  current_regs = savestate;
  return regs;

segfault:
  lldbg("Data abort. PC: %08x DFAR: %08x DFSR: %08x\n",
        regs[REG_PC], dfar, dfsr);
  PANIC();
  return regs; /* To keep the compiler happy */
}
예제 #2
0
uint32_t *arm_prefetchabort(uint32_t *regs, uint32_t ifar, uint32_t ifsr)
{
   uint32_t *savestate;

  /* Save the saved processor context in current_regs where it can be accessed
   * for register dumps and possibly context switching.
   */

  savestate    = (uint32_t *)current_regs;
  current_regs = regs;

  /* Get the (virtual) address of instruction that caused the prefetch abort.
   * When the exception occurred, this address was provided in the lr register
   * and this value was saved in the context save area as the PC at the
   * REG_R15 index.
   *
   * Check to see if this miss address is within the configured range of
   * virtual addresses.
   */

  pglldbg("VADDR: %08x VBASE: %08x VEND: %08x\n",
          regs[REG_PC], PG_PAGED_VBASE, PG_PAGED_VEND);

  if (regs[REG_R15] >= PG_PAGED_VBASE && regs[REG_R15] < PG_PAGED_VEND)
    {
      /* Save the offending PC as the fault address in the TCB of the currently
       * executing task.  This value is, of course, already known in regs[REG_R15],
       * but saving it in this location will allow common paging logic for both
       * prefetch and data aborts.
       */

      struct tcb_s *tcb = this_task();
      tcb->xcp.far  = regs[REG_R15];

      /* Call pg_miss() to schedule the page fill.  A consequences of this
       * call are:
       *
       * (1) The currently executing task will be blocked and saved on
       *     on the g_waitingforfill task list.
       * (2) An interrupt-level context switch will occur so that when
       *     this function returns, it will return to a different task,
       *     most likely the page fill worker thread.
       * (3) The page fill worker task has been signalled and should
       *     execute immediately when we return from this exception.
       */

      pg_miss();

      /* Restore the previous value of current_regs.  NULL would indicate that
       * we are no longer in an interrupt handler.  It will be non-NULL if we
       * are returning from a nested interrupt.
       */

      current_regs = savestate;
    }
  else
    {
      lldbg("Prefetch abort. PC: %08x IFAR: %08x IFSR: %08x\n",
            regs[REG_PC], ifar, ifsr);
      PANIC();
    }

  return regs;
}