Exemple #1
0
void *ppc_exc_vector_address(unsigned vector)
{
  uintptr_t vector_base = 0xfff00000;
  uintptr_t vector_offset = vector << 8;

  if (ppc_cpu_has_altivec()) {
    if (vector == ASM_60X_VEC_VECTOR) {
      vector_offset = ASM_60X_VEC_VECTOR_OFFSET;
    }
  }

  if (ppc_cpu_is(PPC_405)) {
    switch (vector) {
      case ASM_BOOKE_FIT_VECTOR:
        vector_offset = ASM_PPC405_FIT_VECTOR_OFFSET;
        break;
      case ASM_BOOKE_WDOG_VECTOR:
        vector_offset = ASM_PPC405_WDOG_VECTOR_OFFSET;
        break;
      case ASM_TRACE_VECTOR:
        vector_offset = ASM_PPC405_TRACE_VECTOR_OFFSET;
        break;
      case ASM_PPC405_APU_UNAVAIL_VECTOR:
        vector_offset = ASM_60X_VEC_VECTOR_OFFSET;
      default:
        break;
    }
  }

  if (
    ppc_cpu_is_bookE() == PPC_BOOKE_STD
      || ppc_cpu_is_bookE() == PPC_BOOKE_E500
  ) {
    if (vector < sizeof(ivor_values) / sizeof(ivor_values [0])) {
      vector_offset = ((uintptr_t) ivor_values [vector]) << 4;
    } else {
      vector_offset = 0;
    }
  }

  if (bsp_exceptions_in_RAM) {
    vector_base = ppc_exc_vector_base;
  }

  return (void *) (vector_base + vector_offset);
}
Exemple #2
0
/* legacy mode for bookE DEC exception;
 * to avoid the double layer of function calls
 * (dec_handler_bookE -> C_dispatch_irq_handler -> user handler)
 * it is preferrable for the user to hook the DEC
 * exception directly.
 * However, the legacy mode works with less modifications
 * of user code.
 */
int C_dispatch_dec_handler_bookE (BSP_Exception_frame *frame, unsigned int excNum)
{
	/* clear interrupt; we must do this
	 * before C_dispatch_irq_handler()
	 * re-enables MSR_EE.
	 * Note that PPC405 uses a different SPR# for TSR
	 */
	if ( ppc_cpu_is_bookE()==PPC_BOOKE_405)
		_write_PPC405_TSR( BOOKE_TSR_DIS );
	else
		_write_BOOKE_TSR( BOOKE_TSR_DIS );
	return C_dispatch_irq_handler(frame, ASM_DEC_VECTOR);
}
static uint32_t ppc_exc_get_DAR_dflt(void)
{
  if (ppc_cpu_is_60x())
    return PPC_SPECIAL_PURPOSE_REGISTER(PPC_DAR);
  else
    switch (ppc_cpu_is_bookE()) {
      default:
        break;
      case PPC_BOOKE_STD:
      case PPC_BOOKE_E500:
        return PPC_SPECIAL_PURPOSE_REGISTER(DEAR_BOOKE);
      case PPC_BOOKE_405:
        return PPC_SPECIAL_PURPOSE_REGISTER(DEAR_405);
    }
  return 0xdeadbeef;
}
Exemple #4
0
int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config)
{
    int                           i;
    rtems_interrupt_level         level;
    rtems_irq_connect_data*       vchain;

    /*
     * Store various code accelerators
     */
    internal_config 		= config;
    default_rtems_entry 	= config->defaultEntry;
    rtems_hdl_tbl 		= config->irqHdlTbl;

    rtems_interrupt_disable(level);

	if ( !BSP_setup_the_pic(config) ) {
		printk("PIC setup failed; leaving IRQs OFF\n");
		return 0;
	}

	for ( i = config->irqBase; i < config->irqBase + config->irqNb; i++ ) {
		for( vchain = &rtems_hdl_tbl[i];
		     ((int)vchain != -1 && vchain->hdl != default_rtems_entry.hdl);
		     vchain = (rtems_irq_connect_data*)vchain->next_handler )
		{
			if (vchain->on)
              vchain->on(vchain);
		}
		if ( vchain != &rtems_hdl_tbl[i] ) {
			/* at least one handler registered */
			BSP_enable_irq_at_pic(i);
		} else {
/* Do NOT disable; there might be boards with cascaded
 * interrupt controllers where the BSP (incorrectly) does
 * not ignore the cascaded interrupts in BSP_disable_irq_at_pic()!
 * Instead, we rely on BSP_setup_the_pic() for a good
 * initial configuration.
 *
			BSP_disable_irq_at_pic(i);
 */
		}
	}

    rtems_interrupt_enable(level);

	{
			ppc_exc_set_handler(ASM_EXT_VECTOR, C_dispatch_irq_handler);

			if ( ppc_cpu_is_bookE() ) {
				/* bookE decrementer interrupt needs to be cleared BEFORE
				 * dispatching the user ISR (because the user ISR is called
				 * with EE enabled)
				 * We do this so that existing DEC handlers can be used
				 * with minor modifications.
				 */
				ppc_exc_set_handler(ASM_BOOKE_DEC_VECTOR, C_dispatch_dec_handler_bookE);
			} else {
				ppc_exc_set_handler(ASM_DEC_VECTOR, C_dispatch_irq_handler);
			}
	}
    return 1;
}
Exemple #5
0
rtems_device_driver Clock_initialize( rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
	/* Current CPU type */
	ppc_cpu_id_t cpu_type = get_ppc_cpu_type();

	/* Make major/minor available to others such as shared memory driver */
	rtems_clock_major = major;
	rtems_clock_minor = minor;

	/*
	 * Set default ticker.
	 *
	 * The function rtems_clock_tick() returns a status code.  This value
	 * will be discarded since the RTEMS documentation claims that it is
	 * always successful.
	 */
	ppc_clock_tick = (void (*)(void)) rtems_clock_tick;

	/* Set the decrementer to the maximum value */
	ppc_set_decrementer_register( PPC_CLOCK_DECREMENTER_MAX);

	/* Decrementer value */
	ppc_clock_decrementer_value = bsp_clicks_per_usec * rtems_configuration_get_microseconds_per_tick() - 1;

	/* Check decrementer value */
	if (ppc_clock_decrementer_value == 0) {
		ppc_clock_decrementer_value = PPC_CLOCK_DECREMENTER_MAX;
		RTEMS_SYSLOG_ERROR( "decrementer value would be zero, will be set to maximum value instead\n");
	}

	/* Set the nanoseconds since last tick handler */
	rtems_clock_set_nanoseconds_extension( ppc_clock_nanoseconds_since_last_tick);

	if (ppc_cpu_is_bookE()) {
		/* Set decrementer auto-reload value */
		PPC_SET_SPECIAL_PURPOSE_REGISTER( BOOKE_DECAR, ppc_clock_decrementer_value);

		/* Install exception handler */
		ppc_exc_set_handler( ASM_BOOKE_DEC_VECTOR, ppc_clock_exception_handler_booke);

		/* Enable decrementer and auto-reload */
		PPC_SET_SPECIAL_PURPOSE_REGISTER_BITS( BOOKE_TCR, BOOKE_TCR_DIE | BOOKE_TCR_ARE);
	} else if (cpu_type == PPC_e300c2 || cpu_type == PPC_e300c3) {
		/* TODO: Not tested for e300c2 */

		/* Enable auto-reload */
		PPC_SET_SPECIAL_PURPOSE_REGISTER_BITS( HID0, 0x00000040);

		/* Install exception handler */
		ppc_exc_set_handler( ASM_DEC_VECTOR, ppc_clock_exception_handler_e300);
	} else {
		/* Here the decrementer value is actually the interval */
		++ppc_clock_decrementer_value;

		/* Initialize next time base */
		ppc_clock_next_time_base = ppc_time_base() + ppc_clock_decrementer_value;

		/* Install exception handler */
		ppc_exc_set_handler( ASM_DEC_VECTOR, ppc_clock_exception_handler_first);
	}

	/* Set the decrementer value */
	ppc_set_decrementer_register( ppc_clock_decrementer_value);

	return RTEMS_SUCCESSFUL;
}
Exemple #6
0
rtems_status_code ppc_exc_make_prologue(
  unsigned vector,
  ppc_exc_category category,
  uint32_t *prologue,
  size_t *prologue_size
)
{
  const uint32_t *prologue_template = NULL;
  size_t prologue_template_size = 0;
  bool fixup_vector = false;

  if (!ppc_exc_is_valid_category(category)) {
    return RTEMS_INVALID_NUMBER;
  }

  if (
    ppc_cpu_has_shadowed_gprs()
      && (vector == ASM_60X_IMISS_VECTOR
        || vector == ASM_60X_DLMISS_VECTOR
        || vector == ASM_60X_DSMISS_VECTOR)
  ) {
    prologue_template = ppc_exc_tgpr_clr_prolog;
    prologue_template_size = (size_t) ppc_exc_tgpr_clr_prolog_size;
  } else if (
    category == PPC_EXC_CLASSIC
      && ppc_cpu_is_bookE() != PPC_BOOKE_STD
      && ppc_cpu_is_bookE() != PPC_BOOKE_E500
  ) {
    prologue_template = ppc_exc_min_prolog_auto;
    prologue_template_size = (size_t) ppc_exc_min_prolog_size;
  } else if (
    category == PPC_EXC_CLASSIC_ASYNC
      && ppc_cpu_is_bookE() == PPC_BOOKE_E500
      && (ppc_interrupt_get_disable_mask() & MSR_CE) == 0
  ) {
    prologue_template = ppc_exc_min_prolog_async_tmpl_normal;
    prologue_template_size = (size_t) ppc_exc_min_prolog_size;
    fixup_vector = true;
  } else {
    prologue_template = ppc_exc_prologue_templates [category];
    prologue_template_size = (size_t) ppc_exc_min_prolog_size;
    fixup_vector = true;
  }

  if (prologue_template_size <= *prologue_size) {
    *prologue_size = prologue_template_size;

    memcpy(prologue, prologue_template, prologue_template_size);

    if (!ppc_exc_create_branch_op(vector, prologue, prologue_template_size)) {
      return RTEMS_INVALID_ADDRESS;
    }

    if (fixup_vector) {
      if (vector <= 0x7fffU) {
        prologue [PPC_EXC_PROLOG_VEC_OFFSET] =
          (prologue [PPC_EXC_PROLOG_VEC_OFFSET] & 0xffff8000U)
            | (vector & 0x7fffU);
      } else {
        return RTEMS_INVALID_ID;
      }
    }
  } else {
    return RTEMS_INVALID_SIZE;
  }

  return RTEMS_SUCCESSFUL;
}
Exemple #7
0
void ppc_exc_initialize_with_vector_base(
  uintptr_t interrupt_stack_begin,
  uintptr_t interrupt_stack_size,
  void *vector_base
)
{
  rtems_status_code sc = RTEMS_SUCCESSFUL;
  const ppc_exc_categories *const categories = ppc_exc_current_categories();
  unsigned vector = 0;
  uint32_t sda_base = 0;
  uint32_t r13 = 0;

  if (categories == NULL) {
    ppc_exc_fatal_error();
  }

  /* Assembly code needs SDA_BASE in r13 (SVR4 or EABI). Make sure
   * early init code put it there.
   */
  __asm__ volatile (
    "lis %0, _SDA_BASE_@h\n"
    "ori %0, %0, _SDA_BASE_@l\n"
    "mr  %1, 13\n"
    : "=r" (sda_base), "=r"(r13)
  );

  if (sda_base != r13) {
    ppc_exc_fatal_error();
  }

  ppc_exc_initialize_interrupt_stack(interrupt_stack_begin, interrupt_stack_size);

#ifndef PPC_EXC_CONFIG_BOOKE_ONLY

  /* Use current MMU / RI settings when running C exception handlers */
  ppc_exc_msr_bits = ppc_machine_state_register() & (MSR_DR | MSR_IR | MSR_RI);

#ifdef __ALTIVEC__
  /* Need vector unit enabled to save/restore altivec context */
  ppc_exc_msr_bits |= MSR_VE;
#endif

#endif /* PPC_EXC_CONFIG_BOOKE_ONLY */

  if (ppc_cpu_is_bookE() == PPC_BOOKE_STD || ppc_cpu_is_bookE() == PPC_BOOKE_E500) {
    ppc_exc_initialize_booke(vector_base);
  }

  for (vector = 0; vector <= LAST_VALID_EXC; ++vector) {
    ppc_exc_category category = ppc_exc_category_for_vector(categories, vector);

    if (category != PPC_EXC_INVALID) {
      void *const vector_address = ppc_exc_vector_address(vector, vector_base);
      uint32_t prologue [16];
      size_t prologue_size = sizeof(prologue);

      sc = ppc_exc_make_prologue(
        vector,
        vector_base,
        category,
        prologue,
        &prologue_size
      );
      if (sc != RTEMS_SUCCESSFUL) {
        ppc_exc_fatal_error();
      }

      ppc_code_copy(vector_address, prologue, prologue_size);
    }
  }

#ifndef PPC_EXC_CONFIG_BOOKE_ONLY
  /* If we are on a classic PPC with MSR_DR enabled then
   * assert that the mapping for at least this task's
   * stack is write-back-caching enabled (see README/CAVEATS)
   * Do this only if the cache is physically enabled.
   * Since it is not easy to figure that out in a
   * generic way we need help from the BSP: BSPs
   * which run entirely w/o the cache may set
   * ppc_exc_cache_wb_check to zero prior to calling
   * this routine.
   *
   * We run this check only after exception handling is
   * initialized so that we have some chance to get
   * information printed if it fails.
   *
   * Note that it is unsafe to ignore this issue; if
   * the check fails, do NOT disable it unless caches
   * are always physically disabled.
   */
  if (ppc_exc_cache_wb_check && (MSR_DR & ppc_exc_msr_bits)) {
    /* The size of 63 assumes cache lines are at most 32 bytes */
    uint8_t dummy[63];
    uintptr_t p = (uintptr_t) dummy;
    /* If the dcbz instruction raises an alignment exception
     * then the stack is mapped as write-thru or caching-disabled.
     * The low-level code is not capable of dealing with this
     * ATM.
     */
    p = (p + 31U) & ~31U;
    __asm__ volatile ("dcbz 0, %0"::"b" (p));
    /* If we make it thru here then things seem to be OK */
  }
Exemple #8
0
rtems_device_driver Clock_initialize(
  rtems_device_major_number major,
  rtems_device_minor_number minor,
  void *arg
)
{
  uint64_t frequency = bsp_time_base_frequency;
  uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick();
  uint32_t interval = (uint32_t) ((frequency * us_per_tick) / 1000000);

  /*
   * Set default ticker.
   */
  ppc_clock_tick = rtems_timecounter_tick;

  if (ppc_cpu_is_bookE() != PPC_BOOKE_405) {
    /* Decrementer value */
    ppc_clock_decrementer_value = interval - 1;

    /* Check decrementer value */
    if (ppc_clock_decrementer_value == 0) {
      ppc_clock_decrementer_value = PPC_CLOCK_DECREMENTER_MAX;
      RTEMS_SYSLOG_ERROR( "decrementer value would be zero, will be set to maximum value instead\n");
    }
    if (ppc_cpu_is_bookE()) {
      /* Set decrementer auto-reload value */
      PPC_SET_SPECIAL_PURPOSE_REGISTER( BOOKE_DECAR, ppc_clock_decrementer_value);

      /* Install exception handler */
      ppc_exc_set_handler( ASM_BOOKE_DEC_VECTOR, ppc_clock_exception_handler_booke);

      /* Enable decrementer and auto-reload */
      PPC_SET_SPECIAL_PURPOSE_REGISTER_BITS( BOOKE_TCR, BOOKE_TCR_DIE | BOOKE_TCR_ARE);
    } else {
      /* Here the decrementer value is actually the interval */
      ++ppc_clock_decrementer_value;

      /* Initialize next time base */
      ppc_clock_next_time_base = ppc_time_base() + ppc_clock_decrementer_value;

      /* Install exception handler */
      ppc_exc_set_handler( ASM_DEC_VECTOR, ppc_clock_exception_handler_first);
    }

    /* Set the decrementer value */
    ppc_set_decrementer_register( ppc_clock_decrementer_value);
  } else {
    /* PIT interval value */
    ppc_clock_decrementer_value = interval;

    /* Install exception handler */
    ppc_exc_set_handler(ASM_BOOKE_DEC_VECTOR, ppc_clock_exception_handler_ppc405);

    /* Enable PIT and auto-reload */
    PPC_SET_SPECIAL_PURPOSE_REGISTER_BITS(PPC405_TCR, BOOKE_TCR_DIE | BOOKE_TCR_ARE);

    /* Set PIT auto-reload and initial value */
    PPC_SET_SPECIAL_PURPOSE_REGISTER(PPC405_PIT, interval);
  }

  /* Install timecounter */
  ppc_tc.tc_get_timecount = ppc_get_timecount;
  ppc_tc.tc_counter_mask = 0xffffffff;
  ppc_tc.tc_frequency = frequency;
  ppc_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
  rtems_timecounter_install(&ppc_tc);

  return RTEMS_SUCCESSFUL;
}