arch/arm/kernel/setup.c
struct stack {
u32 irq[3];
u32 abt[3];
u32 und[3];
} ____cacheline_aligned;
/*
* cpu_init - initialise one CPU.
*
* cpu_init sets up the per-CPU stacks.
*/
arm的R13是bank register,arm的七种处理器模式有各自的R13(user模式和system模式共用一个,总共六个不同的R13),也就是arm汇编默认的 SP(堆栈指针),就是说一旦产生了模式切换(IRQ,FIQ,异常等), 接着的代码就使用模式对应的SP.cpu_init就是对用到的IRQ, ABT, UND模式的SP都作了初始化
void cpu_init(void) //设置cpu堆栈
{
unsigned int cpu = smp_processor_id(); //获取cpu的id
struct stack *stk = &stacks[cpu];
if (cpu >= NR_CPUS) { //对于ARM NR_CPUS为1
printk(KERN_CRIT "CPU%u: bad primary CPU number\n", cpu);
BUG();
}
/*
* Define the placement constraint for the inline asm directive below.
* In Thumb-2, msr with an immediate value is not allowed.
*/
#ifdef CONFIG_THUMB2_KERNEL
#define PLC "r"
#else
#define PLC "I"
#endif
/*
* setup stacks for re-entrant exception handlers
*/
__asm__ (
"msr cpsr_c, %1\n\t" //切换到IRQ_MODE
"add r14, %0, %2\n\t"
"mov sp, r14\n\t" //设置r13_irq,此时sp是r13_irq
"msr cpsr_c, %3\n\t" //切换到ABT_MODE
"add r14, %0, %4\n\t"
"mov sp, r14\n\t" //设置r13_abt,此时sp是r13_abt
"msr cpsr_c, %5\n\t" //切换到UND_MODE
"add r14, %0, %6\n\t"
"mov sp, r14\n\t" //设置r13_und,此时sp是r13_und
"msr cpsr_c, %7" //切换回SVC_MODE
:
: "r" (stk),
PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
"I" (offsetof(struct stack, irq[0])),
PLC (PSR_F_BIT | PSR_I_BIT | ABT_MODE),
"I" (offsetof(struct stack, abt[0])),
PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
"I" (offsetof(struct stack, und[0])),
PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
: "r14");
}
可以看到,IRQ, ABT, UND模式的堆栈大小都只有3个int,
你可能会问,进入这三个模式后, 怎么保存大量的寄存器?
呵呵,进入这三种模式后,linux会把模式切换到SVC_MODE,使用的是SVC_MODE的堆栈.我们看一下在arch/arm/kernel/entry-armv.S中的汇编代码
1040 /*
1041 * Vector stubs.
1042 *
1043 * This code is copied to 0xffff0200 so we can use branches in the
1044 * vectors, rather than ldr's. Note that this code must not
1045 * exceed 0x300 bytes.
1046 *
1047 * Common stub entry macro:
1048 * Enter in IRQ mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
1049 *
1050 * SP points to a minimal amount of processor-private memory, the address
1051 * of which is copied into r0 for the mode specific abort handler.
1052 */
1053 .macro vector_stub, name, mode, correction=0
1054 .align 5
1055
1056 vector_\name:
1057 .if \correction
1058 sub lr, lr, #\correction
1059 .endif
1060
1061 @
1062 @ Save r0, lr_ (parent PC) and spsr_
1063 @ (parent CPSR)
1064 @
1065 stmia sp, {r0, lr} @ save r0, lr //R13_保存两个int
1066 mrs lr, spsr
1067 str lr, [sp, #8] @ save spsr //R13_再保存一个int
1068
1069 @
1070 @ Prepare for SVC32 mode. IRQs remain disabled.
1071 @
1072 mrs r0, cpsr
1073 eor r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE) //切换到SVC,之后的堆栈操作都用R13_svc,sp都是R13_svc的值
1074 msr spsr_cxsf, r0
1075
1076 @
1077 @ the branch table must immediately follow this code
1078 @
1079 and lr, lr, #0x0f
1080 THUMB( adr r0, 1f )
1081 THUMB( ldr lr, [r0, lr, lsl #2] )
1082 mov r0, sp
1083 ARM( ldr lr, [pc, lr, lsl #2] )
1084 movs pc, lr @ branch to handler in SVC mode
1085 ENDPROC(vector_\name)
/*
* PSR bits
*/
#define USR26_MODE 0x00000000
#define FIQ26_MODE 0x00000001
#define IRQ26_MODE 0x00000002
#define SVC26_MODE 0x00000003
#define USR_MODE 0x00000010
#define FIQ_MODE 0x00000011
#define IRQ_MODE 0x00000012
#define SVC_MODE 0x00000013
#define ABT_MODE 0x00000017
#define UND_MODE 0x0000001b
#define SYSTEM_MODE 0x0000001f
#define MODE32_BIT 0x00000010
#define MODE_MASK 0x0000001f
#define PSR_T_BIT 0x00000020
#define PSR_F_BIT 0x00000040
#define PSR_I_BIT 0x00000080
#define PSR_A_BIT 0x00000100
#define PSR_E_BIT 0x00000200
#define PSR_J_BIT 0x01000000
#define PSR_Q_BIT 0x08000000
#define PSR_V_BIT 0x10000000
#define PSR_C_BIT 0x20000000
#define PSR_Z_BIT 0x40000000
#define PSR_N_BIT 0x80000000
阅读(1649) | 评论(0) | 转发(0) |