• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆 - 60, 文章 - 0, 評論 - 197, 引用 - 0
            數據加載中……

            s3c2410 MMU 啟用后設置中斷跳轉指令遇到的問題

            事情是這樣的, 前些日子在 FS2410 (核心板為三星 s3c2410)開發板上實現了中斷,包括
            響應時鐘 Timer0, 響應按鍵,并實現了串口通信,能把任何數據通過 UART0 發送到 PC 機
            上的超級終端上進行顯示,這樣也便于調試。前兩天又實現了 MMU 的啟用代碼,歡呼雀躍
            啊..., 可就在這個時候問題來了...

            MMU 啟用后中斷不能響應了!, start.S 的代碼片段如下(arm-linux-gcc 匯編格式):

               text
               .global _start
               _start:
                b reset
                NOP
                NOP
                NOP
                NOP
                NOP
                ldr pc ,=handle_irq
                NOP
               reset:
                ldr r0, =0x53000000  @ Close Watch-dog Timer
                mov r1, #0x0
                str r1, [r0]
              
                @ init stack
                ldr sp,=4096
                
                @ disable all interrupts
                mov r1, #0x4A000000
                mov r2, #0xffffffff
                str r2, [r1, #0x08]
                ldr r2, =0x7ff
                str r2, [r1, #0x1c]
              
                bl  memory_setup  @ Initialize memory setting
                bl  flash_to_sdram  @ Copy code to sdram
               
                ldr pc, =run_on_sdram
             run_on_sdram:
                ldr sp, =0x33000000
                bl init_mmu_tlb   @ setup page table
                bl init_mmu   @ MMU enabled
              
                msr cpsr_c, #0xd2  @ set the irq mode stack
                ldr sp, =0x31000000
                msr cpsr_c, #0xdf  @ set the system mode stack
                ldr sp, =0x32000000
                bl  init_irq           
                msr cpsr_c, #0x5f  @ set the system mode open the irq
                
                ldr sp, =0x33000000  @ Set stack pointer
                bl  main
               loop:
                b loop
              
            我是通過在地址 0x00000018 放入一條長跳轉指 ldr pc, =handle_irq 來響應中斷的,在
            沒有啟用 MMU 之前,代碼工作的很好。通過如下兩個函數啟用了 MMU 實現虛擬內存管理:

                 bl init_mmu_tlb   @ setup page table
                 bl init_mmu   @ MMU enabled

            通過下面代碼來映射低端和高端中斷向量表:

              *(tb_base + 0x00000000) = (0x00000000)|(0x03<<10)|(0<<5)|(1<<4)|(1<<3)|0x02;
              *(tb_base + (0xffff0000>>20)) = VECTORS_PHY_BASE|(0x03<<10)|(0<<5)|(1<<4)|(0<<3)|0x02;

            其中 VECTORS_PHY_BASE=0x33f00000, 可以看到:
            通過設置頁表,將 0xffff0000 為首地址的 32 個字節的中斷向量表被映射到 0x33ff0000 為首地址的 32 字節區域,

            既然設置了高端中斷向量,我們就要在 0x33ff0000 處設置中斷跳轉指令,通過調用下面這個函數:

               bl  flash_to_sdram

            把程序自身復制到 SDRAM 的 0x30004000為首地址的區域,而 0x30004000 前面的 16K 即 0x30000000~0x30003FFF
            用來放置頁表,并且把 nand flash 的前 512byte 復制到 SDRAM 0x33ff0000 處, 因為nand flash 的前32byte 是8 個
            中斷跳轉指令,這樣中斷向量表就在 0x33ff0000 處被設置。

            如何讓 ARM 使用高端的中斷跳轉指令呢?通過設置 CP15 協處理器的一些寄存器來啟用。以下是內聯匯編片段

               /*
                * turn on what we want
                * base location of exception = 0xffff0000
                */
               "orr r0, r0, #0x2000\n"
               "orr r0, r0, #0x0002\n"

               /* MMU enabled*/
               "orr r0, r0, #0x0001\n"

               /* write control register*/
               "mcr p15, 0, r0, c1, c0, 0\n"

            萬事俱備,我們可以實驗了,可不幸的中斷不能響應了?!...

            ......經過了一天的折騰,發現將中斷跳轉指令由
               b reset
                NOP
                NOP
                NOP
                NOP
                NOP
                ldr pc,=handle_irq
                NOP

            改為

               b reset
                NOP
                NOP
                NOP
                NOP
                NOP
                ldr pc, handle_irq_addr
                NOP
               handle_irq_addr: 
                .long handle_irq


            中斷就能響應了,代碼運行的很好,可百思不得其解,為什么不能用 ldr pc, =handle_irq
            設置而非要用下面這種形式呢

                    ldr pc, handle_irq_addr
                    NOP
               handle_irq_addr: 
                    .long handle_irq

            我在 main 函數里通過如下代碼將所有的中斷跳轉指令(高端的和低端的)都打印出來了:

            #include "serl.h"
            #include "printf.h"

            #define GPFCON (*(volatile unsigned long *)0x56000050)
            #define GPFDAT (*(volatile unsigned long *)0x56000054)

            int main()
            {
              init_uart();
              GPFDAT = 0x0;
              uart_printf("starting:\n");
              unsigned long *ptr = (unsigned long *)0x30004000;
              unsigned long *ptr2 =(unsigned long *)0x33ff0000;

              unsigned long *ptr3 = (unsigned long *)0x00000000;
              unsigned long *ptr4 = (unsigned long *)0xffff0000;

              int i= 8;
              while (i--) {
                uart_printf("%x  %x  %x  %x\n", *ptr++, *ptr2++, *ptr3++, *ptr4++);
              }
              while (1);
              return 0;
            }

            代碼將數據通過串口在超級終端上進行顯示后,發現確有微妙不同:

            中斷不能響應時(ldr pc, =handle_irq):
            0x30004000 0x33ff0000 0x00000000 0xffff0000
            -------------------------------------------
            ea000006   ea000006   ea000006   ea000006
            e1a00000   e1a00000   e1a00000   e1a00000
            e1a00000   e1a00000   e1a00000   e1a00000
            e1a00000   e1a00000   e1a00000   e1a00000
            e1a00000   e1a00000   e1a00000   e1a00000
            e1a00000   e1a00000   e1a00000   e1a00000
            e59ff1fc      e59ff1fc      e59ff1fc      e59ff1fc
            e1a00000   e1a00000   e1a00000   e1a00000


            中斷可以響應時(ldr pc, handle_irq_addr):
            0x30004000 0x33ff0000 0x00000000 0xffff0000
            -------------------------------------------
            ea000007   ea000007   ea000007   ea000007
            e1a00000   e1a00000   e1a00000   e1a00000
            e1a00000   e1a00000   e1a00000   e1a00000
            e1a00000   e1a00000   e1a00000   e1a00000
            e1a00000   e1a00000   e1a00000   e1a00000
            e1a00000   e1a00000   e1a00000   e1a00000
            e59ff000     e59ff000     e59ff000     e59ff000
            e1a00000   e1a00000   e1a00000   e1a00000


            難道編譯器對這兩種跳轉產生了不同的影響? 將代碼反匯編來看個究竟:

            中斷不能響應時(ldr pc, =handle_irq):
            ---------------------------------------------------------------------
                   0: ea000006  b 0x20
                   4: e1a00000  nop   (mov r0,r0)
                   8: e1a00000  nop   (mov r0,r0)
                   c: e1a00000  nop   (mov r0,r0)
                  10: e1a00000  nop   (mov r0,r0)
                  14: e1a00000  nop   (mov r0,r0)
                  18: e59ff1fc  ldr pc, [pc, #508] ; 0x21c
                  1c: e1a00000  nop   (mov r0,r0)


            發現 ldr pc, =handle_irq 被匯編成

               ldr pc, [pc, #508] ; 0x21c

            我們又發現編譯器為這條指令生成了一條注釋: ; 0x21c, 它的意思是說去地址0x21c 處加載
            數據,怎么算的呢? 當前地址是 0x18, 加上 508 即 0x1fc 得出 0x214,好像不是0x21c,
            慢著... ARM 采用三級流水結構,那么讀 pc 時得到的得數值會是相對當前指令的第二條指
            令的地址, 即當前地址值加上 0x8,這么算來:

              0x18 + 0x1fc + 0x8 = 0x21c

            去 0x21c 處看看:

              21c: 30004208  andcc r4, r0, r8, lsl #4

            是 0x30004208 這么個值,也就是說 ARM 把 0x30004208 裝進了 pc
            ......


            再來看看將中斷跳轉指令改成

                    ldr pc, handle_irq_addr
                    NOP
               handle_irq_addr: 
                     .long handle_irq

            也就是中斷能響應時的反匯編代碼:

                   0: ea000007  b 0x24
                   4: e1a00000  nop   (mov r0,r0)
                   8: e1a00000  nop   (mov r0,r0)
                   c: e1a00000  nop   (mov r0,r0)
                  10: e1a00000  nop   (mov r0,r0)
                  14: e1a00000  nop   (mov r0,r0)
                  18: e59ff000  ldr pc, [pc, #0] ; 0x20
                  1c: e1a00000  nop   (mov r0,r0)

            可以看到 0x18 處為      

                  18: e59ff000  ldr pc, [pc, #0] ; 0x20

            與上面分析同理,去 0x20 處看看:

                  20: 3000420c  andcc r4, r0, ip, lsl #4

            發現 ARM 把 0x3000420c 這個數值裝進了 pc


            前后對比一下, 一個是 0x30004208, 另一個是 0x3000420c, 兩者相差 4 個字節
            而后一種情況多出的4個字節是由于 定義
               
               handle_irq_addr: 
                .long handle_irq

            而占用的 4 個字節。

            看來編譯器忠實的匯編了代碼,那么很可能是 MMU 啟用后對 ldr pc, =handle_irq 這樣
            的中斷跳轉指令產生了影響?

            ......現在還沒有找到合理的解釋,請高手不吝賜教

            posted on 2008-01-28 11:11 Normandy 閱讀(3791) 評論(3)  編輯 收藏 引用 所屬分類: Embeded Area

            評論

            # re: s3c2410 MMU 啟用后設置中斷跳轉指令遇到的問題  回復  更多評論   

            樓主其實已經摸到錯誤的門了,雖然沒能得出結論…………
            2008-01-28 14:36 | ggyy

            # re: s3c2410 MMU 啟用后設置中斷跳轉指令遇到的問題  回復  更多評論   

            @ggyy

            呵呵,問題已經解決,一個低級的錯誤,原因如下:
            508 + 0x8 即 516, 大于 512, 前面我提到把 Nand flash 的前 512 字節復制到 0x33ff0000 處用以設置高端中斷向量表,這樣當發生 IRQ 中斷時,程序會去 0x33ff0000 + 508 + 0x8 處把 0x30004208 裝進 pc 并進行跳轉來響應中斷,但不幸的是我只復制了512字節,所以 IRQ 中斷是不能響應的??偨Y一下,對比上面提到的兩種設置中斷跳轉指令的方式:

            (1)
            b reset
            NOP
            NOP
            NOP
            NOP
            NOP
            ldr pc,=handle_irq
            NOP

            (2)
            b reset
            NOP
            NOP
            NOP
            NOP
            NOP
            ldr pc, handle_irq_addr
            NOP
            handle_irq_addr:
            .long handle_irq

            第二種方式的好處是顯而易見的,只需要偏移 0x8 就能取到目的地址了;對第一種方式,ARM 要去通過一個偏移來取到目的地址,具體數值要看編譯如何設置了。
            2008-01-29 14:00 | Normandy

            # re: s3c2410 MMU 啟用后設置中斷跳轉指令遇到的問題  回復  更多評論   

            其實,ARM匯編指令LDR很好的說明了這個問題,看看它的說明,好好理解下。
            2008-11-14 17:12 | zqs
            久久无码精品一区二区三区| 精品国产青草久久久久福利| 国产高潮国产高潮久久久| 精品乱码久久久久久久| 欧美亚洲另类久久综合| 婷婷国产天堂久久综合五月| 久久经典免费视频| 亚洲国产精品一区二区久久| 青青青青久久精品国产h久久精品五福影院1421 | 91超碰碰碰碰久久久久久综合| 国产综合成人久久大片91| 国产精品久久久久免费a∨| 狠狠色丁香婷婷综合久久来| 久久婷婷色综合一区二区| 久久天天躁狠狠躁夜夜躁2O2O| 久久久久亚洲AV成人网人人网站| 亚洲国产精品无码成人片久久| 精品久久人人妻人人做精品 | 久久噜噜久久久精品66| 亚洲狠狠婷婷综合久久久久| 久久WWW免费人成—看片| 久久综合噜噜激激的五月天| 久久影院午夜理论片无码| 国产高潮国产高潮久久久| 久久精品国产免费观看| 欧美日韩精品久久久久| 久久国产香蕉视频| 国产成人精品免费久久久久| 97精品国产97久久久久久免费 | 久久精品亚洲日本波多野结衣| 亚洲国产精品无码久久九九| 久久久久99精品成人片三人毛片| 亚洲乱亚洲乱淫久久| 日本免费久久久久久久网站| 国产成人精品免费久久久久| 久久国产色AV免费看| 亚洲精品无码久久久久久| 亚洲αv久久久噜噜噜噜噜| 久久笫一福利免费导航| 狠狠精品久久久无码中文字幕| 超级碰碰碰碰97久久久久|