static void cache_manager_smp_functions( size_t set_size, cpu_set_t *cpu_set ) { rtems_cache_flush_multiple_data_lines_processor_set( &data_to_flush, sizeof(data_to_flush), set_size, cpu_set ); rtems_cache_invalidate_multiple_data_lines_processor_set( &data_to_flush, sizeof(data_to_flush), set_size, cpu_set ); rtems_cache_flush_entire_data_processor_set( set_size, cpu_set ); rtems_cache_invalidate_entire_instruction(); rtems_cache_invalidate_multiple_instruction_lines( &function_to_flush, 4 /* arbitrary size */ ); }
static int call_at_level(int start, int fl, int s, bool dirty) { if (fl == start) { /* * Some architectures like the SPARC have register windows. A side-effect * of this context switch is that we start with a fresh window set. On * architectures like ARM or PowerPC this context switch has no effect. */ _Context_Switch(&ctx, &ctx); } if (fl > 0) { if (always_true) { return call_at_level(start, fl - 1, s, dirty); } else { return prevent_opt_func(fl - 1, fl - 2); } } else { char *volatile space; rtems_counter_ticks a; rtems_counter_ticks b; if (dirty) { dirty_data_cache(main_data, data_size, cache_line_size, fl); rtems_cache_invalidate_entire_instruction(); } a = rtems_counter_read(); /* Ensure that we use an untouched stack area */ space = alloca(1024); (void) space; _Context_Switch(&ctx, &ctx); b = rtems_counter_read(); t[s] = rtems_counter_difference(b, a); return 0; } }
void _CPU_ISR_install_raw_handler( uint32_t vector, proc_ptr new_handler, proc_ptr *old_handler ) { uint32_t real_vector; CPU_Trap_table_entry *tbr; CPU_Trap_table_entry *slot; uint32_t u32_tbr; uint32_t u32_handler; /* * Get the "real" trap number for this vector ignoring the synchronous * versus asynchronous indicator included with our vector numbers. */ real_vector = SPARC_REAL_TRAP_NUMBER( vector ); /* * Get the current base address of the trap table and calculate a pointer * to the slot we are interested in. */ sparc_get_tbr( u32_tbr ); u32_tbr &= 0xfffff000; tbr = (CPU_Trap_table_entry *) u32_tbr; slot = &tbr[ real_vector ]; /* * Get the address of the old_handler from the trap table. * * NOTE: The old_handler returned will be bogus if it does not follow * the RTEMS model. */ #define HIGH_BITS_MASK 0xFFFFFC00 #define HIGH_BITS_SHIFT 10 #define LOW_BITS_MASK 0x000003FF if ( slot->mov_psr_l0 == _CPU_Trap_slot_template.mov_psr_l0 ) { u32_handler = (slot->sethi_of_handler_to_l4 << HIGH_BITS_SHIFT) | (slot->jmp_to_low_of_handler_plus_l4 & LOW_BITS_MASK); *old_handler = (proc_ptr) u32_handler; } else *old_handler = 0; /* * Copy the template to the slot and then fix it. */ *slot = _CPU_Trap_slot_template; u32_handler = (uint32_t) new_handler; slot->mov_vector_l3 |= vector; slot->sethi_of_handler_to_l4 |= (u32_handler & HIGH_BITS_MASK) >> HIGH_BITS_SHIFT; slot->jmp_to_low_of_handler_plus_l4 |= (u32_handler & LOW_BITS_MASK); /* * There is no instruction cache snooping, so we need to invalidate * the instruction cache to make sure that the processor sees the * changes to the trap table. This step is required on both single- * and multiprocessor systems. * * In a SMP configuration a change to the trap table might be * missed by other cores. If the system state is up, the other * cores can be notified using SMP messages that they need to * flush their icache. If the up state has not been reached * there is no need to notify other cores. They will do an * automatic flush of the icache just after entering the up * state, but before enabling interrupts. */ rtems_cache_invalidate_entire_instruction(); }
/* Verified this is working properly from sparc64_install_isr_entries */ void _CPU_ISR_install_raw_handler( uint32_t vector, proc_ptr new_handler, proc_ptr *old_handler ) { uint32_t real_vector; CPU_Trap_table_entry *tba; CPU_Trap_table_entry *slot; uint64_t u64_tba; uint64_t u64_handler; /* * Get the "real" trap number for this vector ignoring the synchronous * versus asynchronous indicator included with our vector numbers. */ real_vector = SPARC_REAL_TRAP_NUMBER( vector ); /* * Get the current base address of the trap table and calculate a pointer * to the slot we are interested in. */ sparc64_get_tba( u64_tba ); /* u32_tbr &= 0xfffff000; */ u64_tba &= 0xffffffffffff8000; /* keep only trap base address */ tba = (CPU_Trap_table_entry *) u64_tba; /* use array indexing to fill in lower bits -- require * CPU_Trap_table_entry to be full-sized. */ slot = &tba[ real_vector ]; /* * Get the address of the old_handler from the trap table. * * NOTE: The old_handler returned will be bogus if it does not follow * the RTEMS model. */ /* shift amount to shift of hi bits (31:10) */ #define HI_BITS_SHIFT 10 /* shift amount of hm bits (41:32) */ #define HM_BITS_SHIFT 32 /* shift amount of hh bits (63:42) */ #define HH_BITS_SHIFT 42 /* We're only interested in bits 0-9 of the immediate field*/ #define IMM_MASK 0x000003FF if ( slot->rdpr_tstate_g4 == _CPU_Trap_slot_template.rdpr_tstate_g4 ) { u64_handler = (((uint64_t)((slot->sethi_of_hh_handler_to_g2 << HI_BITS_SHIFT) | (slot->or_g2_hm_handler_to_g2 & IMM_MASK))) << HM_BITS_SHIFT) | ((slot->sethi_of_handler_to_g3 << HI_BITS_SHIFT) | (slot->jmp_to_low_of_handler_plus_g3 & IMM_MASK)); *old_handler = (proc_ptr) u64_handler; } else *old_handler = 0; /* * Copy the template to the slot and then fix it. */ *slot = _CPU_Trap_slot_template; u64_handler = (uint64_t) new_handler; /* mask for extracting %hh */ #define HH_BITS_MASK 0xFFFFFC0000000000 /* mask for extracting %hm */ #define HM_BITS_MASK 0x000003FF00000000 /* mask for extracting %hi */ #define HI_BITS_MASK 0x00000000FFFFFC00 /* mask for extracting %lo */ #define LO_BITS_MASK 0x00000000000003FF slot->mov_vector_g2 |= vector; slot->sethi_of_hh_handler_to_g2 |= (u64_handler & HH_BITS_MASK) >> HH_BITS_SHIFT; slot->or_g2_hm_handler_to_g2 |= (u64_handler & HM_BITS_MASK) >> HM_BITS_SHIFT; slot->sethi_of_handler_to_g3 |= (u64_handler & HI_BITS_MASK) >> HI_BITS_SHIFT; slot->jmp_to_low_of_handler_plus_g3 |= (u64_handler & LO_BITS_MASK); /* need to flush icache after this !!! */ /* need to flush icache in case old trap handler is in cache */ rtems_cache_invalidate_entire_instruction(); }
static void test_timing(void) { rtems_interrupt_lock lock; rtems_interrupt_lock_context lock_context; size_t data_size = sizeof(data); uint64_t d[3]; uint32_t cache_level; size_t cache_size; rtems_interrupt_lock_initialize(&lock, "test"); printf( "data cache line size %zi bytes\n" "data cache size %zi bytes\n", rtems_cache_get_data_line_size(), rtems_cache_get_data_cache_size(0) ); cache_level = 1; cache_size = rtems_cache_get_data_cache_size(cache_level); while (cache_size > 0) { printf( "data cache level %" PRIu32 " size %zi bytes\n", cache_level, cache_size ); ++cache_level; cache_size = rtems_cache_get_data_cache_size(cache_level); } rtems_interrupt_lock_acquire(&lock, &lock_context); d[0] = load(); d[1] = load(); rtems_cache_flush_entire_data(); d[2] = load(); rtems_interrupt_lock_release(&lock, &lock_context); printf( "load %zi bytes with flush entire data\n" " duration with normal cache %" PRIu64 " ns\n" " duration with warm cache %" PRIu64 " ns\n" " duration with flushed cache %" PRIu64 " ns\n", data_size, d[0], d[1], d[2] ); rtems_interrupt_lock_acquire(&lock, &lock_context); d[0] = load(); d[1] = load(); rtems_cache_flush_multiple_data_lines(&data[0], sizeof(data)); d[2] = load(); rtems_interrupt_lock_release(&lock, &lock_context); printf( "load %zi bytes with flush multiple data\n" " duration with normal cache %" PRIu64 " ns\n" " duration with warm cache %" PRIu64 " ns\n" " duration with flushed cache %" PRIu64 " ns\n", data_size, d[0], d[1], d[2] ); rtems_interrupt_lock_acquire(&lock, &lock_context); d[0] = load(); d[1] = load(); rtems_cache_invalidate_multiple_data_lines(&data[0], sizeof(data)); d[2] = load(); rtems_interrupt_lock_release(&lock, &lock_context); printf( "load %zi bytes with invalidate multiple data\n" " duration with normal cache %" PRIu64 " ns\n" " duration with warm cache %" PRIu64 " ns\n" " duration with invalidated cache %" PRIu64 " ns\n", data_size, d[0], d[1], d[2] ); rtems_interrupt_lock_acquire(&lock, &lock_context); d[0] = store(); d[1] = store(); rtems_cache_flush_entire_data(); d[2] = store(); rtems_interrupt_lock_release(&lock, &lock_context); printf( "store %zi bytes with flush entire data\n" " duration with normal cache %" PRIu64 " ns\n" " duration with warm cache %" PRIu64 " ns\n" " duration with flushed cache %" PRIu64 " ns\n", data_size, d[0], d[1], d[2] ); rtems_interrupt_lock_acquire(&lock, &lock_context); d[0] = store(); d[1] = store(); rtems_cache_flush_multiple_data_lines(&data[0], sizeof(data)); d[2] = store(); rtems_interrupt_lock_release(&lock, &lock_context); printf( "store %zi bytes with flush multiple data\n" " duration with normal cache %" PRIu64 " ns\n" " duration with warm cache %" PRIu64 " ns\n" " duration with flushed cache %" PRIu64 " ns\n", data_size, d[0], d[1], d[2] ); rtems_interrupt_lock_acquire(&lock, &lock_context); d[0] = store(); d[1] = store(); rtems_cache_invalidate_multiple_data_lines(&data[0], sizeof(data)); d[2] = store(); rtems_interrupt_lock_release(&lock, &lock_context); printf( "store %zi bytes with invalidate multiple data\n" " duration with normal cache %" PRIu64 " ns\n" " duration with warm cache %" PRIu64 " ns\n" " duration with invalidated cache %" PRIu64 " ns\n", data_size, d[0], d[1], d[2] ); printf( "instruction cache line size %zi bytes\n" "instruction cache size %zi bytes\n", rtems_cache_get_instruction_line_size(), rtems_cache_get_instruction_cache_size(0) ); cache_level = 1; cache_size = rtems_cache_get_instruction_cache_size(cache_level); while (cache_size > 0) { printf( "instruction cache level %" PRIu32 " size %zi bytes\n", cache_level, cache_size ); ++cache_level; cache_size = rtems_cache_get_instruction_cache_size(cache_level); } rtems_interrupt_lock_acquire(&lock, &lock_context); d[0] = do_some_work(); d[1] = do_some_work(); rtems_cache_invalidate_entire_instruction(); d[2] = do_some_work(); rtems_interrupt_lock_release(&lock, &lock_context); printf( "invalidate entire instruction\n" " duration with normal cache %" PRIu64 " ns\n" " duration with warm cache %" PRIu64 " ns\n" " duration with invalidated cache %" PRIu64 " ns\n", d[0], d[1], d[2] ); rtems_interrupt_lock_acquire(&lock, &lock_context); d[0] = do_some_work(); d[1] = do_some_work(); rtems_cache_invalidate_multiple_instruction_lines(do_some_work, 4096); d[2] = do_some_work(); rtems_interrupt_lock_release(&lock, &lock_context); printf( "invalidate multiple instruction\n" " duration with normal cache %" PRIu64 " ns\n" " duration with warm cache %" PRIu64 " ns\n" " duration with invalidated cache %" PRIu64 " ns\n", d[0], d[1], d[2] ); rtems_interrupt_lock_destroy(&lock); }
void _CPU_ISR_install_raw_handler( uint32_t vector, proc_ptr new_handler, proc_ptr *old_handler ) { uint32_t real_vector; CPU_Trap_table_entry *tbr; CPU_Trap_table_entry *slot; uint32_t u32_tbr; uint32_t u32_handler; /* * Get the "real" trap number for this vector ignoring the synchronous * versus asynchronous indicator included with our vector numbers. */ real_vector = SPARC_REAL_TRAP_NUMBER( vector ); /* * Get the current base address of the trap table and calculate a pointer * to the slot we are interested in. */ sparc_get_tbr( u32_tbr ); u32_tbr &= 0xfffff000; tbr = (CPU_Trap_table_entry *) u32_tbr; slot = &tbr[ real_vector ]; /* * Get the address of the old_handler from the trap table. * * NOTE: The old_handler returned will be bogus if it does not follow * the RTEMS model. */ #define HIGH_BITS_MASK 0xFFFFFC00 #define HIGH_BITS_SHIFT 10 #define LOW_BITS_MASK 0x000003FF if ( slot->mov_psr_l0 == _CPU_Trap_slot_template.mov_psr_l0 ) { u32_handler = (slot->sethi_of_handler_to_l4 << HIGH_BITS_SHIFT) | (slot->jmp_to_low_of_handler_plus_l4 & LOW_BITS_MASK); *old_handler = (proc_ptr) u32_handler; } else *old_handler = 0; /* * Copy the template to the slot and then fix it. */ *slot = _CPU_Trap_slot_template; u32_handler = (uint32_t) new_handler; slot->mov_vector_l3 |= vector; slot->sethi_of_handler_to_l4 |= (u32_handler & HIGH_BITS_MASK) >> HIGH_BITS_SHIFT; slot->jmp_to_low_of_handler_plus_l4 |= (u32_handler & LOW_BITS_MASK); /* need to flush icache after this !!! */ rtems_cache_invalidate_entire_instruction(); }