64-bit multi-core MIPS exception and interrupt kernel code analysis (4)
1.3 initialization of other exception entries
The entry for other exceptions is initialized:
[ARCH/MIPS/kernel/traps. C]
Void _ init trap_init ()
{
......
/*
* Copy the generic exception handlers to their final destination.
* This will be overriden later as suitable for a participant
* Configuration.
*/
Set_handler (0x180, & except_vec3_generic, 0x80 );
.......
}
Set_handler:/* install CPU exception handler */
Void _ init set_handler (unsigned long offset, void * ADDR, unsigned Long SIZE)
{
Memcpy (void *) (ebase + offset), ADDR, size );
Local_flush_icache_range (ebase + offset, ebase + Offset + size );
}
The main operation is to copy the other exception handler function effect_vec3_generic to the corresponding entrance, which is generally ebase + 0x180. The main difference lies in the ebase value. In this case, ckseg0 + read_c0_ebase () is used in the cavium, and ckseg0 = 0 xFFFF ffff8000 0180 is used in loongson2:
Void _ init trap_init ()
{
......
If (cpu_has_veic | cpu_has_vint ){
Unsigned long size = 0x200 + vectorspacing * 64;
Ebase = (unsigned long)
_ Alloc_bootmem (size, 1 <FLS (size), 0 );
} Else {
Ebase = ckseg0;
If (cpu_has_mips_r2)
Ebase + = (read_c0_ebase () & 0x3ffff000 );
}
......
}
The other exception handler function effect_vec3_generic is defined in:
[ARCH/MIPS/kernel/genex. S]
/*
* General Exception vector for all other CPUs.
*
* Be careful when changing this, it has to be at most 128 bytes
* To fit into space reserved for the exception handler.
*/
Nested (effect_vec3_generic, 0, SP)
. Set push
. Set noat
# If r5432_cp0_interrupt_war
Mfc0 K0, cp0_index
# Endif
Mfc0 K1, cp0_cause
AndI K1, K1, 0x7c # k1 = exccode * 4, 32bit
# Ifdef config_64bit
Dsll K1, K1, 1 # k1 = exccode * 8, 64bit pointer is 8 bytes
# Endif
Ptr_l K0, exception_handlers (K1)
JR K0
. Set pop
End (effect_vec3_generic)
The code is short. Its function is to take the exccode value of cp0_cause and jump to exception_handlers [exccode. The exception_handler is actually a table, and each item is a pointer to the specific exception handling function. The exccode is cp0_cause [], and the cp0_cause & 0x7c is exccode * 4. In 64-Bit mode, the pointer length is 8 bytes, so it must be shifted to the left to get exccode * 8.
This exception_handlers is defined in:
[ARCH/MIPS/kernel/traps]
Unsigned long exception_handlers [32];
Enter the following in trap_init:
/*
* Setup default Vectors
*/
For (I = 0; I <= 31; I ++)
Set_effect_vector (I, handle_reserved );
......
Set_effect_vector (0, rollback? Rollback_handle_int: handle_int );
Set_effect_vector (1, handle_tlbm );
Set_effect_vector (2, handle_tlbl );
Set_effect_vector (3, handle_tlbs );
Set_effect_vector (4, handle_adel );
Set_effect_vector (5, handle_ades );
Set_effect_vector (6, handle_ibe );
Set_effect_vector (7, handle_dbe );
Set_effect_vector (8, handle_sys );
Set_effect_vector (9, handle_bp );
Set_effect_vector (10, rdhwr_noopt? Handle_ri:
(Cpu_has_vtag_icache?
Handle_ri_rdhwr_vivt: handle_ri_rdhwr ));
Set_effect_vector (11, handle_cpu );
Set_effect_vector (12, handle_ov );
Set_effect_vector (13, handle_tr );
......
This set_effect_vector () is defined in the same file:
Void _ init * set_effect_vector (int n, void * ADDR)
{
Unsigned long handler = (unsigned long) ADDR;
Unsigned long old_handler = exception_handlers [N];
Exception_handlers [N] = handler;
If (n = 0 & cpu_has_divec) {// when processing the extended interrupt vector, an optional feature is included in both mips32 and 64 R2, And neither loongson2 nor cavium is implemented, so we don't care
Unsigned long jump_mask = ~ (1 <28)-1 );
U32 * Buf = (u32 *) (ebase + 0x200 );
Unsigned int K0 = 26;
If (handler & jump_mask) = (ebase + 0x200) & jump_mask )){
Uasm_ I _j (& Buf, Handler &~ Jump_mask );
Uasm_ I _nop (& BUF );
} Else {
Uasm_ I _la (& Buf, K0, Handler );
Uasm_ I _jr (& Buf, k0 );
Uasm_ I _nop (& BUF );
}
Local_flush_icache_range (ebase + 0x200, (unsigned long) BUF );
}
Return (void *) old_handler;
}
The main operation is to assign the specific exception handler address to the element N of exception_handlers.
As you can see, the exccode used for indexing is related to the specific exception handler. What is the meaning of the exccode value specified by MIPS:
0 int interrupt
1 mod TLB modification exception
2 tlbl TLB read exception
3 tlbs TLB write exception
4 Adel read address Error
5 ades write address Error
6. An IBE bus error occurs)
7 DBE Bus Error (read/write data)
8. sys System Call exception
......
The preceding handle_int, handle_sys, handle_adel, handle_ades, handle_ibe, handle_dbe... is generated by the following macro:
[ARCH/MIPS/kernel/genex. S]
Build_handler Adel Ade silent/* #4 */
Build_handler ades Ade silent/* #5 */
Build_handler IBE be CLI silent/* #6 */
Build_handler DBE be CLI silent/* #7 */
Build_handler bp sti silent/* #9 */
Build_handler Ri STI silent/* #10 */
Build_handler cpu sti silent/* #11 */
Build_handler ov STI silent/* #12 */
Build_handler tr STI silent/* #13 */
Build_handler FPE silent/* #15 */
Build_handler mdmx STI silent/* #22 */
# Ifdef config_hardware_watchpoints
/*
* For watch, interrupts will be enabled after the watch
* Registers are read.
*/
Build_handler watch CLI silent/* #23 */
# Else
Build_handler watch STI verbose/* #23 */
# Endif
Build_handler mcheck CLI verbose/* #24 */
Build_handler Mt STI silent/* #25 */
Build_handler dsp sti silent/* #26 */
Build_handler reserved STI verbose/* Others */
Build_handler is defined:
. Macro build_handler exception handler clear verbose
_ Build_handler \ exception \ Handler \ clear \ verbose _ int
. Endm
. Macro _ build_handler exception handler clear verbose ext
. Align 5
Nested (handle _ \ exception, pt_size, SP)
. Set noat
Save_all
Fexport (handle _ \ exception \ ext)
_ Build_clear _ \ clear
. Set
_ Build _ \ verbose \ exception
Move A0, SP
Ptr_la Ra, ret_from_exception
J do _ \ Handler
End (handle _ \ exception)
. Endm