從啟動核心功能void Launch(DWORD dwLaunchAddr)看彙編和C的函數參數傳遞

來源:互聯網
上載者:User

作者:wogoyixikexie@gliet

 

void Launch(DWORD dwLaunchAddr)這個函數是在SMDK2440A/Src/Bootloader/Eboot/util.s(32)實現的
;******************************************************************************

    INCLUDE kxarm.h

PHY_RAM_START EQU 0x30000000
VIR_RAM_START EQU 0x80000000

TEXTAREA

LEAF_ENTRY Launch

ldr r2, = PhysicalStart
ldr    r3, = (VIR_RAM_START - PHY_RAM_START)

sub    r2, r2, r3

mov    r1, #0x0070            ; Disable MMU
mcr    p15, 0, r1, c1, c0, 0
nop
mov    pc, r2                  ; Jump to PStart
nop

; MMU & caches now disabled.

PhysicalStart

mov    r2, #0
mcr    p15, 0, r2, c8, c7, 0  ; Flush the TLB
mov    pc, r0 ; Jump to program we are launching.
根據C語言中void Launch(DWORD dwLaunchAddr),只有一個參數以及C和彙編函數調用的參數路由規則。
這個DWORD dwLaunchAddr應該傳遞給彙編中的r0。
但是我搞不明白這東西是怎麼啟動起來的。並且這個啟動方法和優龍的有很大差別。
根據config.bib中的設定,這個核心開始的物理地址應該是)0x30200000
按照道理應該是直接運行PhysicalStart這個彙編段才能運行起來,但是怎麼會在前面橫插下面的代碼呢?
ldr r2, = PhysicalStart
ldr    r3, = (VIR_RAM_START - PHY_RAM_START)

sub    r2, r2, r3

mov    r1, #0x0070            ; Disable MMU
mcr    p15, 0, r1, c1, c0, 0
nop
mov    pc, r2                  ; Jump to PStart

還有一個疑問,為什麼eboot要在nboot之後開啟MMU,但是在啟動核心的時候又關閉MMU,不能在eboot把MMU都關閉嗎?
這樣做有什麼好處?
=================================================================

引用 1 樓 hzdysymbol 的回複:

Launch函數其實只是把PC指標指過去,跳轉到相應的地址運行
Eboot中應該有需要訪問虛擬位址吧,所以不能關
關掉後再跳到Image是因為Image中還會再做一次初始化的動作,如果在Image中的起始部分把相關的初始化拿掉,應該可以不關MMU

你說的我明白,我的意思是對他的做法有點不解。
我覺得這個比較令人費解。
ldr r2, = PhysicalStart
ldr    r3, = (VIR_RAM_START - PHY_RAM_START) //為什麼要這樣做呢?
sub    r2, r2, r3
直接把這個0x30200000放到PC不行嗎?

------------------------------------------------
優龍是直接跳轉到相應的記憶體物理地址啟動並執行
不會像在上面那樣搞得模模糊糊。

C/C++ code
//====================================================//優龍bootloader載入NK運行入口函數:使用函數指標的方法,//相當巧妙,程式可讀性比三星內建的eboot強悍//====================================================void call_linux(U32 a0, U32 a1, U32 a2){    void (*goto_start)(U32, U32);        rINTMSK=BIT_ALLMSK;        cache_clean_invalidate();    tlb_invalidate();        __asm{//        mov    r0, a0//%0//        mov    r1, a1//%1//        mov    r2, a2//%2        mov    ip, #0        mcr    p15, 0, ip, c13, c0, 0    /* zero PID */        mcr    p15, 0, ip, c7, c7, 0    /* invalidate I,D caches */        mcr    p15, 0, ip, c7, c10, 4    /* drain write buffer */        mcr    p15, 0, ip, c8, c7, 0    /* invalidate I,D TLBs */        mrc    p15, 0, ip, c1, c0, 0    /* get control register */        bic    ip, ip, #0x0001            /* disable MMU */        mcr    p15, 0, ip, c1, c0, 0    /* write control register */        //mov    pc, r2        //nop        //nop        /* no outpus */        //: "r" (a0), "r" (a1), "r" (a2)    }//    SetClockDivider(1, 1);//    SetSysFclk(FCLK_200M);        //start kernel, use 200M    //SET_IF();    goto_start = (void (*)(U32, U32))a2;//這個a2=0x30200000,在調用的時候傳遞進來    (*goto_start)(a0, a1);    }
----------------------------------------------------------------------------
問題的關鍵是在Disable MMU後必須在2條指令內執行mov pc操作,否則程式就跑飛 
但是在真正跳轉到NK地址前,還需要flush cache等操作
所以就先跳到PhysicalStart處,做完其他動作再跳到NK入口
-----------------------------------------------------------------------------
問題的關鍵是在Disable MMU後必須在2條指令內執行mov pc操作,否則程式就跑飛 
這個在哪裡有介紹呢?這個我是第一聽說,學習了。

但是在真正跳轉到NK地址前,還需要flush cache等操作 ,所以就先跳到PhysicalStart處,做完其他動作再跳到NK入口
對,的確如此。

我的疑惑是
ldr r2, = PhysicalStart
ldr    r3, = (VIR_RAM_START - PHY_RAM_START) //求出虛擬位址和物理地址之差。其實虛擬、物理地址轉換就是這個原理

sub    r2, r2, r3 //這個相當於是PhysicalStart 所在地址減去(-)虛擬位址和物理地址之差

mov    r1, #0x0070            ; Disable MMU
mcr    p15, 0, r1, c1, c0, 0
nop
mov    pc, r2          ; Jump to PStart 這個難道會跳到PhysicalStart 去執行?按照他的程式,是會的。
難道程式這麼做是把這個PhysicalStart所在的虛擬位址轉換為物理地址?
就是PhysicalStart(虛擬位址) -虛擬位址和物理地址之差
難道編譯器編譯出來的東西也有物理地址和虛擬位址之分的?
真是這樣嗎?我覺得這個是比較合理的解釋。
因為優龍沒有使用(VIR_RAM_START - PHY_RAM_START)的原因就是因為,它在bootloader階段已經關閉了MMU,沒有必要這麼做了。

各位前輩,不知道我這樣理解是否正確,請指教。
----------------------------------------------------------------------------
引用 14 樓 wohuazhen 的回複:
難道編譯器編譯出來的東西也有物理地址和虛擬位址之分的?
我認為ldr r0, =PhysicalStart中的PhysicalStart,編譯器給的是物理地址,但是當在開啟MMU後,這段代碼載入到cpu解釋過程中會被處理器轉換成虛擬位址。


不是啊,這個標號所標識的地址在MMU開啟的時候是是標識虛擬位址,當關閉MMU它就是物理地址,由於,這個代碼已經在MMU開啟的時候跑到記憶體運行了,所以我們要手動把它變回物理地址,就是下面的代碼
ldr r2, = PhysicalStart
ldr    r3, = (VIR_RAM_START - PHY_RAM_START)

sub    r2, r2, r3

mov    r1, #0x0070            ; Disable MMU
mcr    p15, 0, r1, c1, c0, 0
nop
mov    pc, r2                  ; Jump to PStart

——這個代碼非常巧妙。剛開始還真是沒有反映過來。
----------------------------------------------------------------------------
至於eboot為什麼要開MMU,而優龍的ADS Bootloader為什麼不開, 
我想大家一定和我一樣很想知道為什麼。
——其實這是由於eboot要調用 FMD驅動以及一些微軟的函數,這些函數是運行在虛擬記憶體的,eboot為了討好她,利用他們,只能委曲求全了,裸奔還要開MMU,豈有此理!哈哈。
優龍 Bootloader,自然是沒有和上面這些聯絡了。自然沒有必要開。

所以才會造成啟動NK函數有如此大的不同。

哈哈。自己解決也不錯。
----------------------------------------------------------------------------
引用 17 樓 hhyh612 的回複:
編譯器其實是不區分虛真實位址的,只不過boot.bib裡寫了RAMIMAGE的地址是80000000(所謂的虛地址),所以PhysicalStart這個標號的值就是8XXXXXXX的虛地址,在關閉mmu後,必須把它轉成物理地址3XXXXXXX

至於為什麼Disable MMU後2條指令內必須mov pc
是因為執行mcr    p15, 0, r1, c1, c0, 0 指令時pc是虛地址8XXXXXXX
執行完MMU就關了,8XXXXXXX就不存在了,所以需要馬上讓pc變成真實位址3XXXXXXX

2條指令內是因為ARM流水線的原因,所以MMU關了,但是mcr之後的兩條指令以及在pc是虛地址的時候預取了,所以不會報錯

如果2條指令之內不mov pc到3XXXXXXX,接下來就要Prefetch Abort了。。——完全明白了,謝謝你


謝謝 hhyh612 ,所有迷惑解了。
引用 15 樓 gooogleman 的回複:
引用 14 樓 wohuazhen 的回複:
難道編譯器編譯出來的東西也有物理地址和虛擬位址之分的?
我認為ldr r0, =PhysicalStart中的PhysicalStart,編譯器給的是物理地址,但是當在開啟MMU後,這段代碼載入到cpu解釋過程中會被處理器轉換成虛擬位址。


不是啊,這個標號所標識的地址在MMU開啟的時候是是標識虛擬位址,當關閉MMU它就是物理地址,由於,這個代碼已經在MMU開啟的時候跑到記憶體運行了,所以我們要手動把它變回物理地…

關於程式相關標號,昨下班回去我查看了《ARM系列處理器應用完全技術手冊》一書,它的解釋,這種標號在彙編時被處理成PC值加上或減去一個數字常量。我想這是為什麼“這個標號所標識的地址在MMU開啟的時候是是標識虛擬位址,當關閉MMU它就是物理地址”的原因了。
另外“2條指令內是因為ARM流水線的原因”合理的解釋,學習了。
==================================================================
引用 17 樓 hhyh612 的回複:
編譯器其實是不區分虛真實位址的,只不過boot.bib裡寫了RAMIMAGE的地址是80000000(所謂的虛地址),所以PhysicalStart這個標號的值就是8XXXXXXX的虛地址,在關閉mmu後,必須把它轉成物理地址3XXXXXXX

至於為什麼Disable MMU後2條指令內必須mov pc
是因為執行mcr    p15, 0, r1, c1, c0, 0 指令時pc是虛地址8XXXXXXX
執行完MMU就關了,8XXXXXXX就不存在了,所以需要馬上讓pc變成真實位址3XXXXXXX

2條指令內是因為ARM流水線的原因,所以MMU關了,但是mcr之後的兩條指令以及在pc是虛地址的時候預取了,所以不會報錯

如果2條指令之內不mov pc到3XXXXXXX,接下來就要Prefetch Abort了。。——完全明白了,謝謝你


謝謝 hhyh612 ,所有迷惑解了。
=========================================================================
引用 19 樓 wohuazhen 的回複:
引用 15 樓 gooogleman 的回複:
引用 14 樓 wohuazhen 的回複:
難道編譯器編譯出來的東西也有物理地址和虛擬位址之分的?
我認為ldr r0, =PhysicalStart中的PhysicalStart,編譯器給的是物理地址,但是當在開啟MMU後,這段代碼載入到cpu解釋過程中會被處理器轉換成虛擬位址。


不是啊,這個標號所標識的地址在MMU開啟的時候是是標識虛擬位址,當關閉MMU它就是物理地址,由於,這個代碼已經在MMU開啟的時候跑到記憶體運行…


不是吧,標號的值不會變得
用mov pc的話,一定用的是絕對位址,和pc無關
如果用b指令,那麼用的是pc相關的相對位址
=============================================================================
最後,還要給點提醒:就是彙編和C混合編程在ARM下使用R0,R1,R2,R3來傳遞參數,而X86使用堆棧來傳遞
 
關於彙編和C語言函數參數傳遞問題請參考這個文章
http://linux.chinaunix.net/techdoc/develop/2008/06/28/1013691.shtml
http://topic.csdn.net/u/20071128/16/d7c16f51-b70c-4b2f-a65b-f4c90c519d00.html
轉載請標明:作者wogoyixikexie@gliet.桂林電子科技大學一系科協。如有錯誤,希望能夠留言指出。
 
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.