zoukankan      html  css  js  c++  java
  • eboot中断学习(作者:wogoyixikexie@gliet)

    eboot中断学习(作者:wogoyixikexie@gliet)

    //-----------------------------------------------------------------------------------------------------------

    // 作者:wogoyixikexie@gliet

    //论坛账号:gooogleman (经常在CSDN出没)

    // 版权:桂林电子科技大学一系科协wogoyixikexie@gliet

    // 平台:wince5.0 2440 5.0 BSP

    // 发布日期:2009年6月19日

    // 最后修改:2009年6月20日

    // 注意事项:未经作者同意,不得在转载的时候擅自修改、删除文章的任何部分

    //-----------------------------------------------------------------------------------------------------------

    作者:wogoyixikexie@gliet(转载请注明)
     前几天这个帖子http://topic.csdn.net/u/20090605/12/abd72d4e-260c-4e72-966f-298ed343ed3c.html搞的一头雾水,现在看懂了一些,
    特写篇博客
      我一直使用的是ADS 的bootloader (STEPLDR+eboot整合在一起了),对PB下的bootloader不是很了解,现在有点时间,正好来看看。
      像所有bootloader一样,STEPLDR开始就是复位,PB下的bootloader有个特殊情况,就是没有完整的中断向量表,所以是不支持中断的,
      要稍作修改才行。我的ADS bootloader具有完整的中断向量以及相关栈的初始化,支持中断。
    STARTUPTEXT
        LEAF_ENTRY StartUp
       
        b ResetHandler 
        b .
        b .
        b .  
        b .  
        b .  
        b .   
        b .

    有此可以看出,STEPLDR只是对复位进行了处理。如果发生别的中断就会B . 死循环了。
      这里要提醒的是在eboot中发生的中断时跳到STEPLDR存放中断向量表的地方的,以前我居然认为是跳到eboot中断向量表的地方,真是雷死人了。在ARM结构中,一旦发生中断,PC就会指向0x00000000(bootloader中使用)或者0xffff0000(wince 下使用),所以eboot发生中断,很明显应该跳到STEPLDR的0x00000000,eboot一般已经开了MMU,那么发生中断应该是跳到0x00000000对应的虚拟地址就可以了。
      STEPLDR还没有开MMU的,其实STEPLDR就是被自动加载到2440 内部4K SRAM,并完成拷贝eboot到内存并跳转到eboot运行的功能。STEPLDR代码较简单,无非是实现一些复位,休眠唤醒,软复位等功能,在这里就不再赘述了。
      现在我就来看PB 的bootloader下的难点——eboot中是如何初始化内存映射表的?
      在eboot的startup.s中有
    ;   Define RAM space for the Page Tables:
    ;
    PHYBASE         EQU     0x30000000      ; physical start
    PTs             EQU     0x30010000      ; 1st level page table address (PHYBASE + 0x10000)
                                            ; save room for interrupt vectors.前面用来保存中断向量

    ;-------------------------------------------------------------------------------
    下面是内存映射表初始化的地方
    下面的注释,很大部分是参考我一个师兄的杰作,在这里贴出他文章地址
    http://blog.chinaunix.net/u1/38994/showart_1881778.html
    和大家分享一下。
    还有我去年的老帖子地址http://topic.csdn.net/u/20081231/10/BBDE79C2-2884-48E3-9718-90D7FCC1AFA8.html


    ; Compute physical address of the OEMAddressTable.
    20      add     r11, pc, #g_oalAddressTable - (. + 8)
            ldr     r10, =PTs                ; (r10) = 1st level page table
    ; r10=0x30010000


            ; Setup 1st level page table (using section descriptor)    
            ; Fill in first level page table entries to create "un-mapped" regions
            ; from the contents of the MemoryMap array.
            ;
            ;   (r10) = 1st level page table
            ;   (r11) = ptr to MemoryMap array
    ;0x2000=0x80000000 >> 18 具体原因参考MMU设置 说明这是从cached 地址0x80000000开始的
            add     r10, r10, #0x2000       ; (r10) = ptr to 1st PTE for "unmapped space"
            mov     r0, #0x0E               ; (r0) = PTE for 0: 1MB cachable bufferable
            orr     r0, r0, #0x400          ; set kernel r/w permission
    25      mov     r1, r11                 ; (r1) = ptr to MemoryMap array

           
    30      ldr     r2, [r1], #4            ; (r2) = virtual address to map Bank at
            ldr     r3, [r1], #4            ; (r3) = physical address to map from
            ldr     r4, [r1], #4            ; (r4) = num MB to map

            cmp     r4, #0                  ; End of table?
            beq     %f40

            ldr     r5, =0x1FF00000
            and     r2, r2, r5              ; VA needs 512MB, 1MB aligned.               

            ldr     r5, =0xFFF00000
            and     r3, r3, r5              ; PA needs 4GB, 1MB aligned.

            add     r2, r10, r2, LSR #18    ;这是MMU设置决定的,再左移回去
            add     r0, r0, r3              ; (r0) = PTE for next physical page

    35      str     r0, [r2], #4            ;物理地址存到相应的虚拟地址
            add     r0, r0, #0x00100000     ; (r0) = PTE for next physical page 1M
            sub     r4, r4, #1              ; Decrement number of MB left
            cmp     r4, #0
            bne     %b35                    ; Map next MB

            bic     r0, r0, #0xF0000000     ; Clear Section Base Address Field
            bic     r0, r0, #0x0FF00000     ; Clear Section Base Address Field
            b       %b30                    ; Get next element

    //创建对应的0xa0000000开始的uncached映射MMU表  
    //比较C高速缓存是否仍然置位,如果仍然置位了,那么说明还没有执行uncached创建,
    //如果C位已经清0,那么说明,uncached循环也执行完毕了,所以跳回到25标号继续创建   
    40      tst     r0, #8
            bic     r0, r0, #0x0C           ; clear cachable & bufferable bits in PTE //清除B写缓冲和C高速缓存
    //r10现在对应0x80000000虚拟地址的PTR起始地址,hex(0x20000000>>18)为0x800,
    //所以r10 = r10 + 0x800;之后r10指向了0xa0000000虚拟地址对应的PTR起始地址     
            add     r10, r10, #0x0800       ; (r10) = ptr to 1st PTE for "unmapped uncached space"
            bne     %b25                    ; go setup PTEs for uncached space
            // 下面这句没有看出有什么作用哦。
            sub     r10, r10, #0x3000       ; (r10) = restore address of 1st level page table

            ; Setup mmu to map (VA == 0) to (PA == 0x30000000).
            ldr     r0, =PTs                ; PTE entry for VA = 0  重新加载PTs ,这里没有加上偏移,相当于偏移了0
            //所以,这个虚拟地址就是0了,从整体来看,就是物理地址 0x30000000映射到了0x00000000了,汇编真的太难看懂了
            ldr     r1, =0x3000040E         ; uncache/unbuffer/rw, PA base == 0x30000000
            str     r1, [r0]

            ; uncached area.加上了0x0800=0x2000000>>18相当于是uncached地址了,不过中断向量的地址是cached的
            add     r0, r0, #0x0800         ; PTE entry for VA = 0x0200.0000 , uncached    
            ldr     r1, =0x30000402         ; uncache/unbuffer/rw, base == 0x30000000
            str     r1, [r0]
           
            ; Comment:
            ; The following loop is to direct map RAM VA == PA. i.e.
            ;   VA == 0x30XXXXXX => PA == 0x30XXXXXX for S3C2400
            ; Fill in 8 entries to have a direct mapping for DRAM
            ;
            ldr     r10, =PTs               ; restore address of 1st level page table
            ldr     r0,  =PHYBASE           // 内存起始物理地址0x30000000
    //0x3000 / 4=0x30000000>>18 有时候不知道为什么三星会这么变态,明明是这样了,还不注释好点,或者直接写0x30000000>>18
    //让人看了相当郁闷,不知所云。0x30000000映射到0x30000000,似乎没有这个必要。
            add     r10, r10, #(0x3000 / 4) ; (r10) = ptr to 1st PTE for 0x30000000

            add     r0, r0, #0x1E           ; 1MB cachable bufferable
            orr     r0, r0, #0x400          ; set kernel r/w permission
            mov     r1, #0
            mov     r3, #64
    45      mov     r2, r1                  ; (r2) = virtual address to map Bank at
            cmp     r2, #0x20000000:SHR:BANK_SHIFT   //512 M 比较
            add     r2, r10, r2, LSL #BANK_SHIFT-18
            strlo   r0, [r2]
            add     r0, r0, #0x00100000     ; (r0) = PTE for next physical page
            subs    r3, r3, #1
            add     r1, r1, #1
            bgt     %b45

            ldr     r10, =PTs               ; (r10) = restore address of 1st level page table
           
    ; The page tables and exception vectors are setup.
            ; Initialize the MMU and turn it on.
            mov     r1, #1
            mcr     p15, 0, r1, c3, c0, 0   ; setup access to domain 0
            mcr     p15, 0, r10, c2, c0, 0  // C2 -------ldr     r10, =PTs
    //The CP15:c2 register holds the translation table base address (TTB)—
    //an address pointing to the location of the master L1 table in virtual memory(指出L1页表在虚拟内存中的地址).
            mcr     p15, 0, r0, c8, c7, 0   ; flush I+D TLBs
            mov     r1, #0x0071             ; Enable: MMU
            orr     r1, r1, #0x0004         ; Enable the cache

            ldr     r0, =VirtualStart

            cmp     r0, #0                  ; make sure no stall on "mov pc,r0" below
            mcr     p15, 0, r1, c1, c0, 0
            mov     pc, r0                  ;  & jump to new virtual address
            nop

            ; MMU & caches now enabled.
            ;   (r10) = physcial address of 1st level page table
            ;

    VirtualStart

            mov     sp, #0x8C000000
            add     sp, sp, #0x30000        ; arbitrary initial super-page stack pointer
            b       main                    哈哈,跳到main函数了。
           
    现在看来,关于上次eboot中断向量表的讨论,终于有结果了。
    因为上面有虚拟地址0 映射到物理地址0x30000000,   虚拟地址0x30000000 映射到物理地址0x30000000
    虚拟地址0x8c000000 映射到物理地址0x30000000 

    在eboot中加入中断的堆栈初始化后,用下面几个地址就可以了。
    mrs  r0, cpsr
      bic  r0, r0, #MODEMASK
      orr  r1, r0, #IRQMODE|NOINT
      msr  cpsr_cxsf, r1  ; IRQMode
      ldr  sp, = IRQStack
      
      bic  r0, r0, #MODEMASK|NOINT
      orr  r1, r0, #SVCMODE
      msr  cpsr_cxsf, r1  ; SVCMode.
      ldr  sp, = SVCStack
      
      
    #define pISR (*(unsigned *)(0x30000000+0x18))
    0x30000000换成过0x00000000,0x8C000000,都可以正常工作
    pISR =(unsigned)(0xEA000000)+(((unsigned)IsrHandler - (0x8C000000 + 0x18 + 0x8) )>>2);   
    上面这句相当于在C语言里面初始化了中断向量表
    B IRQHandler    
    计算原理:B 偏移地址
    偏移地址=IsrHandler 所在地址-(boot.bib的起始地址+0x18(这个大家都知道了吧)+0x8(这个是ARM流水线,具体Google了))》2
    为什么要友谊两位?这也是B指令的原因。Google一下就明白了。
    1、 B 指令
                B 指令的格式为:
                B{条件} 目标地址
                B 指令是最简单的跳转指令。一旦遇到一个 B 指令,ARM
    处理器将立即跳转到给定的目标地址,从那里继续执行。注意存储在跳转指令中的实际值是相对当前PC 值的一个偏移量,
    而不是一个绝对地址,它的值由汇编器来计算(参考寻址方式中的相对寻址)。
    它是 24 位有符号数,左移两位后有符号扩展为 32 位,表示的有效偏移为 26 位(前后32MB 的地址空间)。

    现在看来这个和ADS是一致的。
    在ADS中,为了支持JLINK等调试
    加入了如下映射。
    MMU_SetMTT([0x00000000,0x0100000, 0x30000000,RW_CB);
    其中0x30000000是ADS的RO base设置地址,是物理地址。
    0x00000000是虚拟地址,在JLINK等调试的时候,中断向量表其实已经搬运到内存的0x30000000开始地方。
    而2440 此时MMU已经打开,不能识别0x30000000物理地址,一旦中断,就会跳转到0x00000000这个虚拟地址去执行相应的中断handler
    (*^__^*) 嘻嘻……,我是这么理解的,不知道对不对,这个问题已经困扰我好久了,以前似懂非懂,现在我觉得这应该是正确的。
    在wince下,中断时候就是跳转到0xffff0000地方,我看过下面的代码,确实如此。所以ARM相关文档中0xffff0000以及0x00000000这两个
    存放中断向量表的地方应该指的是虚拟地址。
     那么,在PB下的2440 eboot+STEPLDR中也应该是一样的。
     经过上面的层层映射,0x00000000、0x8C000000以及0x30000000这三个虚拟地址都同时指向物理地址0x30000000,所以这三个虚拟地址
    可以互相代替,也是一样的效果,这恰恰证明了MMU的高明——多个虚拟地址可以对应一个物理地址!
     不过,在这里我还是有两个疑问。
     一、STEPLDR的代码是在2440 的内部4K SRAM 运行的,那中断向量表应该还是在0x0000 0000处才对,难道这时候2440 就把0x0000 0000
     看成是虚拟地址了?0x00000000、0x8C000000以及0x30000000这三个虚拟地址都同时指向物理地址0x30000000,但是0x30000000好像和
     中断向量表没有什么关系啊,难道这个内部SRAM有自动拷贝到内存初始地址的功能?在三星手册没有啊?哈哈,真是不知道怎么弄的了。
     希望高人再帮我解决疑惑了。
     二、ADS 的MMU初始化和eboot中的有点小小的差异。
     在ADS中
     void MMU_SetMTT(int vaddrStart,int vaddrEnd,int paddrStart,int attr)
    {
        U32 *pTT;
        int i,nSec;
        pTT=(U32 *)_MMUTT_STARTADDRESS+(vaddrStart>>20);
        nSec=(vaddrEnd>>20)-(vaddrStart>>20);
        for(i=0;i <=nSec;i++)*pTT++=attr |(((paddrStart>>20)+i) < <20);
    }

    这里加的偏移地址是(vaddrStart>>20)虚拟地址右移了20位,但是eboot中却是右移了18位,其余的基本一致,请问这是怎么回事。
    我看了一下ARM 结构体系相关的英文文档,发现右移20位才合适啊。eboot中咋了,但是确实能正常使用。这点也请高人指示,我想
    掌握了ARM中断向量的运用,那我觉得对ARM的认识才算入门了。
     哈哈,今天本来公司安排弄摄像头的,可是我一直想着这件事情,就看了一下,结果看了好久才了解一点。总算有点收获了。

    ===========================================================================

    嘿嘿,刚才http://www.armce.cn/bbs的老大斑竹帮我解决了
    问题二。

    这是指针和非指针的问题。

    和下面的效果一样。

    ETDrawer回复我:
    pTT=(U32 *)_MMUTT_STARTADDRESS+(vaddrStart>>20); 我感觉可能是这个原因

    DWORD A = 0x12345678;
    DWORD dwAddr = A + 8;

    PDWORD B = 0x12345678;
    PDWORD pdwAddr = B + 2;

    dwAddr == (DWORD)pdwAddr?

      

    ——————————问题一的答案。

    这里要提醒的是在eboot中发生的中断时跳到STEPLDR存放中断向量表的地方的,以前我居然认为是跳到eboot中断向量表的地方,真是雷死人了。
    ——哈哈,关于问题一,源于我对上面的错误理解。现在我纠正!
    eboot发生中断,就会跳转到虚拟地址0,这个虚拟地址0对应的物理地址就是存放中断向量的正确地方。

    所以在#define pISR (*(unsigned *)(0x30000000/0x00000000/0x8C000000+0x18))

    都是可以的,因为它指向同一个物理地址0x30000000
    这个中断向量式隐含的初始化了,并且在eboot中要留有空间。


    OK所有问题都解决了!哈哈

  • 相关阅读:
    团队开发第二阶段
    每日日报
    每日日报
    每日日报
    每日日报
    每日日报
    C++类class和结构体struct区别
    c++简单的类的建立与参数的两种传递方法
    C++ 使用delete删除指针
    暂存
  • 原文地址:https://www.cnblogs.com/gooogleman/p/1869643.html
Copyright © 2011-2022 走看看