boot源代码全分析系列(基于PowerPC)(2)

    下面为初始化CPU的代码,实现的功能依次为屏蔽watchdog、初始化中断控制寄存器、清空Cache、关闭MMU等。

    .globl  init_e300_core   init_e300_core: /* time t 10 */       /* Initialize machine status; enable machine check interrupt */          li  r3, MSR_KERNEL      /*设置MSR,允许数据\指令复制以及Machine check*/       rlwimi  r3, r5, 0, 25, 25   /* preserve IP bit set by HRCW */   #ifdef DEBUG        rlwimi  r3, r5, 0, 21, 22   /* debugger might set SE & BE bits */   #endif        SYNC                        /* Some chip revs need this... */       mtmsr   r3       SYNC       mtspr   SRR1, r3            /* Make SRR1 match MSR 中断相关*/          lis r3, CFG_IMMR@h   #if defined(CONFIG_WATCHDOG)        /* Initialise the Wathcdog values and reset it (if req) */       lis r4, CFG_WATCHDOG_VALUE       ori r4, r4, (SWCRR_SWEN | SWCRR_SWRI | SWCRR_SWPR)       stw r4, SWCRR(r3)          /* and reset it */          li  r4, 0x556C       sth r4, SWSRR@l(r3)       li  r4, -0x55C7       sth r4, SWSRR@l(r3)   #else        /* 关闭Wathcdog  */       lwz r4, SWCRR(r3)       /* Check to see if its enabled for disabling         once disabled by SW you can't re-enable */       andi. r4, r4, 0x4       beq 1f       xor r4, r4, r4       stw r4, SWCRR(r3)   1:   #endif /* CONFIG_WATCHDOG */           /* Initialize the Hardware Implementation-dependent Registers */       /* HID0 also contains cache control         */       /*------------------------------------------------------*/          lis r3, CFG_HID0_INIT@h       ori r3, r3, CFG_HID0_INIT@l       SYNC       mtspr   HID0, r3          lis r3, CFG_HID0_FINAL@h       ori r3, r3, CFG_HID0_FINAL@l       SYNC       mtspr   HID0, r3          lis r3, CFG_HID2@h       ori r3, r3, CFG_HID2@l       SYNC       mtspr   HID2, r3          /* 关闭MMU功能,先清空所有BAT (块地址转换)*/          xor r0, r0, r0       mtspr   DBAT0U, r0       mtspr   DBAT0L, r0       mtspr   DBAT1U, r0       mtspr   DBAT1L, r0       mtspr   DBAT2U, r0       mtspr   DBAT2L, r0       mtspr   DBAT3U, r0       mtspr   DBAT3L, r0       mtspr   IBAT0U, r0       mtspr   IBAT0L, r0       mtspr   IBAT1U, r0       mtspr   IBAT1L, r0       mtspr   IBAT2U, r0       mtspr   IBAT2L, r0       mtspr   IBAT3U, r0       mtspr   IBAT3L, r0       SYNC          /* 禁用tlb(快表) */          li  r3, 32       mtctr   r3       li  r3, 0   1:  tlbie   r3       addi    r3, r3, 0x1000       bdnz    1b       SYNC          /* Done! */       Blr  

    这里需要注意的是,当程序在Flash中运行时,执行程序跳转时使用了跳转指令,但是不是使用绝对地址的跳转(即直接对PC操作)。因为若使用绝对地址,那么程序的取址就是相对于当前PC位置向前或向后的一段空间,而不会跳进SDRAM中。

4、初始化内存控制器

    PowerPC处理器初识化内存控制器就是通过操作BAT以及TLB来实现的,将IBAT0~7以及DBAT0~7初始化,并禁用TLB,代码如下:

/* setup_bats - set them up to some initial state */       .globl  setup_bats   setup_bats:       addis   r0, r0, 0x0000          /* IBAT 0 */       addis   r4, r0, CFG_IBAT0L@h       ori r4, r4, CFG_IBAT0L@l       addis   r3, r0, CFG_IBAT0U@h       ori r3, r3, CFG_IBAT0U@l       mtspr   IBAT0L, r4       mtspr   IBAT0U, r3       isync          /* DBAT 0 */       addis   r4, r0, CFG_DBAT0L@h       ori r4, r4, CFG_DBAT0L@l       addis   r3, r0, CFG_DBAT0U@h       ori r3, r3, CFG_DBAT0U@l       mtspr   DBAT0L, r4       mtspr   DBAT0U, r3       isync      #ifdef CONFIG_HIGH_BATS        /* IBAT 4 */       addis   r4, r0, CFG_IBAT4L@h       ori     r4, r4, CFG_IBAT4L@l       addis   r3, r0, CFG_IBAT4U@h       ori     r3, r3, CFG_IBAT4U@l       mtspr   IBAT4L, r4       mtspr   IBAT4U, r3       isync          /* DBAT 4 */       addis   r4, r0, CFG_DBAT4L@h       ori     r4, r4, CFG_DBAT4L@l       addis   r3, r0, CFG_DBAT4U@h       ori     r3, r3, CFG_DBAT4U@l       mtspr   DBAT4L, r4       mtspr   DBAT4U, r3       isync      #endif           /* Invalidate TLBs.       * -> for (val = 0; val < 0x20000; val+=0x1000)       * ->   tlbie(val);       */       lis r3, 0       lis r5, 2      1:       tlbie   r3       addi    r3, r3, 0x1000       cmp 0, 0, r3, r5       blt 1b          blr  

上面只贴出了高低位各一个BAT的操作代码,其他的类似。

5、复制程序到RAM

    PowerPC中此段程序并不返回,在将程序代码全部复制到ROM中后,将会直接继续在RAM中运行:

/*完成了代码复制,不返回,直接调用in_ram执行*/       addi    r0, r10, in_ram - _start + EXC_OFF_SYS_RESET       mtlr    r0       blr   .globl  relocate_code   relocate_code:       mr  r1,  r3     /* 创建一个新的栈指针 */       mr  r9,  r4     /* 备份 */       mr  r10, r5               mr  r3,  r5             /* r3:拷贝的终点 */       lis r4, CFG_MONITOR_BASE@h      /* r4:拷贝的起点 */       ori r4, r4, CFG_MONITOR_BASE@l       lwz r5, GOT(__init_end)       sub r5, r5, r4                      /* r5:拷贝的长度 */       li  r6, CFG_CACHELINE_SIZE      /* Cache Line Size */      /* New GOT-PTR = (old GOT-PTR - CFG_MONITOR_BASE) + Destination Address */       sub r15, r10, r4          /* First our own GOT */       add r14, r14, r15       /* then the one used by the C code */       add r30, r30, r15          /* Now relocate code */       cmplw   cr1,r3,r4       addi    r0,r5,3       srwi.   r0,r0,2       beq cr1,4f      /* In place copy is not necessary */       beq 7f      /* Protect against 0 count    */       mtctr   r0       bge cr1,2f       la  r8,-4(r4)       la  r7,-4(r3)          /* copy */   1:  lwzu    r0,4(r8)       stwu    r0,4(r7)       bdnz    1b          addi    r0,r5,3       srwi.   r0,r0,2       mtctr   r0       la  r8,-4(r4)       la  r7,-4(r3)          /* and compare */   20: lwzu    r20,4(r8)       lwzu    r21,4(r7)       xor. r22, r20, r21       bne  30f       bdnz    20b       b 4f          /* compare failed */   30: li r3, 0       blr      2:  slwi    r0,r0,2 /* re copy in reverse order ... y do we needed it? */       add r8,r4,r0       add r7,r3,r0   3:  lwzu    r0,-4(r8)       stwu    r0,-4(r7)       bdnz    3b      /*   * Now flush the cache: note that we must start from a cache aligned   * address. Otherwise we might miss one cache line.   */   4:  cmpwi   r6,0       add r5,r3,r5       beq 7f      /* Always flush prefetch queue in any case */       subi    r0,r6,1       andc    r3,r3,r0       mr  r4,r3   5:  dcbst   0,r4       add r4,r4,r6       cmplw   r4,r5       blt 5b       sync            /* Wait for all dcbst to complete on bus */       mr  r4,r3   6:  icbi    0,r4       add r4,r4,r6       cmplw   r4,r5       blt 6b   7:  sync            /* Wait for all icbi to complete on bus */       isync  

6、初始化堆栈

    对于mpc83xx系列,初始化堆栈代码如下:

/* set up the stack pointer in our newly created cache-ram (r1) */   lis r1, (CFG_INIT_RAM_ADDR + CFG_GBL_DATA_OFFSET)@h   ori r1, r1, (CFG_INIT_RAM_ADDR + CFG_GBL_DATA_OFFSET)@l      li  r0, 0       /* Make room for stack frame header and */   stwu    r0, -4(r1)  /* clear final stack frame so that  */   stwu    r0, -4(r1)  /* stack backtraces terminate cleanly   */  

7、跳转到Stage2入口处

    这也是Stage1的最后一步,程序在执行到这一步后,基本的硬件初始化工作也就完成了,下面是跳转的代码:

GET_GOT         /* initialize GOT access    */   /* r3: IMMR */   lis r3, CFG_IMMR@h   /* run low-level CPU init code (in Flash)*/   bl  cpu_init_f      /* r3: BOOTFLAG */   mr  r3, r21   /* run 1st part of board init code (in Flash)*/   bl  board_init_f  

其中board_init_f就是Stage2的函数入口。

    由上可以看出start.S的流程为:异常向量——上电复位后进入复位异常向量——跳到启动代码处——设置处理器进入管理模式——关闭看门狗——关闭中断——设置时钟分频——关闭MMU和CACHE——进入lowlever_init.S——检查当前代码所处的位置,如果在FLASH中就将代码搬移到RAM中。至此,Stage1分析到此结束。

    跳转到board_init_f后,程序开始执行Stage2阶段,代码多为C。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wwddwg.html