2011年11月29日 星期二
2011年10月4日 星期二
Uboot 起始點
Uboot裡, code起始點其實要找u-boot.lds
公版是放在/arch/cpu/$cpu_name/ 下
我用這板freescale給的BSP 則放在/board/$vendor_name/$board_name/ 下
在start.o 前面還塞個flash_header.o
start.o 用/cpu/arm_cortex/ 下的start.o
flash_header.S 實在有點看不懂
arm 指令集要研究一下囉
以下轉貼一下 高手研究的結果 原出處連結
secname和contents是必須的,其他的都是可選的。下面挑幾個常用的看看︰
1、secname︰段名
2、contents︰決定哪些內容放在本段,可以是整個目標檔案,也可以是目標檔案中的某段(程式碼段、數據段等)
3、start︰本段連接(執行)的位址,如果沒有使用AT(ldadr),本段存儲的位址也是start。GNU網站上說start可以用任意一種描述位址的符號來描述。
4、AT(ldadr)︰定義本段存儲(加載)的位址。
下面,結合u-boot.lds看看一個正式的連接腳本檔案。
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
;指定輸出可執行檔案是elf格式,32位ARM指令,小端
OUTPUT_ARCH(arm)
;指定輸出可執行檔案的平台為ARM
ENTRY(_start)
;指定輸出可執行檔案的起始程式碼段為_start.
SECTIONS
{
. = 0x00000000 ; 從0x0位置開始
. = ALIGN(4) ; 程式碼以4位元組對齊
.text : ; 指定程式碼段
{
cpu/arm920t/start.o (.text) ; 程式碼的第一個程式碼部分
*(.text) ; 其它程式碼部分
}
. = ALIGN(4)
.rodata : { *(.rodata) } ; 指定只讀數據段
. = ALIGN(4);
.data : { *(.data) } ; 指定讀/寫數據段
. = ALIGN(4);
.got : { *(.got) } ; 指定got段, got段式是uboot自定義的一個段, 非標準段
__u_boot_cmd_start = . ; 把__u_boot_cmd_start賦值為當前位置, 即起始位置
.u_boot_cmd : { *(.u_boot_cmd) }; 指定u_boot_cmd段, uboot把所有的uboot命令放在該段.
__u_boot_cmd_end = . ; 把__u_boot_cmd_end賦值為當前位置,即結束位置
. = ALIGN(4);
__bss_start = . ; 把__bss_start賦值為當前位置,即bss段的開始位置
.bss : { *(.bss) } ; 指定bss段
_end = . ; 把_end賦值為當前位置,即bss段的結束位置
}
公版是放在/arch/cpu/$cpu_name/ 下
我用這板freescale給的BSP 則放在/board/$vendor_name/$board_name/ 下
在start.o 前面還塞個flash_header.o
start.o 用/cpu/arm_cortex/ 下的start.o
flash_header.S 實在有點看不懂
arm 指令集要研究一下囉
以下轉貼一下 高手研究的結果 原出處連結
對於.lds檔案,它定義了整個程式編譯之後的連接過程,決定了一個可執行程式的各個段的存儲位置。
先看一下GNU官方網站上對.lds檔案形式的完整描述︰
SECTIONS {
...
secname start BLOCK(align) (NOLOAD) : AT ( ldadr )
{ contents } >region :phdr =fill
...
}
先看一下GNU官方網站上對.lds檔案形式的完整描述︰
SECTIONS {
...
secname start BLOCK(align) (NOLOAD) : AT ( ldadr )
{ contents } >region :phdr =fill
...
}
secname和contents是必須的,其他的都是可選的。下面挑幾個常用的看看︰
1、secname︰段名
2、contents︰決定哪些內容放在本段,可以是整個目標檔案,也可以是目標檔案中的某段(程式碼段、數據段等)
3、start︰本段連接(執行)的位址,如果沒有使用AT(ldadr),本段存儲的位址也是start。GNU網站上說start可以用任意一種描述位址的符號來描述。
4、AT(ldadr)︰定義本段存儲(加載)的位址。
看一個簡單的例子︰(摘自《2410完全開發》)
/* nand.lds */
SECTIONS {
firtst 0x00000000 : { head.o init.o }
second 0x30000000 : AT(4096) { main.o }
}
/* nand.lds */
SECTIONS {
firtst 0x00000000 : { head.o init.o }
second 0x30000000 : AT(4096) { main.o }
}
以上,
head.o放在0x00000000位址開始處,init.o放在head.o後面,他們的執行位址也是0x00000000,即連接和存儲位址相同(沒有AT指定);
main.o放在4096(0x1000,是AT指定的,存儲位址)開始處,但是它的執行位址在0x30000000,執行之前需要從0x1000(加載處)複製到0x30000000(執行處),此過程也就用到了讀取Nand flash。
這就是存儲位址和連接(執行)位址的不同,稱為加載時域和執行時域,可以在.lds連接腳本檔案中分別指定。
head.o放在0x00000000位址開始處,init.o放在head.o後面,他們的執行位址也是0x00000000,即連接和存儲位址相同(沒有AT指定);
main.o放在4096(0x1000,是AT指定的,存儲位址)開始處,但是它的執行位址在0x30000000,執行之前需要從0x1000(加載處)複製到0x30000000(執行處),此過程也就用到了讀取Nand flash。
這就是存儲位址和連接(執行)位址的不同,稱為加載時域和執行時域,可以在.lds連接腳本檔案中分別指定。
編寫好的.lds檔案,在用arm-linux-ld連接命令時帶-Tfilename來調用執行,如
arm-linux-ld Tnand.lds x.o y.o o xy.o。
arm-linux-ld Tnand.lds x.o y.o o xy.o。
也用-Ttext參數直接指定連接位址,如
arm-linux-ld Ttext 0x30000000 x.o y.o o xy.o。
arm-linux-ld Ttext 0x30000000 x.o y.o o xy.o。
既然程式有了兩種位址,就涉及到一些跳轉指令的區別
ARM彙編中,常有兩種跳轉方法︰b跳轉指令、ldr指令向PC賦值。我自己經過歸納如下︰
(1)b step1 ︰b跳轉指令是相對跳轉,倚賴當前PC的值,偏移量是透過該指令本身的bit[23:0]算出來的,這使得使用b指令的程式不倚賴於要跳到的程式碼的位置,只看指令本身。
(2)ldr pc, =step1 ︰該指令是從內存中的某個位置(step1)讀出數據並賦給PC,同樣倚賴當前PC的值,但是偏移量是那個位置(step1)的連接位址(執行時的位址),所以可以用它實現從Flash到RAM的程式跳轉。
(3)此外,有必要回味一下adr偽指令,U-boot中那段relocate程式碼就是透過adr實現當前程式是在RAM中還是flash中。仍然用我當時的註釋︰
ARM彙編中,常有兩種跳轉方法︰b跳轉指令、ldr指令向PC賦值。我自己經過歸納如下︰
(1)b step1 ︰b跳轉指令是相對跳轉,倚賴當前PC的值,偏移量是透過該指令本身的bit[23:0]算出來的,這使得使用b指令的程式不倚賴於要跳到的程式碼的位置,只看指令本身。
(2)ldr pc, =step1 ︰該指令是從內存中的某個位置(step1)讀出數據並賦給PC,同樣倚賴當前PC的值,但是偏移量是那個位置(step1)的連接位址(執行時的位址),所以可以用它實現從Flash到RAM的程式跳轉。
(3)此外,有必要回味一下adr偽指令,U-boot中那段relocate程式碼就是透過adr實現當前程式是在RAM中還是flash中。仍然用我當時的註釋︰
relocate: /* 把U-Boot重新定位到RAM */
adr r0, _start /* r0是程式碼的當前位置 */
/* adr偽指令,彙編器自動透過當前PC的值算出 如果執行到_start時PC的值,放到r0中︰
當此段在flash中執行時r0 = _start = 0;
當此段在RAM中執行時_start = _TEXT_BASE(在board/smdk2410/config.mk中指定的值為0x33F80000,即u-boot在把程式碼拷貝到RAM中去執行的程式碼段的開始) */
ldr r1, _TEXT_BASE /* 測試判斷是從Flash啟動,還是RAM */
/* 此句執行的結果r1始終是0x33FF80000,因為此值是又編譯器指定的(ads中設定,或-D設定編譯器參數) */
cmp r0, r1 /* 比較r0和r1,調試的時候不要執行重定位 */
adr r0, _start /* r0是程式碼的當前位置 */
/* adr偽指令,彙編器自動透過當前PC的值算出 如果執行到_start時PC的值,放到r0中︰
當此段在flash中執行時r0 = _start = 0;
當此段在RAM中執行時_start = _TEXT_BASE(在board/smdk2410/config.mk中指定的值為0x33F80000,即u-boot在把程式碼拷貝到RAM中去執行的程式碼段的開始) */
ldr r1, _TEXT_BASE /* 測試判斷是從Flash啟動,還是RAM */
/* 此句執行的結果r1始終是0x33FF80000,因為此值是又編譯器指定的(ads中設定,或-D設定編譯器參數) */
cmp r0, r1 /* 比較r0和r1,調試的時候不要執行重定位 */
下面,結合u-boot.lds看看一個正式的連接腳本檔案。
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
;指定輸出可執行檔案是elf格式,32位ARM指令,小端
OUTPUT_ARCH(arm)
;指定輸出可執行檔案的平台為ARM
ENTRY(_start)
;指定輸出可執行檔案的起始程式碼段為_start.
SECTIONS
{
. = 0x00000000 ; 從0x0位置開始
. = ALIGN(4) ; 程式碼以4位元組對齊
.text : ; 指定程式碼段
{
cpu/arm920t/start.o (.text) ; 程式碼的第一個程式碼部分
*(.text) ; 其它程式碼部分
}
. = ALIGN(4)
.rodata : { *(.rodata) } ; 指定只讀數據段
. = ALIGN(4);
.data : { *(.data) } ; 指定讀/寫數據段
. = ALIGN(4);
.got : { *(.got) } ; 指定got段, got段式是uboot自定義的一個段, 非標準段
__u_boot_cmd_start = . ; 把__u_boot_cmd_start賦值為當前位置, 即起始位置
.u_boot_cmd : { *(.u_boot_cmd) }; 指定u_boot_cmd段, uboot把所有的uboot命令放在該段.
__u_boot_cmd_end = . ; 把__u_boot_cmd_end賦值為當前位置,即結束位置
. = ALIGN(4);
__bss_start = . ; 把__bss_start賦值為當前位置,即bss段的開始位置
.bss : { *(.bss) } ; 指定bss段
_end = . ; 把_end賦值為當前位置,即bss段的結束位置
}
2011年10月1日 星期六
2011年9月30日 星期五
ADB 連結問題排除
搞了半天 HTC hero /adb devices 就是找不到, 我Fujitsu Haro 就是找不到
谷歌了一下
方法一: ~/.android 目錄下建一個adb.ini
加以下內容
----------------------
1 #Vendor ID 總共數量
04c5 #VID
方法二
/etc/udev/rules.d/ 新增一檔案 50-android.rules
內容:
谷歌了一下
方法一: ~/.android 目錄下建一個adb.ini
加以下內容
----------------------
1 #Vendor ID 總共數量
04c5 #VID
方法二
/etc/udev/rules.d/ 新增一檔案 50-android.rules
內容:
SUBSYSTEM=="usb", ATTRS{idVendor}=="04c5", SYMLINK+="android_adb", MODE="0666", OWNER="<username>"
ADB tools
轉載
Adb 全名是 Android Debug Bridge,是開發或使用 Android 時很常用到的工具。使用者可以從Android 官方站下載 SDK,在其中的 platform-tools (原本在 \Tools) 中找到。
當機器上有打開 USB debug mode 時,使用者即可通過adb 進行各種 debug 、底層(linux user space)的 Android 功能。比較常用的功能:
- tools\ddms.bat: Android AP/Framework 層最主要的 debug tool
- 安裝 Android 應用程式
- 連接機器,使用 linux userspace 的功能。 ex: ping, ssh, ftp ... blah blah.
adb的工作方式比較特殊採用監聽Socket TCP 5554等端口的方式讓IDE和Qemu通訊,預設情況下adb會daemon相關的port。
這篇文章主要是整理了一些adb 的基本功能,後面補上一些開發時常用的功能。
文件參考:
- 官方的說明文件: http://developer.android.com/intl/zh-TW/guide/developing/tools/adb.html
- Android模擬器adb命令介紹
- Source code: system/core/adb/ ,除了 adb client 跟 adbd (Android 系統內負責處理 adb 功能的 daemon)的實作外,裡面包含了 service 跟 overview 的文件。
功能介紹
1. 通過adb 進入機器或模擬器的shell模式
adb shell
也可以執行各種Linux的命令,其命令格式為:adb shell command
PS: 當 adb shell 之後提示字元為"#"時,表示使用者為 root (最大權限),若是 "$" 則是以shell 權限工作
adb shell ls 就是列出目錄
adb shell dmesg 會列印出Linux kernel log
adb shell cat /proc/kmsg 持續印出 kernel log (需要 root)
adb shell keyevent 1 輸入 keyevent,可輸入的內容參考 adb shell keyevent
2. 安裝Android 應用程式(*.apk)
可執行adb install android123.apk,這樣名為android123的安裝包就會安裝到Android模擬器中,前提是android123.apk文件需要放到SDK\Tools目錄下。
比較特殊的安裝方法還有
"-r": 當已經安裝過舊版本的程式時,可以使用 -r 去覆蓋。
"-f": 強制安裝,通常在安裝程式時會遇到相容問題,可使用此參數解決。
3. PC 端與Android 機器的檔案傳輸
除了使用記憶卡模式外,還可使用下面命令可以進行檔案傳輸:
把android123.txt 傳到機器上的/tmp/ 資料夾中:
adb push android123.txt /tmp/android123.txt
從機器上把 android123.txt 抓到PC端:
adb pull /tmp/android123.txt android123.txt
4. 顯示系統資訊 - dumpsys
除了直接輸入 adb shell dumpsys 外,也可以另外指定要顯示的 service,簡列一些參數,用法如:
adb shell dumpsys SurfaceFlinger
battery: 列出基本的電池資訊
batteryinfo: 各種功能使用 power 的狀況,同About Phone 裡面的電池使用狀況。
SurfaceFlinger: 系統的 Surface 使用情況
power: 列出 Power Manager 的參數,如 wakelock 時間等
alarm: 列出目前有註冊 alarm 者
5. 其他
- Android 預設可編譯成三種模式: eng, userdebug, user。一般使用者拿到的機器多是 user 版,當然如果是開發人員,可能會使用 eng 或 userdebug 版 進行debug。或是使用者自行 root 機器後,可使用下列指令取得 root 權限
adb root
- 一般為了防止系統出問題,所以 /system 通常在掛載時會設定為唯讀(read only),當使用者有root權限時,可使用下面指令將系統重新掛載成 R/W 模式,可對 /system 內的檔案做修改
adb remount
- 如果在使用 adb 時發現有* daemon not running. starting it now *的提示可以結束adb
adb kill-server
- 顯示 android 機器連接狀況
adb devices
結果如下
List of devices attached
1234567890ABCDEF device
- 等待正在運行的設備
adb wait-for-device
- Port forwarding,在某些應用如模擬器的網路連接使用、VNC時,會用到這項功能。主要是用來將機器上的的TCP port 5555 轉發到 port 1234
adb forward tcp:5555 tcp:1234
- 擷取系統內的各種資訊,產生 bug report
adb bugreport
Original Post Link
2011年9月29日 星期四
訂閱:
文章 (Atom)