1. 准备:
1.1. 资料收集
去freescale的网站上下载下面的几个pdf文件:
名称 | 内容 |
EREFRM.pdf | A Programmer's Reference Manual for Freescale Embedded Processors |
E500CORERM.pdf | PowerPC™ e500 Core Family Reference Manual |
E500ABIUG.pdf | PowerPC™ e500 Application Binary Interface User's Guide |
MPC5554.pdf | MPC5554 Microcontroller Data Sheet |
MPC5553_MPC5554_RM.pdf | MPC5553/5554 Microcontroller Reference Manual |
1.2. Linux源代码下载:
2. CPU学习
2.1. 寄存器
E500内核寄存器分为用户模式(ULR)和特权模式(SLR):
它们的访问受MSR(Machine State Register)的PR位的控制,PR=0时可以访问SLR。而MSR只有处于特权模式下才能访问,因此只有通过中断、系统调用和异常才能实现用户态到特权态的切换。
MSR寄存器如下所示:
在linux-2.6.33\arch\powerpc\include\asm\reg_booke.h中可以看到,Linux如下定义MSR的各个位:
/* Machine State Register (MSR) Fields */
#define MSR_SF_LG 63 /* Enable 64 bit mode */
#define MSR_ISF_LG 61 /* Interrupt 64b mode valid on 630 */
#define MSR_HV_LG 60 /* Hypervisor state */
#define MSR_VEC_LG 25 /* Enable AltiVec */
#define MSR_VSX_LG 23 /* Enable VSX */
#define MSR_POW_LG 18 /* Enable Power Management */
#define MSR_WE_LG 18 /* Wait State Enable */
#define MSR_TGPR_LG 17 /* TLB Update registers in use */
#define MSR_CE_LG 17 /* Critical Interrupt Enable */
#define MSR_ILE_LG 16 /* Interrupt Little Endian */
#define MSR_EE_LG 15 /* External Interrupt Enable */
#define MSR_PR_LG 14 /* Problem State / Privilege Level */
#define MSR_FP_LG 13 /* Floating Point enable */
#define MSR_ME_LG 12 /* Machine Check Enable */
#define MSR_FE0_LG 11 /* Floating Exception mode 0 */
#define MSR_SE_LG 10 /* Single Step */
#define MSR_BE_LG 9 /* Branch Trace */
#define MSR_DE_LG 9 /* Debug Exception Enable */
#define MSR_FE1_LG 8 /* Floating Exception mode 1 */
#define MSR_IP_LG 6 /* Exception prefix 0x000/0xFFF */
#define MSR_IR_LG 5 /* Instruction Relocate */
#define MSR_DR_LG 4 /* Data Relocate */
#define MSR_PE_LG 3 /* Protection Enable */
#define MSR_PX_LG 2 /* Protection Exclusive Mode */
#define MSR_PMM_LG 2 /* Performance monitor */
#define MSR_RI_LG 1 /* Recoverable Exception */
#define MSR_LE_LG 0 /* Little Endian */
#define MSR_GS (1<<28) /* Guest state */
#define MSR_UCLE (1<<26) /* User-mode cache lock enable */
#define MSR_SPE (1<<25) /* Enable SPE */
#define MSR_DWE (1<<10) /* Debug Wait Enable */
#define MSR_UBLE (1<<10) /* BTB lock enable (e500) */
#define MSR_IS MSR_IR /* Instruction Space */
#define MSR_DS MSR_DR /* Data Space */
#define MSR_PMM (1<<2) /* Performance monitor mark bit */
#define MSR_CM (1<<31) /* Computation Mode (0=32-bit, 1=64-bit) */
#if defined(CONFIG_PPC_BOOK3E_64)
#define MSR_ MSR_ME | MSR_CE
#define MSR_KERNEL MSR_ | MSR_CM
#define MSR_USER32 MSR_ | MSR_PR | MSR_EE
#define MSR_USER64 MSR_USER32 | MSR_CM
#elif defined (CONFIG_40x)
#define MSR_KERNEL (MSR_ME|MSR_RI|MSR_IR|MSR_DR|MSR_CE)
#define MSR_USER (MSR_KERNEL|MSR_PR|MSR_EE)
#else
#define MSR_KERNEL (MSR_ME|MSR_RI|MSR_CE)
#define MSR_USER (MSR_KERNEL|MSR_PR|MSR_EE)
#endif
从上面红色内容可以看出,Linux内核态和用户态MSR的区别。
Linux进程启动函数(execve)中,需要从系统态到用户态转换这个转换函数在start_thread()中完成,如下:
void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp)
{
set_fs(USER_DS);
/*
* If we exec out of a kernel thread then thread.regs will not be
* set. Do it now.
*/
if (!current->thread.regs) {
struct pt_regs *regs = task_stack_page(current) + THREAD_SIZE;
current->thread.regs = regs - 1;
}
memset(regs->gpr, 0, sizeof(regs->gpr));
regs->ctr = 0;
regs->link = 0;
regs->xer = 0;
regs->ccr = 0;
regs->gpr[1] = sp;
/*
* We have just cleared all the nonvolatile GPRs, so make
* FULL_REGS(regs) return true. This is necessary to allow
* ptrace to examine the thread immediately after exec.
*/
regs->trap &= ~1UL;
regs->mq = 0;
regs->nip = start;
regs->msr = MSR_USER;
discard_lazy_cpu_state();
#ifdef CONFIG_VSX
current->thread.used_vsr = 0;
#endif memset(current->thread.fpr, 0, sizeof(current->thread.fpr));
current->thread.fpscr.val = 0;
#ifdef CONFIG_ALTIVEC
memset(current->thread.vr, 0, sizeof(current->thread.vr));
memset(¤t->thread.vscr, 0, sizeof(current->thread.vscr));
current->thread.vscr.u[3] = 0x00010000; /* Java mode disabled */
current->thread.vrsave = 0;
current->thread.used_vr = 0;
#endif /* CONFIG_ALTIVEC */
#ifdef CONFIG_SPE
memset(current->thread.evr, 0, sizeof(current->thread.evr));
current->thread.acc = 0;
current->thread.spefscr = 0;
current->thread.used_spe = 0;
#endif /* CONFIG_SPE */
}