概述
1、高通平台android开发总结
1.1 搭建高通平台环境开发环境
在高通开发板上烧录文件系统
建立高通平台开发环境
高通平台,android和 modem 编译流程分析
高通平台 7620 启动流程分析
qcril 流程分析,设置sim卡锁
python scons 语法学习
Python 语言之 scons 工具流程分析:
1.2 搭建高通平台环境开发环境
高通android智能平台概述
选择合适的源代码以及工具
建立 Android 开发环境(部分略)
建立 modem 开发环境
1.2.1 高通android智能平台概述
高通 7230 android 智能手机解决方案的软件包括两个部分
1. 以linux 操作系统为基础的 android 系统
2. 以 L4,REX为基础的 Modem 部分
在高通7系列的架构中,一个IC内部集成有两个ARM处理器,一个ARM9(或者arm11),专门负责处理通信协议,射频以及GPIO等,软件架构采用 AMSS, 另外一个是ARM11,用来处理多媒体,上层应用,以及其他的一些任务,运行的系统是 android 系统,这两个处理器之间通过共享内存的硬件方式来进行通信。
1.2.1.1 什么是L4,REX,BREW,AMSS以及相互之间的关系
L4是一组计算机程序,是最初由Jochen Liedtke设计的微内核构架的操作系统内核,现在已经形成一个微内核家族。L4这个微内核系统由于其出色的性能和很小的体积而开始被计算机工业所认知,被移植到了许多不同的硬件构架上。高通的 L4 提供了操作系统最基本的操作,是买别人的。
早期的操作系统绝大多数是 Monolithic Kernel, 意思是整个操作系统 - 包括Scheduling (调度), File system (文件系统), Networking (网络), Device driver (设备驱动程序), Memory management (存储管理), Paging(存储页面管理) - 都在内核中完成.一直到现在广泛应用的操作系统,如UNIX,Linux,和Windows还大都是monolithic kernel操作系统.但随着操作系统变得越来越复杂(现代操作系统的内核有一两百万行C程序是很常见的事情),把所有这些功能都放在内核中使设计难度迅速增加.
微内核是一个与Monolithic Kernel相反的设计理念.它的目的是使内核缩到最小,把所有可能的功能模块移出内核.理想情况下,内核中仅留下Address Space Support(地址空间支持),IPC (Inter-Process Communication,进程间通讯),和Scheduling(调度),其他功能模块做为用户进程运行。
REX 是在 L4 之上封装的服务,是一个抢占式,多任务的RTOS,所有的任务都以task的形式存在,REX提供包括任务创建,同步,互斥,计时器,中断控制等功能的API,这里的task实际上就是我们的线程,每个 task对应着一个线程。REX维护一个task list(双向链表),始终运行高优先级的task。products里面所有的服务包括3g协议栈等都是以task的形式跑在rex之上的。
而Brew的话是运行的环境,跟Java 有点儿类似,相当于是一个虚拟机。
AMSS――高级的移动用户软件(Advanced Mobile Subscriber Software)技术,是一种新的软件架构,是对原来软件架构 DMSS 的升级。 AMSS源代码实际上是QC BREW(Binary Runtime Environment For Wireless)平台的的底层部分,去掉了为应用程序提供接口的AEE(application execution environment)部分,高通在Dual Proc芯片上的其他平台基本上都是采用的这样的架构。
参考文档:
微内核操作系统及L4概述
http://wenku.baidu.com/view/90929762caaedd3383c4d311.html
MSM平台上的AMSS
http://blog.csdn.net/yili_xie/archive/2010/01/04/5129469.aspx
1.2.2 选择合适的源代码以及工具
要编译出可供烧写使用的镜像文件需要三部分代码:
1) 获取经过高通打补丁的 android 源代码
2) 获取高通针对不同处理器的 vendor 源代码
3) 获取 modem 源代码
1.2.2.1 获取经过高通打补丁的android 源代码
网址:
https://www.codeaurora.org/wiki/QAEP#Branch_Releases
https://www.codeaurora.org/xwiki/bin/QAEP/eclair
https://www.codeaurora.org/xwiki/bin/QAEP/eclair_caramel
https://www.codeaurora.org/xwiki/bin/QAEP/froyo_almond
目前使用的 android 分支:
Android 2.1 版本 eclair
M7630AABBQMLZA1150 msm7630 eclair M7630AABBQMLZA1150.xml 2010年02月01日
M7630AABBQMLZA1200 msm7630 eclair M7630AABBQMLZA1200.xml 2010年03月30日
M7630AABBQMLZA2010 msm7630 éclair M7630AABBQMLZA2010.xml July 02, 2010
M7630AABBQMLZA1240 msm7630 eclair_caramel M7630AABBQMLZA1240.xml 2010年05月31日
M7630AABBQMLZA1250 msm7630 eclair_caramel M7630AABBQMLZA1250.xml 2010年06月15日
M7630AABBQMLZA1280 msm7630 eclair_caramel M7630AABBQMLZA1280.xml 2010年08月03日
M76XXTSNCJNLYA5340 msm7627 eclair_chocolate M76XXTSNCJNLYA5340.xml 2010年06月04
Android 2.2 版本 froyo
M7630AABBQMLZA2020 msm7630 froyo M7630AABBQMLZA2020.xml 2010年09月01
M76XXTSNCJNLYA6050 msm7627 froyo_almond M76XXTSNCJNLYA6050.xml 2010年10月29日
以下命令获取代码:
https://www.codeaurora.org/xwiki/bin/QAEP/froyo_almond
ac_root=/home/shared/qualcomm
ac_root=/mnt/shared/qualcomm/
ac_date=20101105
ac_branch=froyo_almond
build_id=M76XXTSNCJNLYA6050
ac_xml=M76XXTSNCJNLYA6050.xml
mkdir -pv $ac_root/$ac_branch-$build_id-$ac_date
cd $ac_root/$ac_branch-$build_id-$ac_date
repo init -u git://codeaurora.org/platform/manifest.git -b $ac_branch -m $ac_xml
nohup repo sync&
1.2.2.2 获取高通针对不同处理器的vendor源代码
根据选择的 Android 源代码分支不同, vendor 代码的选择也是不一样的,BUILD ID 必须一致
M7630AABBQMLZA1150 对应 HY11-VR881-5.zip
M7630AABBQMLZA1250 对应 HY11-VR881-11.zip
M7630AABBQMLZA2020 对应 HY11-N1627-3.zip AMSS 7X30 LINUX RELEASE 2.0.20
M76XXTSNCJNLYA6050 对应 HY11-N1188-6.zip AMSS 7X27 LINUX REL 6.0.50
vendor 代码通过有效的高通帐号登录 HYPERLINK "https://support.cdmatech.com/login/" https://support.cdmatech.com/login/ 网站获取
1.2.2.3 获取 modem 源代码
根据硬件配置情况,选择不同的 BUILD ID, 然后根据 BUILD ID 选择相近的源代码
modem 代码通过有效的高通帐号登录 HYPERLINK "https://support.cdmatech.com/login/" https://support.cdmatech.com/login/ 网站获取
BUILD ID 是一组字母的组合,如:AAABQOLYM
以下分别对各个字段进行说明:
第三个字母 A 表示 LPDDR2 #USES_LPDDR2=yes
第三个字母 B 表示 LPDDR1
第六个字母 M 表示 Multimode
第六个字母 C 表示 CDMA
第六个字母 D 表示 JCDMA #相对于C多了:USES_UMTS=yes USES_DSHDR_JCDMA_APIS=yes
第六个字母 O 表示 UMTS only #相对于C多了:USES_UMTS=yes USES_SUPPORT_UMTS_GPS_PROTOCOLS=yes
#相对于C少了:USES_CDMA=yes USES_HDR=yes USES_REL_C=yes USES_CDMA2000=yes
#USES_EXPORT_MCCMEID=yes USES_SUPPORT_CDMA_GPS_PROTOCOLS=yes
第7,8个字母为 AZ 表示 NADN boot
第7,8个字母为 LY 表示 eMMC boot #相对于AZ多了选项: USES_SDCC_BOOT=yes USES_HSU_MS_FD_BOOT=yes
最后一个字母为 M 表示 modem
最后一个字母为 A 表示 app
以上为 7x30 平台的一些规律,具体参考文档,7227 参考相应的 release note:
<<80-VR192-1_E_AMSS_Linux_Software_Users_Manual.pdf>>
第1个字母
第2个字母 F: 基于ffa参考设计 S: 基于surf的参考设计
第3个字母
第4个字母
第5个字母 K /J
K 相对于 J 多了以下选项
USES_HSU_CHG_BOOT=yes
USES_HSU_FAST_CHARGE=yes
USES_CHARGER=yes
USES_EBI1_TURBO_FFA=yes
第6个字母 O/ N / P
O表示只支持 UMTS(WCDMA)
------------------
USES_IPHC=yes
USES_PDCP=yes
USES_SUPPORT_UMTS_GPS_PROTOCOLS=yes
USES_UMTS=yes
-----------------
P表示只支持 CDMA/CDMA2000
USES_CDMA=yes
USES_CDMA2000=yes
USES_REL_C=yes
USES_SUPPORT_CDMA_GPS_PROTOCOLS=yes
USES_EXPORT_MCCMEID=yes
USES_HDR=yes
-----------------
N表示既支持 UMTS(WCDMA) 且支持 CDMA/CDMA2000
第7个字母
第8个字母
surf和ffa的区别
generally speaking surf have FPGA and don't have battery.
and FFA don't have FPGA but have battery.
msm7627_surf and msm7627_ffa and msm7627_7x_surf means different hardware reference design. please check with your hardware engineer on which qualcomm hardware reference you use and then select the right build command.
4.6 Build commands
To create an AMSS build, run the command script with the build ID matching the build
configuration desired. The command scripts may be executed from the build/ms subdirectory or
from the AMSS root directory using the full path to the command script as in the following
examples:
./AMSS/products/<asic>/build/ms/MSNCJNLYM.cmd – For SURF multimode build
./AMSS/products/<asic>/build/ms/MSNCJOLYM.cmd – For SURF UMTS only build
./AMSS/products/<asic>/build/ms/MSNCJPLYM.cmd – For SURF 1X only build
./AMSS/products/<asic>/build/ms/MFNCKNLYM.cmd – For FFA multimode and for reference only
以高通的开发板子为例,看如何选择源代码,通过 QPST 连接高通的开发板,我们可以看到他的配置信息如下:
高通 demo 版的配置情况:SURF-MSM7630 7X30A-AAABQMAZM-1200
从配置情况来看只有 HY11-N0216-3_1.2.00 HY11-N0216-4_1.2.20 满足要求
HY11-N0216-3_1.2.00/AMSS/products/7x30/build/ms/AAABQMAZM.cmd
HY11-N0216-4_1.2.20/AMSS/products/7x30/build/ms/AAABQMAZM.cmd
后期我们要跟据实际情况来选择 BUILD ID,如我们的手机的配置情况为:
LPDDR2 ,WCDMA,eMMC 启动(NAND备选),那么modem 的BUILD ID为:
AAABQOLYM 或者 AAABQOAZM
AAABQOLYM HY11-N0723-2_1.2.20/AMSS/products/7x30/build/ms/AAABQOLYM.cmd
AAABQOAZM HY11-N1122-1_1.2.20/AMSS/products/7x30/build/ms/AAABQOAZM.cmd (NABD boot 备选)
高通的Android第一人晓峰不建议我们第一次就用eMMC,而应该用Nand,目前只有HTC在用eMMC。高通在eMMC上面提供了参考代码,但是是未经过验证。终端厂商在使用过程中,一定会有很多问题需要自己解。
补充信息:
现在可能用到 BUILD ID 以及相应的 modem 和 vendor 源代码。
modem代码:
BUILD ID modem 源代码 modem镜像 说明文档
M7630AABBQMAZM1200 HY11-N0216-3.zip HK11-N0216-3.zip HT11-N0216-3.zip
M7630AABBQMAZM1220 HY11-N0216-4.zip HK11-N0216-4.zip HT11-N0216-4.zip
--
M7630AABBQMLYM1200 HY11-N0723-1.zip HK11-N0723-1.zip HT11-N0723-1.zip
M7630AABBQMLYM1220 HY11-N0723-2.zip HK11-N0723-2.zip HT11-N0723-2.zip
--
M7630AAABQCAZM1220 HY11-N1122-1.zip HK11-N1122-1.zip HT11-N1122-1.zip
M7630AAABQCAZM1240 HY11-N1122-2.zip HK11-N1122-2.zip HT11-N1122-2.zip
M7630AAABQCAZM1250 HY11-N1122-3.zip HK11-N1122-3.zip HT11-N1122-3.zip
M7630AAABQCAZM1260 HY11-N1122-4.zip HK11-N1122-4.zip HT11-N1122-4.zip
M7630AAABQCAZM1280 HY11-N1122-5.zip HK11-N1122-5.zip HT11-N1122-5.zip
M7630AAABQCAZM1290 HY11-N1122-6.zip HK11-N1122-6.zip HT11-N1122-6.zip
--
M7630AAABQMAZM1240 HY11-N1496-2.zip HK11-N1496-2.zip HT11-N1496-2.zip
M7630AAABQMAZM1250 HY11-N1496-3.zip HK11-N1496-3.zip HT11-N1496-3.zip
80-N0216-3_B_M7630AABBQMAZM1200.pdf
5.3.2.1 LPDDR1 NAND boot Multimode AABBQMAZM.cmd
5.3.2.2 LPDDR1 eMMC boot Multimode AABBQMLYM.cmd
5.3.2.3 LPDDR1 eMMC boot UMTS only AABBQOLYM.cmd
5.3.2.4 LPDDR1 NAND boot JCDMA AABBQDAZM.cmd
5.3.2.5 LPDDR2 NAND boot Multimode AAABQMAZM.cmd
5.3.2.6 LPDDR2 eMMC boot Multimode AAABQMLYM.cmd
80-N0216-4_A_M7630AABBQMAZM1220.pdf
5.3.2 Build instructions and commands
5.3.2.1 LPDDR1 NAND boot Multimode AABBQMAZM.cmd
5.3.2.2 LPDDR1 eMMC boot Multimode AABBQMLYM.cmd
5.3.2.3 LPDDR1 eMMC boot UMTS only AABBQOLYM.cmd
5.3.2.4 LPDDR1 NAND boot JCDMA AABBQDAZM.cmd
5.3.2.5 LPDDR2 NAND boot Multimode AAABQMAZM.cmd
5.3.2.6 LPDDR2 eMMC boot Multimode AAABQMLYM.cmd
5.3.2.7 LPDDR2 eMMC boot UMTS only AAABQOLYM.cmd
5.3.2.8 LPDDR2 NAND boot C2K Only AAABQCAZM.cmd
5.3.2.9 LPDDR1 eMMC boot C2K Only AABBQCLYM.cmd
5.3.2.10 LPDDR2 NAND boot JCDMA AAABQDAZM.cmd
5.3.2.11 LPDDR2 NAND boot UMTS only AAABQOAZM.cmd
80-N1665-1_B_M7630AAABQ_AZM1240.pdf
5.3.2 Build instructions and commands
5.3.2.1 LPDDR1/LPDDR2 eMMC boot Multimode AABBQMLYM.cmd
5.3.2.2 LPDDR1/LPDDR2 eMMC boot UMTS only AABBQOLYM.cmd
5.3.2.3 LPDDR1/LPDDR2 eMMC boot C2K only AABBQCLYM.cmd
5.3.2.4 LPDDR2/LPDDR1 NAND boot Multimode AAABQMAZM.cmd
5.3.2.5 LPDDR1/LPDDR2 NAND boot JCDMA AABBQDAZM.cmd
5.3.2.6 LPDDR2/LPDDR1 NAND boot C2K only AAABQCAZM.cmd
5.3.2.7 LPDDR2/LPDDR1 NAND boot UMTS only AAABQOAZM.cmd
The same build ID will now work for LPDDR1 as well as LPDDR2.
从以上的发布信息,只有 LPDDR2 和 LPDDR1 不同的情况下可以使用同一个 build ID。
对于我们的硬件配置情况(LPDDR2 eMMC boot UMTS only) 可以使用的编译命令文件为:
AAABQOLYM.cmd AABBQOLYM.cmd
选择 modem 代码 M7630AAABQMAZM1250 HK11-N1496-3.zip
如果是支持 BREW 平台,通常多下面的选项:
USES_BREW_4.0=yes
USES_BREW=yes
USES_BREW_APPMGR=yes
或者 USES_BREW_USB_HID=yes
没有 USES_DIAG_SMD_SUPPORT=yes
项目 PD1007
OEM/Target Equipment (FeaturePhone,Smartphone,Datacard): Smartphone
Anticipated Launch Date: April 1 2011
Target market (such as China Telecom): China Open market
Current Software (such as Q6270BKPRZL1505): froyo-M76XXTSNCJNLYA7010
Bluetooth IC/Module (vendor name and module if support BT): BTS4025
WLAN IC/Module (vendor and module if support WLAN ):WCN1312
Chipset (such as QSC6270):MSM7227-1
RF chipset (such as RGR6240):RTR6285
PMIC chipset (such as PM7540):PM7540
WCMDA Supported Bands (900,1900,2100…. if support WCDMA):2100
CMDA Supported Bands (450,850,1900,2100… if support CDMA ):not suport
OS (Brew,BMP,Android,WM,ThinUI(no UI)…):android froyo
OS version (Android Donuts…): android froyo
1.2.2.3.1 高通 modem 源代码编译前的修正
从高通获取的源代码直接编译会存在一些问题,以下为可能的问题以及解决方法:
1) 为相应的脚本加上编译选项
vim ./AMSS/products/7x30/build/ms/xxxxxx.cmd
加上: BUILD_UNIX=yes
2) 如果编译过程出现 .pl 文件没有执行权限而退出,那么为工程下面所有的 pl 文件加上可执行属性,命令:
find ./ -name "*.pl" |xargs chmod 755
3) 无法找到需要的 pl 脚本解析器
vim ./AMSS/products/7x30/tools/build/depgen.pl
修改
#!/pkg/perl/5.6.1/bin/perl -w
为
#!/usr/bin/perl -w
4) 如果出现错误: "AMSS/products/7x30/core/bsp/build/data/incpathsaaabqmlym.py", line 14
IndentationError: expected an indented block
修改文件:./AMSS/products/7x30/core/bsp/build/scripts/genpaths.pl 内容:
#if ($line =~ /^# makefile (from/)
为:
if ($line =~ /^# makefile /)
原因分析:
genpaths.pl 会对编译过程的中间信息 :
...
line=# makefile (from'incpaths.min',line 363)
line=QVPCODEC_AUDIOINC = $(QVPCODEC)/audio/inc
...
等信息进行解析,由于我们使用的是中文系统,所以以上内容变为:
line=# makefile (从'incpaths.min',行 363)
line=QVPCODEC_AUDIOINC = $(QVPCODEC)/audio/inc
所以导致:
#if ($line =~ /^# makefile (from/) 判断条件为为 false
无法正确生成 incpathsaaabqmlym.py,python 在解析该文件的时候认为存在语法错误。
在 modem 代码 M7630AABBQMAZM2020(HY11-N2280-2.zip)中开始使用 genincpaths.py 产生
./AMSS/products/7x30/core/bsp/build/data/incpathsaaabqoazm.py 文件,所以修改文件
amend-source-code-qualcomm-modem.sh 在脚本中需要加入以下内容:
incpathsxxx_py=$PRODUCT_DIR/core/bsp/build/scripts/genincpaths.py
if test -f $incpathsxxx_py; then
PERL=`which /usr/bin/perl`
sed -i "s/(from//g" $incpathsxxx_py
fi
./AMSS/products/7x30/multimedia/audio/drivers/Adie/AdieCodecDb/src/DALAdieCodecDb.c
#DalAdieCodecDbInternal.h 改为:
#include "DALAdieCodecDbInternal.h"
5) 如果出现 make: execvp: ../../../../platform/cs/bin/cifc: Permission denied 错误,执行以下命令:
chmod -R 755 AMSS/platform/cs/bin/*
1.2.3 建立 Android 开发环境
(略)
curl http://android.git.kernel.org/repo >~/bin/repo
chmod a+x ~/bin/repo
export PATH=~/bin:$PATH
1) 安装基本软件
sudo apt-get install git-core gnupg flex bison gperf build-essential zip curl sun-java5-jdk zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 lib32ncurses5-dev ia32-libs x11proto-core-dev libx11-dev lib32readline5-dev lib32z-dev
2) 安装 sun-java5-jdk
ubuntu 下通过命令: sudo apt-get install sun-java5-jdk 将会安装下面的包
sun-java5-bin sun-java5-demo sun-java5-jdk sun-java5-jre sun-java5-plugin
如果ubuntu 发布版本中没有 sun-java5-jdk 那么
sudo vim /etc/apt/source.list
#for sun-java5-jdk
deb http://us.archive.ubuntu.com/ubuntu/ jaunty multiverse
deb http://us.archive.ubuntu.com/ubuntu/ jaunty-updates multiverse
sudo apt-get update
sudo apt-get sun-java5-jdk
或者,如果 ubuntu 版中不支持 apt-get ,那么用手动安装:
sudo mount -t nfs 172.20.127.15:/home/shared /mnt
sudo dpkg -i /mnt/tools/debs/java-1.5.0-sun/sun-java5-*
3) 配置usb
cd /etc/udev/rules.d/
sudo vi 50-android.rules
# adb single interface device
SUBSYSTEM=="usb_device", SYSFS{idVendor}=="18d1", SYSFS{idProduct}=="d00d",
MODE="0664", GROUP="plugdev"
# adb composite interface device
SUBSYSTEM=="usb_device", SYSFS{idVendor}=="18d1", SYSFS{idProduct}=="deed",
MODE="0664", GROUP="plugdev"
# Sooner low-level bootloader
BUS=="usb", SYSFS{idVendor}=="0bb4", SYSFS{idProduct}=="0a51",
MODE="0664",GROUP="plugdev"
sudo /etc/init.d/udev restart
1.2.4 建立 modem 开发环境
与android 源代码不同,modem 编译工具使用的是 RVDS ,实际上只用到其中的 RVCT 编译器, 高通不提供该工具,我们必须从arm公司获取相应的授权,RVDS 是 ADS 的升级版本,从 ADS 1.2 开始到 RVDS 3.1 我们公司都有其授权,按照高通的要求我们目前必须使用 RVDS 2.2 并且使用他的 349 patch。
RVDS 2.2 安装以及使用步骤如下:
1). RVDS 2.2 共享在 172.20.127.15:/home/shared/ 目录
sudo mount -t nfs 172.20.127.15:/home/shared/ /mnt
cd /mnt/qualcommon/RVDS-2.2/
linux下rvds2.2的安装程序为:
./rvds2.2_linux-pentium/setuplinux.bin
执行以上命令,按照默认步骤安装,安装路径为:~/ARM
注意事项:
安装过程如果出现错误:
..................java.lang.UnsatisfiedLinkError: /tmp/ismp001/6073753.tmp: libstdc++-libc6.2-2.so.3:
cannot open shared object file: No such file or directory
从网上下载 libstdc++-libc6.2-2.so.3 拷贝到 /usr/lib 目录 ,或者从下面地址获取:
http://172.20.127.15/repositories/DocsAndTools/Tools/Qualcomm/RVDS-2.2-patch/patch/libstdc++-libc6.2-2.so.3
工具的安装通过脚本进行了简化,具体过程请参考文档:
80-N0216-2_A_M7630AABBQMAZM1170.pdf
80-VR881-7_B_M7630AABBQMLZA1200.pdf
80-VR192-1_C_AMSS_Linux_Software_Users_Guide.pdf
80-VR192-1_D_AMSS_Linux_Software_Users_Guide.pdf
2) 安装高通指定的 593 patch
cd /mnt/qualcommon/RVDS2.2/下执行命令:
./setup-patch-rvct2.2-bin593-lib349.sh
目前版本只支持 32 位的系统
1.2.4.1 补充
vim ./AMSS/products/7x30/core/bsp/build/scripts/defaults.py 定义了工作线程
#num_jobs = num_cpu * 2 modified by mhf
num_jobs = 2
if num_jobs < 4:
num_jobs = 2
if num_jobs > 8:
num_jobs = 8
env.SetOption('num_jobs', num_jobs)
―――――――
获取 RVDS
官方网站下载评估版本
https://silver.arm.com/browse
http://www.arm.com/products/tools/software-development-tools.php
https://silver.arm.com/download/eval_download.tm
https://silver.arm.com/userguides/Web_Licensing_Portal_User_Guide.pdf (Licensing 需要通过 host id 注册)
―――――――
1.2.4.1.1 获取 licenses
RVDS 的 licenses 从其官方网站获取
https://silver.arm.com/licensing/
https://silver.arm.com/licensing/generate.tm
http://www.keil.com/support/man/docs/license/license_sul_install.htm
入口 https://silver.arm.com/licensing/ 合法用户登录
用户名: mohuifu@gmail.com 密码: Mohuifu7737
入口 https://silver.arm.com/licensing/generate.tm 输入产品的序列号
然后按照步骤一步步操作即可
Server Host Id Type 类型选择 ETHERNET
Server Host Id 填写需要绑定主机的MAC地址 00:1a:64:0a:ba:70
最后保存 license.dat 文件,文本格式。
1.2.4.1.2 Flex 简单使用指南
FLEXlm是应用广泛的License管理工具,它以使软件License能够在网上浮动而出名。浮动的License有利于软件的使用和对 License的管理,这使得用户能够高效地使用有效的许可,并使管理者能够控制允许使用它的节点。由于有大约1500厂商使用FLEXle管理 lICENSE,所以CAD系统管理人员极有可能要同时安装和管理来自不同厂商的License或同一厂商多个产品的License文件。可采取以下方法避免产生冲突:
(1)用一个服务器运行一个Lmgrd(License文件的后台管理程序)和多个License文件;
(2)用一个服务器运行多个Lmgrd和License文件;
(3)运用多个服务器节点,每个服务器运行单独的Lmgrd和License文件。
第一种选择主要造用于高版本的Lmgrd,V6之前和FLEXlm,每个Lmgrd只能管理一个License文件;
第二种选择,将使用一台服务器,但需要运行多个Lmgrd;第三种选择,必须使用多个License服务器。
一、服务器端设定
1.License文件的设定
在使用FLEXlm进行管理的License文件中一般有SERVER行,它通过SERVER行的hostname和hostID定义License服务器。
SERVER this_host 0050BB0F402 27000
hostname hostID post
2.服务方式的选择
(1)一个服务器运行一个Lmgrd和多个License文件如果多个License文件具有相同的hostID,则可以通过修改hostname进行合并。合并时,首先将多个License文件加到一个文件中,然后修改SERVER行,并且只保留一个SERVER行。对于Windows NT操作系统,应在各License的默认位置保存一个合并后的备份,这样每个软件将在其默认位置找到License信息,从而避免了对 LM_LICENSE_FILE的设定;对于UNIX操作系统,可以建立一个默认位置到License存放位置和Link。合并后的License文件,就可以使用同一个Lmgrd。
(2)一个服务器运行一个Lmgrd和一个别License文件如果HostID不一样,则这些License服务只能运行于不同的服务器节点上,并且License不能合并。可以选择使用一个服务器运行一个Lmgrd和License文件。
(3)一个服务器运行多个Lmgrd和License文件如果多个License未进行合并,可以通过在同一台机器上启动多个Lmgrd,每个 Lmgrd管理一个License文件。使用多个Lmgrd管理多个License文件对服务器的性能并没有明显影响。如果License是由不同版本的 FLEXlm产生的,一般是新版本可以管理旧版本的License文件。所以应使用最新的Lmgrd和Vendor daemon。另外,当用一个服务器的多个Lmgrd管理多个License文件时,应该注意任何二个License文件的post都不能一样,并且对于每个License而言,应选用合造的Lmgrd。
二、客户端设定
当使用客户端应用程序时(a Licensedapplication),可以通过在系统的环境变量中设定LM_LICENSE_FILE,使Application能够指向不同服务器上的License文件。如果要使a Licensed application使用不同服务器都有单独的一个License文件),客户端应将需要用到的License文件拷贝到本机目录下,并指定LM_LICENSE_FILE环境变量。UNIX: %setenv LM_LICENSE_FILE lfpath1 : lfpath2 :…… : lfpathN Windows: lfpath1 ;lfpath2:…… ;lfpathN LfpathN为第N个License的路径;UNIX下路径间用":"隔开;Windows/NT下路径间使用";"隔开;
这样,每个Licensed aplication在启动时将依次查询LM_LICENSE_FILE中所指定的License文件,并向相应的License服务器申请许可,以使用户能从所列的服务器得到许可。LM_LICENSE_FILE也可以使用各License文件中所指定的"post@hostname"。下面以Windows NT为例介绍多个FLEXlm的安装。
三、同一机器上多个FLEXlm License Server的安装
(1) 以Administrator身分登录;
(2)在C盘建C:FLEXlm目录,并拷贝相关文件到其下;
(3)在C:FLEXlm下建立欲安装License Server的软件目录,放置各软件的License文件,Daemon和Daemon所需的动态连接库;
(4)修改License.dat和SERVER行和DAEMON的位置,并启动FLEXlm License Manager。
(5)在Setup修改Service Name,输入造当名称,以区别是何种License服务;利用Browse选择合适Lmgrd.exe和对应和License.dat并指定Debug.log和放置路径;
(6)选中"StartServer at Power-Up"与"Use NT Services",这样下次启动机器时,将自动启动该Li-cense服务;
(7)点击Control按钮检查Service Name是否与设定名称相同,如果不同,回到"Setup"重新选择Service Name;如果一样,点击"Start"启动该Li-cense Server;点击"Status"检查Licevse Server启动情况,若出现Server_name: License server UP (MASTER),表示License Server启动成功;
(8)安装另外的License Server:可依上述(3)~(7)重新执行一次即可;
(9)切换不同License Server:在"Setup"中选择适当的"Service Name",然后启动或停止相应的License服务;
(10)移除License Server:在"Setup"选择适当的"Service Name",然后按"Remove"即可。
1.2.4.1.3 启动 license 服务器
#!/bin/bash
ac_PATH=~/ARM/Utilities/FLEXlm/9.2/release/linux-pentium/
PATH=${ac_PATH}:${PATH}
export PATH
LICENSE_FILE=~/ARM/licenses/license.dat
LOG=~/ARM/licenses/license.log
case "$1" in
start)
lmgrd -c ${LICENSE_FILE} 2>> ${LOG} 1>&2
echo -n " lmgrd"
;;
stop)
ac_pid=`pidof lmgrd`
kill $ac_pid 2>> ${LOG} 1>&2
ac_pid=`pidof armlmd`
kill $ac_pid 2>> ${LOG} 1>&2
#lmgrd -c ${LICENSE_FILE} -x lmdown 2>> ${LOG} 1>&2
;;
*)
echo "Usage: `basename $0` {start|stop}" 1>&2
exit 64
;;
esac
1.2.4.1.4 license 没有办法从服务器获取的几种情况
1.需要关闭网络防火墙
2.在客户端需要配置license服务器的服务端口
3.要求在同一个局域网内
sudo ufw disable
防火墙在系统启动时自动禁用
sudo iptables -A OUTPUT -p tcp --dport 8224 -j ACCEPT
修改/etc/sysconfig/iptables 文件,添加以下内容:
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 23 -j ACCEPT
1.2.4.1.5 破解 rvds 的license
第 1 章 欢迎使用 FLEXlm
在linux下创建一个虚拟网卡
http://nxjsjx.com/cgl/%E8%BD%AF%E4%BB%B6/%E5%A4%9A%E5%AA%92%E4%BD%93%E5%88%B6%E4%BD%9C%E8%BD%AF%E4%BB%B6/flash/Autocad%202002/Netsetup/support/AdLM/Docs/FlexUser/all.htm#895035
1.2.5 在高通开发板上烧录文件系统
通过设置模块完成系统,应用程序等个性化设置。
烧录之前必须了解获取硬件配置情况
2. 由硬件配置情况到高通网站选择相应的镜像文件
3. 烧录镜像文件到高通demo开发板
4. 从高通网站下载源代码编译相应的镜像文件进行验证
1. 烧录之前必须了解获取硬件配置情况
高通 demo 板的配置情况:SURF-MSM7630 7X30A-AAABQMBZM-1090 或者 7X30A-AAABQMAZM-1200
以上信息可以通过 QPST 连接高通的demo开发板获得
2. 由硬件配置情况到高通网站选择相应的镜像文件
要给高通的开发板烧录文件系统,必须有以下的镜像文件:
adsp.mbn dsp相关的
amss.mbn AMSS modem binary image
dbl.mbn 设备启动的装载程序
osbl.mbn OS boot loader binary image
partition.mbn 分区表的二进制文件
appsboot.mbn 应用程序的启动文件,如果是 eMMC 启动对应文件 emmc_appsboot.mbn
boot.img ap 端的linux 内核
system.img android 文件系统的 system 分区
userdata.img android 文件系统的 data 分区
其中 adsp.mbn,amss.mbn,dbl.mbn,osbl.mbn,partition.mbn 可以从以下目录获取
unzip /home/shared/qualcommon/HK11-N0216-3.zip
unzip /home/shared/qualcommon/HK11-N0216-4.zip
HK11-N0216-3_1.2.00/AAABQMAZ/
HK11-N0216-4_1.2.20/AAABQMAZ/
appsboot.mbn,boot.img,system.img,userdata.img 必须来自eclair源代码
3. 烧录镜像文件到高通demo开发板
怎样烧写文件请参考工具使用文档
通过fastboot烧写 boot.img syste.img usrdata.img
参考文档:
80-VR192-1_D_AMSS_Linux_Software_Users_Guide.pdf
6.2 USB setup in Linux
6.2.1 Using Fastboot in Linux
4. 从高通网站下载源代码编译相应的镜像文件进行验证
高通有两个cpu,他们分别跑不同的系统,应用程序(ap)端是android系统,modem 端是高通自己的系统。
======
android 系统目前使用的是 eclair 版本,此版本来自标准的 android 2.1 eclair,高通在上面加了自己的补丁,代码网址:
https://www.codeaurora.org/wiki/QAEP#Branch_Releases
https://www.codeaurora.org/wiki/QLBEP
下载 M7630AABBQMLZA1150 分支:
February 1, 2010 M7630AABBQMLZA1150 msm7630 eclair M7630AABBQMLZA1150.xml
命令如下:
mkdir -pv ~/workspace/gphone/eclair-M7630AABBQMLZA1150-20100201
cd ~/workspace/gphone/eclair-M7630AABBQMLZA1150-20100201
repo init -u git://codeaurora.org/platform/manifest.git -b eclair -m M7630AABBQMLZA1150.xml
nohup repo sync
代码下的 vendor/qcom-proprietary 来自包 HY11-VR881-5.zip
以上两部分代码已经下载并且合并,共享在:
http://172.20.127.15/repositories/TD1002/trunk/eclair-M7630AABBQMLZA1150
---------------
编译 eclair 代码
svn co http://172.20.127.15/repositories/TD1002/trunk/eclair-M7630AABBQMLZA1150
cd eclair-M7630AABBQMLZA1150
cd eclair-M7630AABBQMLZA1150$
. ./setenv.sh
. ./make-image.sh
=======
modem代码从高通网站:https://support.cdmatech.com/login/ 上获取
我们目前使用的是:
共享在:
http://172.20.127.15/repositories/TD1002/trunk/modem-M7630AABBQMAZM1220
-------
编译 modem 代码
svn co http://172.20.127.15/repositories/TD1002/trunk/modem-M7630AABBQMAZM1220
cd modem-M7630AABBQMAZM1220
. ./setenv-qualcomm.sh
. ./make
========
编译结果分别如下:
------------
其中 adsp.mbn,amss.mbn,dbl.mbn,osbl.mbn,partition.mbn 位于以下目录:
./modem-M7630AABBQMAZM1220/AMSS/products/7x30/build/ms/bin/AAABQMAZ/adsp.mbn
./modem-M7630AABBQMAZM1220/AMSS/products/7x30/build/ms/bin/AAABQMAZ/amss.mbn
./modem-M7630AABBQMAZM1220/AMSS/products/7x30/build/ms/bin/AAABQMAZ/dbl.mbn
./modem-M7630AABBQMAZM1220/AMSS/products/7x30/build/ms/bin/AAABQMAZ/osbl.mbn
./modem-M7630AABBQMAZM1220/AMSS/products/7x30/build/ms/bin/AAABQMAZ/partition.mbn
------------
appsboot.mbn,boot.img,system.img,userdata.img 位于以下目录:
./eclair-M7630AABBQMLZA1150/out/target/product/msm7630_surf/appsboot.mbn
./eclair-M7630AABBQMLZA1150/out/target/product/msm7630_surf/boot.img
./eclair-M7630AABBQMLZA1150/out/target/product/msm7630_surf/system.img
./eclair-M7630AABBQMLZA1150/out/target/product/msm7630_surf/userdata.img
./eclair-M7630AABBQMLZA1150/out/target/product/msm7630_surf/system.img.ext3
./eclair-M7630AABBQMLZA1150/out/target/product/msm7630_surf/userdata.img.ext3
------------
eMMC 启动使用的是 ext3 文件系统,需要使用镜像 system.img.ext3 userdata.img.ext3
补充说明:
partition.mbn 文件的原始数据来自配置文件:
./AMSS/products/7x30/tools/jsdcc/partition_load_pt/partition.xml
1.3 高通平台,android和 modem 编译流程分析
android 代码编译流程分析
modem 代码编译流程分析
1.3.1 android代码编译流程分析
1. 从服务器下载 android 源码到当前目录
http://smartphone/repositories/TD1014/branch/froyo_almond-M76XXTSNCJNLYA6050-drivers/
svn co http://172.20.127.15/repositories/TD1014/trunk/froyo_almond-M76XXTSNCJNLYA6050/
cd froyo_almond-M76XXTSNCJNLYA6050/
. ./setenv.sh 设置环境变量
Setting Environment ...
通常情况下 generic 用于编译模拟器版本
Options are:
1. generic
2. msm7627_surf
3. msm7627_ffa
4. tiny-system
====从以上列表中选择====
Which would you like? [1]
烧录的镜像文件appsboothd.mbn appsboot.mbn boot.img system.img userdata.img persist.img 来自 android 源码
appsboot.mbn 的主要功能是装载 linux 内核,通过 linux 的引导来完成 android 系统的加载,
appsboot.mbn 被烧写在相应的分区,它的加载由 osbl.mbn 来完成, osbl.mbn 程序来自 modem。
7x30 7x27 系列 appsboot 不一样,7x30 的 appsboot.mbn 是 7x27 appsboothd.mbn appsboot.mbn 两个文件的合并
1) appsboot.mbn 生成过程解析
2) boot.img 生成过程解析,怎样手动生成 boog.img
1.3.1.1 编译工具检测
make out/target/product/msm7630_surf/appsboot.mbn
1.3.1.1.1
1.3.1.2 appsboot.mbn 生成过程解析
make out/target/product/msm7630_surf/appsboot.mbn
make out/target/product/msm7630_surf/nandwrite
make out/target/product/msm7630_surf/emmc_appsboot.mbn
分别执行:
make -C bootable/bootloader/lk BOOTLOADER_OUT=../../.././out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ msm7630_surf
make -C bootable/bootloader/lk BOOTLOADER_OUT=../../.././out/target/product/msm7630_surf/obj/nandwrite msm7630_surf_nandwrite BUILD_NANDWRITE=1
make -C bootable/bootloader/lk BOOTLOADER_OUT=../../.././out/target/product/msm7630_surf/obj/BOOTLOADER_EMMC_OBJ msm7630_surf EMMC_BOOT=1
生成 nandwrite
===============
#build nandwrite as a part of Android Build
TARGET_NANDWRITE := $(PRODUCT_OUT)/obj/nandwrite/build-$(TARGET_PRODUCT)_nandwrite/lk
NANDWRITE_OUT := $(TOP)/$(TARGET_OUT_INTERMEDIATES)/nandwrite
nandwrite_clean:
$(hide) rm -f $(TARGET_NANDWRITE)
$(hide) rm -rf $(NANDWRITE_OUT)
$(NANDWRITE_OUT):
mkdir -p $(NANDWRITE_OUT)
$(TARGET_NANDWRITE): nandwrite_clean $(NANDWRITE_OUT)
@echo $(TARGET_PRODUCT)_nandwrite
$(MAKE) -C bootable/bootloader/lk BOOTLOADER_OUT=../../../$(NANDWRITE_OUT) $(TARGET_PRODUCT)_nandwrite BUILD_NANDWRITE=1
================
vim ./bootable/bootloader/lk/makefile:98:
TARGET := msm7630_surf #./bootable/bootloader/lk/project/msm7630_surf.mk
PLATFORM := msm7x30 #./bootable/bootloader/lk/target/msm7630_surf/rules.mk
msm7x30
msm7630_surf.mk
msm7630_surf_nandwrite
=============================
include project/$(PROJECT).mk
include target/$(TARGET)/rules.mk
include target/$(TARGET)/tools/makefile
include platform/$(PLATFORM)/rules.mk
include arch/$(ARCH)/rules.mk
include platform/rules.mk
include target/rules.mk
include kernel/rules.mk
include dev/rules.mk
include app/rules.mk
...
include make/module.mk
...
include make/build.mk
========================
vim bootable/bootloader/lk/make/module.mk
INCMODULES := $(MODULES)
$(info including $(INCMODULES))
include $(addsuffix /rules.mk,$(INCMODULES))
展开为:
./bootable/bootloader/lk/app/nandwrite/rules.mk
./bootable/bootloader/lk/dev/fbcon/rules.mk
./bootable/bootloader/lk/dev/keys/rules.mk
./bootable/bootloader/lk/lib/debug/rules.mk
./bootable/bootloader/lk/lib/heap/rules.mk
./bootable/bootloader/lk/lib/libc/rules.mk
./bootable/bootloader/lk/lib/ptable/rules.mk
========================
bootable/bootloader/lk/make/build.mk:29:
include arch/$(ARCH)/compile.mk
./bootable/bootloader/lk/project/msm7630_surf_nandwrite.mk 中有:
MODULES += app/nandwrite
./bootable/bootloader/lk/platform/msm7x30/rules.mk中有:
MODULES += dev/fbcon
./bootable/bootloader/lk/kernel/rules.mk 中有:
MODULES += lib/libc lib/debug lib/heap
./bootable/bootloader/lk/target/msm7630_surf/rules.mk 中有:
MODULES += dev/keys lib/ptable
所以:
MODULES= app/nandwrite dev/fbcon dev/keys lib/debug lib/heap lib/libc lib/ptable
因为
ifeq ($(BUILD_NANDWRITE), 1)
APPSBOOTHDR_FILES :=
else
out/host/linux-x86/bin/acp -fpt out/target/product/msm7630_surf/obj/nandwrite/build-msm7630_surf_nandwrite/lk out/target/product/msm7630_surf/nandwrite
25780 184 34000 59964 ea3c ../../.././out/target/product/msm7630_surf/obj/nandwrite/build-msm7630_surf_nandwrite/lk
arm-eabi-objcopy -O binary ../../.././out/target/product/msm7630_surf/obj/nandwrite/build-msm7630_surf_nandwrite/lk ../../.././out/target/product/msm7630_surf/obj/nandwrite/build-msm7630_surf_nandwrite/lk.bin
generating listing: ../../.././out/target/product/msm7630_surf/obj/nandwrite/build-msm7630_surf_nandwrite/lk.lst
generating listing: ../../.././out/target/product/msm7630_surf/obj/nandwrite/build-msm7630_surf_nandwrite/lk.debug.lst
generating symbols: ../../.././out/target/product/msm7630_surf/obj/nandwrite/build-msm7630_surf_nandwrite/lk.sym
generating size map: ../../.././out/target/product/msm7630_surf/obj/nandwrite/build-msm7630_surf_nandwrite/lk.size
make[2]:正在离开目录 /opt/workspace/gphone/qualcomm/eclair-M7630AABBQMLZA1150/bootable/bootloader/lk
make[1]:正在离开目录 /opt/workspace/gphone/qualcomm/eclair-M7630AABBQMLZA1150/bootable/bootloader/lk
target Prebuilt: (out/target/product/msm7630_surf/nandwrite)
make -C bootable/bootloader/lk BOOTLOADER_OUT=./out/target/product/msm7630_surf/obj/nandwrite msm7630_surf_nandwrite BUILD_NANDWRITE=1
make[2]: 正在进入目录 `/opt/workspace/gphone/qualcomm/eclair-M7630AABBQMLZA1150/bootable/bootloader/lk`
msm7630_surf_nandwrite
make -C bootable/bootloader/lk BOOTLOADER_OUT=../../.././out/target/product/msm7630_surf/obj/nandwrite msm7630_surf_nandwrite BUILD_NANDWRITE=1
==》生成 mkheader 工具
gcc target/msm7630_surf/tools/mkheader.c -o target/msm7630_surf/tools/mkheader
$(BUILDDIR)/system-onesegment.ld: $(LOCAL_DIR)/system-onesegment.ld
@echo generating $@
@$(MKDIR)
$(NOECHO)sed "s/%MEMBASE%/$(MEMBASE)/;s/%MEMSIZE%/$(MEMSIZE)/" < $< > $@
generating ../../.././out/target/product/msm7630_surf/obj/nandwrite/build-msm7630_surf_nandwrite/system-onesegment.ld
compiling arch/arm/crt0.S
compiling arch/arm/crt0.S
。。。compiling lib/ptable/ptable.c
compiling lib/ptable/ptable.c
vim bootable/bootloader/lk/platform/msm7x30/rules.mk
-----
LINKER_SCRIPT += $(BUILDDIR)/system-onesegment.ld
include platform/msm_shared/rules.mk
-----
./build/core/product_config.mk:177:TARGET_DEVICE := $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_DEVICE)
./build/core/envsetup.mk:152:OUT_DIR := $(TOPDIR)out
./build/core/envsetup.mk:159:TARGET_OUT_ROOT_release := $(OUT_DIR)/target
./build/core/envsetup.mk:161:TARGET_OUT_ROOT := $(TARGET_OUT_ROOT_$(TARGET_BUILD_TYPE))
./build/core/envsetup.mk:178: TARGET_PRODUCT_OUT_ROOT := $(TARGET_OUT_ROOT)/product
./build/core/envsetup.mk:184:PRODUCT_OUT := $(TARGET_PRODUCT_OUT_ROOT)/$(TARGET_DEVICE)
build/core/envsetup.mk:200:TARGET_OUT_INTERMEDIATES := $(PRODUCT_OUT)/obj
bootable/bootloader/lk/AndroidBoot.mk:4:BOOTLOADER_OUT := $(TOP)/$(TARGET_OUT_INTERMEDIATES)/BOOTLOADER_OBJ
bootable/bootloader/lk/makefile:32:BUILDDIR := $(BOOTLOADER_OUT)/build-$(PROJECT)
bootable/bootloader/lk/makefile:34:OUTELF := $(BUILDDIR)/lk
所以:
TARGET_PRODUCT_OUT_ROOT=out/target/product/
PRODUCT_OUT=out/target/product/msm7630_surf/
TARGET_OUT_INTERMEDIATES=out/target/product/msm7630_surf/obj/
BOOTLOADER_OUT=out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/
所以:
BUILDDIR=out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf
所以:
OUTELF=out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk
make -C bootable/bootloader/lk BOOTLOADER_OUT=../../.././out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ msm7630_surf
bootable/bootloader/lk/makefile
OUTELF := $(BUILDDIR)/lk
./bootable/bootloader/lk/make/build.mk
$(OUTELF): $(ALLOBJS) $(LINKER_SCRIPT)
@echo linking $@
$(NOECHO)$(LD) $(LDFLAGS) -T $(LINKER_SCRIPT) $(ALLOBJS) $(LIBGCC) -o $@
vim ./bootable/bootloader/lk/AndroidBoot.mk
TARGET_NANDWRITE := $(PRODUCT_OUT)/obj/nandwrite/build-$(TARGET_PRODUCT)_nandwrite/lk
$(TARGET_NANDWRITE): nandwrite_clean $(NANDWRITE_OUT)
@echo $(TARGET_PRODUCT)_nandwrite
$(MAKE) -C bootable/bootloader/lk BOOTLOADER_OUT=../../../$(NANDWRITE_OUT) $(TARGET_PRODUCT)_nandwrite BUILD_NANDWRITE=1
BOOTLOADER_EMMC_OUT := $(TOP)/$(TARGET_OUT_INTERMEDIATES)/BOOTLOADER_EMMC_OBJ
vim ./bootable/bootloader/lk/make/build.mk
$(OUTELF): $(ALLOBJS) $(LINKER_SCRIPT)
@echo linking $@
$(NOECHO)$(LD) $(LDFLAGS) -T $(LINKER_SCRIPT) $(ALLOBJS) $(LIBGCC) -o $@
bootable/bootloader/lk/makefile:33:OUTBIN := $(BUILDDIR)/lk.bin
bootable/bootloader/lk/makefile:34:OUTELF := $(BUILDDIR)/lk
./lk/platform/msm7x30/rules.mk:23:LINKER_SCRIPT += $(BUILDDIR)/system-onesegment.ld
==》链接 lk
linking ../../.././out/target/product/msm7630_surf/obj/nandwrite/build-msm7630_surf_nandwrite/lk
linking ../../.././out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk
generating image: ../../.././out/target/product/msm7630_surf/obj/nandwrite/build-msm7630_surf_nandwrite/lk.bin
generating image: ../../.././out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk.bin
text data bss dec hex filename
29592 7388 42720 79700 13754 ../../.././out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk
text data bss dec hex filename
25780 184 34000 59964 ea3c ../../.././out/target/product/msm7630_surf/obj/nandwrite/build-msm7630_surf_nandwrite/lk
==》以 binary 格式,把文件 out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk 输出到:
out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk.bin
arm-eabi-objcopy -O binary out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk.bin
==》
生成... out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk.lst
生成... out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk.debug.lst
生成... out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk.sym
生成... out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk.size
make[1]:正在离开目录 /opt/workspace/gphone/qualcomm/eclair-M7630AABBQMLZA1150/bootable/bootloader/lk
==》
make -C kernel O=../out/target/product/msm7630_surf/obj/KERNEL_OBJ ARCH=arm CROSS_COMPILE=arm-eabi- msm7630-perf_defconfig
make[1]: 正在进入目录 /opt/workspace/gphone/qualcomm/eclair-M7630AABBQMLZA1150/kernel
generating symbols: ../../.././out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk.sym
generating size map: ../../.././out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk.size
mkheader 从 lk.bin 生成 appsboothd.mbn 语法: mkheader <bin> <hdr>
然后把 appsboothd.mbn 和 lk.bin 合并为文件 appsboot.mbn,删除 appsboothd.mbn 文件
appsboothd.mbn 大小 40K
./bootable/bootloader/lk/target/msm7630_surf/tools/mkheader out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk.bin out/target/product/msm7630_surf/appsboothd.mbn
合并 out/target/product/msm7630_surf/appsboothd.mbn out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk.bin 为:
out/target/product/msm7630_surf/appsboot.mbn
cat out/target/product/msm7630_surf/appsboothd.mbn out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk.bin > out/target/product/msm7630_surf/appsboot.mbn
删除:out/target/product/msm7630_surf/appsboothd.mbn
==================================================
1.3.1.3 boot.img 生成过程解析,怎样手动生成 boog.img
boot.img 包括两个部分: kernel 和 ramdisk ,通过命令:
make out/target/product/msm7630_surf/boot.img showcommands
会自动生成 kernel 和 ramdisk,然后把两者合并制作成烧写的镜像文件:boot.img
kernel 为 out/target/product/$TARGET_PRODUCT/obj/KERNEL_OBJ/arch/arm/boot/zImage
或者 out/target/product/$TARGET_PRODUCT/kernel , kernel 是 zImage 的拷贝
编译内核之前必须获取一个默认的配置文件 .config ,此配置文件可以生成,或者来自默认配置,高通中 msm7630_surf 的
默认配置文件名为: msm7630-perf_defconfig 在文件:
vendor/qcom/msm7630_surf/AndroidBoard.mk:45 中通过:
KERNEL_DEFCONFIG := msm7630-perf_defconfig 进行了指定。
我们可以通过命令:
make -j3 ARCH=arm CROSS_COMPILE=arm-eabi- kernel showcommands
或者通过如下命令一步步完成:
1. 获取默认的内核配置并生成.config 的命令如下:
make -C kernel O=../out/target/product/msm7630_surf/obj/KERNEL_OBJ ARCH=arm CROSS_COMPILE=arm-eabi- msm7630-perf_defconfig
-C kernel 告诉 make 进入 kernel 工作目录,到其下面寻找 makefile 文件
O 内核编译的中间文件以及编译结果等都存储在该目录下,此做法的好处是不会在kernel源代码目录下生成垃圾文件
ARCH=arm 告诉系统到 ./kernel/arch/$ARCH/configs/ 目录下找文件 msm7630-perf_defconfig,生成的.config 保存在:
out/target/product/msm7630_surf/obj/KERNEL_OBJ/.config
2. 手动编译内核
make -C kernel O=../out/target/product/msm7630_surf/obj/KERNEL_OBJ/
3. 如果需要配置内核,使用下面的命令
make kernelconfig
他首先会进入 menuconfig 界面,用户配置完成以后,会把修改后的配置文件$(KERNEL_OUT)/.config 更新为默认的配置文件
cp out/target/product/msm7627_ffa/obj/KERNEL_OBJ/.config kernel/arch/arm/configs/msm7627-perf_defconfig
kernel/arch/arm/configs/$(KERNEL_DEFCONFIG)
4. 手动生成 ramdisk 执行命令
make out/target/product/msm7630_surf/ramdisk.img showcommands
会用到命令:
out/host/linux-x86/bin/mkbootfs out/target/product/msm7630_surf/root | out/host/linux-x86/bin/minigzip >
out/target/product/msm7630_surf/ramdisk.img
5. 手动生成 boot.img 需要使用命令 mkbootimg ,语法如下:
mkbootimg --kernel 内核 --ramdisk ramdisk镜像 --cmdline 命令行 --base 基地址 --pagesize 大小 --output 输出的boot.img
==========
KERNEL=out/target/product/$TARGET_PRODUCT/kernel
KERNEL=out/target/product/$TARGET_PRODUCT/obj/KERNEL_OBJ/arch/arm/boot/zImage
RAMDISK=out/target/product/$TARGET_PRODUCT/ramdisk.img
CMDLINE="console=ttyDCC0 androidboot.hardware=qcom"
BASE=0x00200000
PAGESIZE=4096
OUTPUT=out/target/product/$TARGET_PRODUCT/boot.img
out/host/linux-x86/bin/mkbootimg --kernel $KERNEL --ramdisk $RAMDISK --cmdline "$CMDLINE" --base $BASE --pagesize $PAGESIZE --output $OUTPUT
=========================================
编译 bootloader (appsboot.mbn) ,nandwrite 生成过程解析
./vendor/qcom/msm7630_surf/AndroidBoard.mk:25:
include bootable/bootloader/lk/AndroidBoot.mk
===================
因为有:
bootable/bootloader/lk/AndroidBoot.mk:3:
TARGET_BOOTLOADER := $(PRODUCT_OUT)/appsboot.mbn
INSTALLED_BOOTLOADER_TARGET := $(PRODUCT_OUT)/bootloader
file := $(INSTALLED_BOOTLOADER_TARGET)
ALL_PREBUILT += $(file)
$(file): $(TARGET_BOOTLOADER) | $(ACP)
$(transform-prebuilt-to-target)
所以拷贝:
out/target/product/msm7630_surf/appsboot.mbn
为:
out/target/product/msm7630_surf/bootloader
====================
因为有:
./bootable/bootloader/lk/AndroidBoot.mk:38:
TARGET_NANDWRITE := $(PRODUCT_OUT)/obj/nandwrite/build-$(TARGET_PRODUCT)_nandwrite/lk
# Copy nandwrite utility to target out directory
INSTALLED_NANDWRITE_TARGET := $(PRODUCT_OUT)/nandwrite
file := $(INSTALLED_NANDWRITE_TARGET)
ALL_PREBUILT += $(file)
$(file) : $(TARGET_NANDWRITE) | $(ACP)
$(transform-prebuilt-to-target)
endif
所以拷贝:
out/target/product/msm7630_surf/obj/nandwrite/build-msm7630_surf_nandwrite/lk
为:
out/target/product/msm7630_surf/nandwrite
=====================
编译内核:
#----------------------------------------------------------------------
# Compile Linux Kernel
#----------------------------------------------------------------------
ifeq ($(KERNEL_DEFCONFIG),)
KERNEL_DEFCONFIG := msm7630-perf_defconfig
endif
include kernel/AndroidKernel.mk
======================
编译 appsboot.mbn
源代码位于: bootable/bootloader/lk/
因为:
vendor/qcom/msm7630_surf/BoardConfig.mk:60:
TARGET_USERIMAGES_USE_EXT2 := true
所以:分别编译支持nand 和 emmc启动的 appsboot.mbn
===================
bootable/bootloader/lk/AndroidBoot.mk
$(TARGET_BOOTLOADER): appsbootldr_clean emmc_appsbootldr_clean $(BOOTLOADER_OUT) $(BOOTLOADER_EMMC_OUT)
$(MAKE) -C bootable/bootloader/lk BOOTLOADER_OUT=../../../$(BOOTLOADER_OUT) $(TARGET_PRODUCT)
$(MAKE) -C bootable/bootloader/lk BOOTLOADER_OUT=../../../$(BOOTLOADER_EMMC_OUT) $(TARGET_PRODUCT) EMMC_BOOT=1
$(TARGET_NANDWRITE): nandwrite_clean $(NANDWRITE_OUT)
@echo $(TARGET_PRODUCT)_nandwrite
$(MAKE) -C bootable/bootloader/lk BOOTLOADER_OUT=../../../$(NANDWRITE_OUT) $(TARGET_PRODUCT)_nandwrite BUILD_NANDWRITE=1
====================
-C 表明到目录 bootable/bootloader/lk 下找 makfile 文件
bootable/bootloader/lk/makefile
====================
bootable/bootloader/lk/makefile:87:
include target/$(TARGET)/tools/makefile
bootable/bootloader/lk/target/msm7630_surf/tools/makefile
====================
appsboot.mbn: appsboothd.mbn $(OUTBIN)
cat $(APPSBOOTHEADER_DIR)/appsboothd.mbn $(OUTBIN) > $(APPSBOOTHEADER_DIR)/appsboot.mbn
rm -f $(APPSBOOTHEADER_DIR)/appsboothd.mbn
appsboothd.mbn: mkheader $(OUTBIN)
$(SRC_DIR)/mkheader $(OUTBIN) $(APPSBOOTHEADER_DIR)/appsboothd.mbn
========================================
hexdump out/target/product/msm7630_surf/appsboothd.mbn
40个字节的内容如下:
-----
0000000 0005 0000 0002 0000 0000 0000 0000 0000
0000010 9074 0000 9074 0000 9074 0000 0000 0000
0000020 9074 0000 0000 0000
0000028
-----
我们编译的:
0000000 0005 0000 0002 0000 0000 0000 0000 0000
0000010 9074 0000 9074 0000 9074 0000 0000 0000
0000020 9074 0000 0000 0000
高通的:
0000000 0005 0000 0002 0000 0000 0000 0000 0010
0000010 99ac 0000 99ac 0000 99ac 0010 0000 0000
0000020 99ac 0010 0000 0000
We found that the contents of the first 40 bytes is not the same
hexdump out/target/product/msm7630_surf/appsboot.mbn > bbk.txt
hexdump ~/appsboot.mbn > qualcomm > qualcomm.txt (appsboot.mbn from Qualcomm, can properly programmed system.img)
the first 40 bytes below:
Content from the compilation:
0000000 0005 0000 0002 0000 0000 0000 0000 0000
0000010 9074 0000 9074 0000 9074 0000 0000 0000
0000020 9074 0000 0000 0000
Content from the Qualcomm:
0000000 0005 0000 0002 0000 0000 0000 0000 0010
0000010 99ac 0000 99ac 0000 99ac 0010 0000 0000
0000020 99ac 0010 0000 0000
========
Analysis of the generation of appsboot.mbn,from the command:
cat out/target/product/msm7630_surf/appsboothd.mbn out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk.bin > out/target/product/msm7630_surf/appsboot.mbn
we known ,appsboot.mbn consists of two parts: appsboothd.mbn and lk.bin;
appsboothd.mbn come form command:
./bootable/bootloader/lk/target/msm7630_surf/tools/mkheader out/target/product/msm7630_surf/obj/BOOTLOADER_OBJ/build-msm7630_surf/lk.bin out/target/product/msm7630_surf/appsboothd.mbn
1.3.1.4 编译过程存在的问题
1.3.1.4.1 prelinkmap 的时候 base 0xaff00000 out of range
build/tools/apriori/prelinkmap.c(100): build/core/prelink-linux-arm.map:13 base 0xaff00000 out of range.
./build/tools/apriori/prelinkmap.c:99:
"%s:%d base 0x%08x out of range.n",
1.3.1.4.2 LOCAL_SDK_VERSION 使应用程序不能访问hide的api
LOCAL_SDK_VERSION 会使应用程序不能访问hide的api,如果要访问自定义的api,那么在个应用的Android.mk 文件中屏蔽掉 LOCAL_SDK_VERSION := current
./packages/apps/Mms/Android.mk:13:#LOCAL_SDK_VERSION := current
./packages/apps/BBKMms/Android.mk:13:#LOCAL_SDK_VERSION := current
./packages/apps/Camera/Android.mk:9:# LOCAL_SDK_VERSION := current
1.3.1.4.3 armv5te-vfp 编译配置,导致一些游戏运行不了
device/qcom/msm7627_ffa/BoardConfig.mk:56:
TARGET_ARCH_VARIANT := armv5te-vfp
build/core/combo/TARGET_linux-arm.mk:37:
TARGET_ARCH_SPECIFIC_MAKEFILE := $(BUILD_COMBOS)/arch/$(TARGET_ARCH)/$(TARGET_ARCH_VARIANT).mk
......
$(TARGET_ARCH_SPECIFIC_MAKEFILE)
build/core/combo/arch/arm/armv5te-vfp.mk:6:
include $(BUILD_COMBOS)/arch/arm/armv5te.mk
build/core/combo/TARGET_linux-arm.mk:209:
如果 WITH_JIT 没有赋值,那么在文件 TARGET_linux-arm.mk 中会设置 WITH_JIT 默认值为 true
# Enable the Dalvik JIT compiler if not already specified.
ifeq ($(strip $(WITH_JIT)),)
WITH_JIT := true
Endif
dalvik/vm/Android.mk
1.3.2 分布式编译 android 代码
编译服务安装过程
1. unzip distcc.zip
2. cd distcc
3. chmod u+x installdistcc3.0.sh
4. sudo ./installdistcc3.0.sh
编译过程
5. cp setenv-dp.sh path to android source code root
6. . ./setenv-dp.sh
7. make -j24
1.3.3 modem 代码编译流程分析
从 svn 下载 modem 源代码,进入其根目录
svn co http://172.20.127.15/repositories/TD1014/trunk/modem-M76XXTSNCJNLYM6050/
首先执行环境变量设置脚本
cd modem-M76XXTSNCJNLYM6050
. ./setenv-qualcomm.sh
编译程序执行脚本
. ./make-TFNCKNLYM.sh
#!/bin/bash
echo ". ./AMSS/products/76XX//build/ms/bbkTFNCKNLYM.cmd $1"
. ./AMSS/products/76XX//build/ms/bbkTFNCKNLYM.cmd $1
AMSS/products/76XX/build/ms/bbkTFNCKNLYM.cmd
cd ./AMSS/products/76XX//build/ms
. ./TFNCKNLYM.cmd $1
cd –
./AMSS/products/7x30//build/ms/AAABQOLYM.cmd
AMSS/products/76XX/build/ms/TFNCKNLYM.cmd
make -r -f dmss76XXmodem.mak BUILD_UNIX=yes IMAGE=MODEM_PROC USES_SEC_CLNT=yes USES_MDDI=yes USES_CRYPTOMINCS=yes USES_RUIM=yes USES_PDCP=yes USES_HAL=yes USES_HSU_CHG_BOOT=yes USES_PMEM_REMOTE=yes USES_SDCC=yes USES_SUPPORT_UMTS_GPS_PROTOCOLS=yes USES_CDMA=yes USES_HSU_FAST_CHARGE=yes USES_CHARGER=yes USES_HSU_OTG=yes USES_ERR_SERVICES=yes USES_UMTS=yes USES_FTM_BT_MODEM_DUALPROC=yes USES_SMD_PORT_MGR=yes USES_SPLIT_CODE_DATA=yes USES_EXPORT_7K_APIS=yes USES_EBI1_TURBO_FFA=yes USES_SEC=yes USES_HDR=yes USES_DDR32_CFG_DATA=yes USES_HSU=yes USES_ONCRPC=yes USES_PHLP_XCVR=yes USES_SFS=yes USES_EFS2=yes USES_STRIP_NO_ODM=yes USES_SMD=yes USES_FEATURE_CGPS_XTRA=yes USES_VOCRTCV=yes USES_HS_USB_CHG_REMOTE_API=yes USES_CGPS=yes USES_FLASH_DAL=yes USES_ARM_ASM_SPINLOCK=yes USES_REL_C=yes USES_OEM_RAPI=yes USES_FEATURE_CGPS_XTRA_T=yes USES_IGUANA=yes USES_DAL=yes USES_LINUX_BT=yes USES_IPHC=yes USES_SEC_SVC=yes USES_ONCRPC_PROXY=yes USES_ONCRPC_ROUTER=yes USES_ONCRPC_CB=yes USES_NO_DEBUG=yes USES_DOG_KEEPALIVE=yes USES_HW7500=yes USES_VOCVP3=yes USES_VGA_CONTENT=yes USES_CGPS_SEC=yes USES_AUTH=yes USES_SMEM=yes USES_PICT_BRIDGE=yes USES_QOS=yes USES_BUS_MON_AXI_BUS_HANG_FIXED=yes USES_L4=yes USES_SBI=yes USES_HSU_MS_FD=yes USES_UIM=yes USES_IMG_UPDATE=yes USES_I2C_ON_APPS=yes USES_RPC_ROUTER_XAL_SMD=yes USES_CDMA2000=yes USES_SMEM_LOG=yes USES_EXPORT_MCCMEID=yes USES_NAND8_2K_CFG_DATA=yes USES_BUILD_NATIVELINUX_MODEM=yes USES_GSTK=yes USES_PS_DUN=yes USES_DEM=yes USES_DDR_ONLY=yes USES_DMOV=yes USES_HSU_ECM=yes USES_SUPPORT_CDMA_GPS_PROTOCOLS=yes USES_MBCBASBA=yes USES_BUS_PERF=yes USES_HIGH_POWER_CLK_FREQUENCY_PLAN=yes USES_GZRF6500=yes ASIC=76XXT BUILD=TFNCKNLYM VERSION=6050 BUILDDIR=TFNCKNLYM $1
1.3.3.1 单独编译某个模块(如:qcsbl oemsbl)
编译 modem 的主 makefile 文件为 AMSS/products/76XX/build/ms/dmss76XXmodem.mak
. ./make-TFNCKNLYM.sh genqcsbl 单独生成
. ./make-TFNCKNLYM.sh genoemsbl
./AMSS/products/76XX/build/ms/boot_targets_sec.min:1200
genqcsbl: $(MBNPATH_QCSBL)/qcsbl.mbn $(CERTDIR_QCSBL)/exist
./AMSS/products/76XX/build/ms/boot_targets_nonsec.min:870:
genqcsbl: $(MBNPATH)/qcsbl.mbn
./AMSS/products/76XX/build/ms/dmss76XXmodem.mak:49:
ifeq ($(USES_SECBOOT),yes)
SEC_MODE = sec
else
SEC_MODE = nonsec
endif
include boot_targets_$(SEC_MODE).min
./AMSS/products/76XX/build/ms/boot_targets_sec.min:108:
SECBOOT=$(SRCROOT)/secboot
./AMSS/products/76XX/build/ms/boot_targets_nonsec.min:107:
SECBOOT=$(SRCROOT)/secboot
./AMSS/products/76XX/build/ms/boot_targets_nonsec.min:872:
genoemsbl: $(MBNPATH)/oemsbl.mbn $(OEMSBL_HD_FILE_NAME)
./AMSS/products/76XX/build/ms/bin/TFNCKNLY/oemsbl.mbn
./AMSS/products/76XX/build/ms/bin/TFNCKNLY/oemsblhd.mbn
AMSS/products/76XX/build/ms/dmss76XXmodem.mak
...
all : dmss
...
include dmss_flags.min
include dmss_76XXT_flags.min
include incpaths.min
include armtools.min
-include amss_lint_flags.min
include dmss_objects.min
include boot_targets_$(SEC_MODE).min
...
include dmss_rules.min
-include amss_lint_rules.min
...
corebsp_build : corebsp_build_action corebsp_create_incpaths corebsp_setup
.PHONY: corebsp_build_action
corebsp_build_action :
ifeq ($(USES_COREBSP_BUILD_SYSTEM), yes)
$(warning COREBSP Build System Enabled)
@echo ================= COREBSP Build =======================================
@echo COREBSP Build System and AMSS Objects
#$(MAKE) -f $(COREBSP_BUILD)/msm7x30_modem.mak $(MAKEFLAGS)
$(MAKE) -f $(COREBSP_BUILD)/msm7x30_modem.mak
#$(MAKE) -f $(COREBSP_BUILD)/msm7x30_modem.mak -rk
@echo COREBSP AMSS Libraries
@if test -f $(COREBSP_BUILD)/msm7x30_lib.mak; then $(MAKE) -f $(COREBSP_BUILD)/msm7x30_lib.mak corebsplibs ; fi
@echo ================= COREBSP Build Done ==================================
else
$(warning COREBSP Build System Disabled)
include $(COREBSP_BUILD)/dmss_objects.min
OBJECTS := $(OBJECTS) $(COREBSP_OBJECTS)
QCTLIBS := $(QCTLIBS) $(COREBSP_QCTLIBS)
Endif
...
编译规则从 all : dmss 开始
dmss 规则 在文件 ./AMSS/products/7x30/build/ms/dmss_rules.min 中
...
ifeq ($(USES_L4), yes)
ifeq ($(IMAGE), APPS_PROC)
ifeq ($(USES_BUILD_NATIVELINUX_APPS), yes)
#dmss : $(TARGETDIR)/exist setup firmware prereqs deps corebsp_build libs copybar exe bldprod
dmss : $(TARGETDIR)/exist prereqs exe bldprod
else
#dmss : $(TARGETDIR)/exist setup firmware prereqs deps corebsp_build libs copybar exe bldprod
dmss : $(TARGETDIR)/exist setup prereqs exe bldprod
endif
else
ifneq ($(USES_OBJECT_ONLY), yes)
ifeq ($(USES_SDCC_BOOT), yes)
dmss : $(TARGETDIR)/exist setup firmware prereqs deps corebsp_build libs copybar exe bldprod create_mem_feat_html partition
else
dmss : $(TARGETDIR)/exist setup firmware prereqs deps corebsp_build libs copybar exe bldprod create_mem_feat_html
endif
else
ifeq ($(USES_SDCC_BOOT), yes)
dmss : $(TARGETDIR)/exist setup deps corebsp_build libs copybar exe bldprod create_mem_feat_html partition
else
dmss : $(TARGETDIR)/exist setup deps corebsp_build libs copybar exe bldprod create_mem_feat_html
endif
endif
endif
endif
...
.PHONY: setup
setup : corebsp_create_incpaths create_incpaths amsssetup amsslinkaddress firmware
...
BUILDID 为 AAABQOLYM 的脚本,比较关心的编译选项有:
BUILD_UNIX=yes
USES_L4=yes
IMAGE=MODEM_PROC
USES_LPDDR2=yes
USES_SDCC=yes
USES_SDCC_BOOT=yes
所以 dmss 规则为:
dmss : $(TARGETDIR)/exist setup deps corebsp_build libs copybar exe bldprod create_mem_feat_html partition
下面将分别对这些规则进行分析:
1.3.3.2 $(TARGETDIR)/exist 规则解析
1.3.3.3 setup规则解析
setup : corebsp_create_incpaths create_incpaths amsssetup amsslinkaddress firmware
1.3.3.3.1 corebsp_create_incpaths
1.3.3.3.2 create_incpaths
1.3.3.3.3 amsssetup
1.3.3.3.4 amsslinkaddress
amsslinkaddress 规则在文件:
./AMSS/products/7x30/build/ms/dmss_rules.min:871 中
amsslinkaddress : amsssetup
@echo Generate AMSS Link Address file: $(CUSTL4SCLFILE).....
@$(GEN_AMSS_LINK_ADDRESS)
amsssetup : create_incpaths
GEN_AMSS_LINK_ADDRESS 执行的是文件:
./AMSS/products/7x30/build/ms/dmss_rules.min:696 中的函数
。。。
L4_BASE_DIR := ../../core/kernel
AMSS_RELOC_DIR := build_$(BUILD_KCFG)/amss/bin
PLATMSDIR := ../../core/kernel/build_$(BUILD_KCFG)/ms
ELFWEAVER_CMD = python tools/pyelf/elfweaver
define GEN_AMSS_LINK_ADDRESS
@echo --------------------------------------------------------
@echo Determining AMSS link address from target XML file...
@-if test -f $(CUSTL4SCLFILE); then rm $(CUSTL4SCLFILE); fi
@echo "#ifndef CUST_L4_SCL_$(BUILD_KCFG)_H" >> $(CUSTL4SCLFILE)
@echo "#define CUST_L4_SCL_$(BUILD_KCFG)_H" >> $(CUSTL4SCLFILE)
@echo -n "#define SCL_L4_START_ADDRESS " >> $(CUSTL4SCLFILE)
@echo Preprocessing XML file into quartz_cfg_$(BUILD)_cpp.xml...
@echo Preprocessing XML file into quartz_cfg_machine_$(BUILD)_cpp.xml...
$(CC) -E $(CFLAGS) $(DMSS_CFLAGS) $(ALL_INCLUDES) $(DIRNAME) -I"$(ARMINC)" $(BUILD_VERSION) $(APPFLAGS) $(MSG_BT_SSID) $(OBJ_CMD) quartz_cfg_machine_$(BUILD)_cpp.xml quartz_cfg_machine.xml
@echo Copying cleaned XML file to quartz_cfg_machine_$(BUILD).xml...
./cleanup_xml.pl -i quartz_cfg_machine_$(BUILD)_cpp.xml -o quartz_cfg_machine_$(BUILD).xml
rm -f quartz_cfg_machine_$(BUILD)_cpp.xml
@echo Preprocessing XML file into quartz_cfg_$(BUILD)_cpp.xml...
$(CC) -E $(CFLAGS) -DAMSS_RELOC_LC="$(AMSS_RELOC_DIR)/$(BUILD_LC).reloc" -DQUARTZ_MACHINE_XML="../../build/ms/quartz_cfg_machine_$(BUILD).xml" $(DMSS_CFLAGS) $(COREBSP_XALL_INCLUDES) $(ALL_INCLUDES) $(DIRNAME) -I"$(ARMINC)" -I"../../core/systemdrivers/hwio/chipset/msm7x30/inc/plat/l4" $(BUILD_VERSION) $(APPFLAGS) $(MSG_BT_SSID) $(OBJ_CMD) quartz_cfg_$(BUILD)_cpp.xml quartz_cfg.xml
@echo Copying cleaned XML file to quartz_cfg_$(BUILD).xml...
./cleanup_xml.pl -i quartz_cfg_$(BUILD)_cpp.xml -o quartz_cfg_$(BUILD).xml
rm -f quartz_cfg_$(BUILD)_cpp.xml
@echo Determining AMSS link address...
@cd $(L4_BASE_DIR); $(ELFWEAVER_CMD) merge ../../build/ms/quartz_cfg_$(BUILD).xml --ignore="AMSS" --lastphys="physical" >> ../../build/ms/$(CUSTL4SCLFILE)
@echo "#endif" >> $(CUSTL4SCLFILE)
@echo Done.
@echo ------------------------------------------------------------------
。。。
@echo Generate AMSS Link Address file: $(CUSTL4SCLFILE).....
中的 CUSTL4SCLFILE 为: cust_l4_scl_M.h
@echo "#ifndef CUST_L4_SCL_$(BUILD_KCFG)_H" >> $(CUSTL4SCLFILE)
@echo "#define CUST_L4_SCL_$(BUILD_KCFG)_H" >> $(CUSTL4SCLFILE)
@echo -n "#define SCL_L4_START_ADDRESS " >> $(CUSTL4SCLFILE)
@echo "#endif" >> $(CUSTL4SCLFILE)
输出文件 ./AMSS/products/7x30/build/ms/cust_l4_scl_M.h ,内容为:
#ifndef CUST_L4_SCL_M_H
#define CUST_L4_SCL_M_H
#define SCL_L4_START_ADDRESS 0x4864000
#endif
/home/gphone/ARM//RVCT/Programs/2.2/593/linux-pentium/tcc -E -c --cpu ARM1136J-S --apcs /noswst/interwork --littleend --force_new_nothrow -Otime -O1 -O1 -DT_ARM -D__ARMEL__ -DCUST_H="custaabbqolym.h" -D__MSMHW_APPS_PROC__=2 -D__MSMHW_MODEM_PROC__=1 -D__MSMHW_PROC_DEF__=__MSMHW_MODEM_PROC__ -DMSMHW_MODEM_PROC -DIMAGE_MODEM_PROC -DASSERT=ASSERT_FATAL -I../../core/api/systemdrivers/hwio/msm7x30/inc -I../../core/api/systemdrivers/hwio/msm7x30/inc/plat/l4/user -I../../core/api/systemdrivers/hwio/msm7x30/inc/proc/modem -I../../apps/nonpkbrew/pk/inc/msm -I../../apps/nonpkbrew/pk/inc -I../../apps/nonpkbrew/pk/src -I../../apps/nonpkbrew/pk/src/msm -I../../apps/nonpkbrew/pk/../sdk/inc -I../../apps/brew/sdk/inc -I../../apps/brew/inc -I../../apps/brew/pk/inc/msm -I../../apps/brew/pk/inc -I../../apps/brew/pk/src -I../../apps/brew/src/OEM -I../../apps/brew/pk/src/msm -I../../apps/brew/inc/OEM -I../../apps/brew/src/OEM/msm -I../../apps/brew/src/OEM/OEMNotify/inc -I../../apps/brew/src/OEM/OEMConfigItem/inc -I../../apps/brew/src/OEM/OEMSound -I../../apps/brew/src/OEM/OEMSysClock/msm -I../../apps/brew/src/OEM/OEMShellBeep -I../../apps/brew/src/OEM/OEMServingNetworks/msm -I../../apps/brew/src/OEM/OEMAnnunciatorControl -I../../multimedia/adsp_diag -I../../apps/staticextensions/inc -I../../apps/staticextensions/oem/inc -I../../apps/staticextensions/oem/src -I../../wconnect/bthost/soccfg/inc -I../../wconnect/bthost/ftm/inc -I../../modem/uim/gstk/inc -I../../modem/uim/gstk/src -I../../modem/uim/estk/inc -I../../modem/uim/estk/src -I../../apps/DynamicExtensions/IMediaVideo -I../../modem/uim/dctstk/src -I../../core/api/hwengines -I../../multimedia/api/adsprtossvc -I../../core/securemsm/ipsec/inc -I../../core/securemsm/ipsec/src -I../../core/securemsm/akaalgo/inc -I../../core/securemsm/akaalgo/src -I../../wconnect/api/rapi/wlanhs/inc -I../../wconnect/api/wlanhs --via ../../build/ms/corebsp.inc --via ../../build/ms/M7X30AABBQOLYM/M7X30AABBQOLYM.inc -I../../modem/qchat/inc -I ../../modem/wms/src/CMCNas/inc -I/home/gphone/ARM//RVCT/Data/2.2/349/include/unix -DBUILD_ASIC="7X30A" -DBUILD_TARGET="AABBQOLYM" -DBUILD_VER="1250" -o quartz_cfg_machine_AABBQOLYM_cpp.xml quartz_cfg_machine.xml
PLATMSDIR := ../../core/kernel/build_$(BUILD_KCFG)/ms
拷贝文件
./AMSS/products/7x30/build/ms/loadsyms_M.cmm
./AMSS/products/7x30/build/ms/loadsyms_M.men
./AMSS/products/7x30/build/ms/quartz_constants_M.cmm
./AMSS/products/7x30/core/kernel/build_M/ms/
------------------------------------------------------------------
Generate AMSS Link Address file: cust_l4_scl_M.h.....
------------------------------------------------------------------
Determining AMSS link address from target XML file...
Preprocessing XML file into quartz_cfg_AABBQOLYM_cpp.xml...
Preprocessing XML file into quartz_cfg_machine_AABBQOLYM_cpp.xml...
Copying cleaned XML file to quartz_cfg_machine_AABBQOLYM.xml...
Preprocessing XML file into quartz_cfg_AABBQOLYM_cpp.xml...
Copying cleaned XML file to quartz_cfg_AABBQOLYM.xml...
Determining AMSS link address...
Done.
1.3.3.3.5 firmware
1.3.3.4 deps规则解析
1.3.3.5 corebsp_build规则解析
corebsp_build : corebsp_build_action corebsp_create_incpaths corebsp_setup
corebsp_build 规则包括三个过程:
corebsp_build_action
corebsp_create_incpaths
corebsp_setup
通过命令 . ./make-AAABQOLYM.sh corebsp_build 可以单独对 corebsp_build 部分进行编译。
1.3.3.5.1 corebsp_build_action
corebsp_build_action :
ifeq ($(USES_COREBSP_BUILD_SYSTEM), yes)
$(warning COREBSP Build System Enabled)
@echo ================= COREBSP Build ====================================
@echo COREBSP Build System and AMSS Objects
#$(MAKE) -f $(COREBSP_BUILD)/msm7x30_modem.mak $(MAKEFLAGS)
$(MAKE) -f $(COREBSP_BUILD)/msm7x30_modem.mak
#$(MAKE) -f $(COREBSP_BUILD)/msm7x30_modem.mak -rk
@echo COREBSP AMSS Libraries
@if test -f $(COREBSP_BUILD)/msm7x30_lib.mak; then $(MAKE) -f $(COREBSP_BUILD)/msm7x30_lib.mak corebsplibs ; fi
@echo ================= COREBSP Build Done ================================
else
$(warning COREBSP Build System Disabled)
include $(COREBSP_BUILD)/dmss_objects.min
OBJECTS := $(OBJECTS) $(COREBSP_OBJECTS)
QCTLIBS := $(QCTLIBS) $(COREBSP_QCTLIBS)
endif
因为:
USES_COREBSP_BUILD_SYSTEM=yes
$(COREBSP_BUILD)/msm7x30_lib.mak 文件不存在
所以 corebsp_build_action 规则
执行语句:$(MAKE) -f $(COREBSP_BUILD)/msm7x30_modem.mak
...
all : corebsp_scons corebsp
1.3.3.5.1.1 corebsp_scons 规则
./AMSS/products/7x30/core/bsp/build/dmss_rules.min 中。
corebsp_scons 包括三个部分:
corebsp_scons_start 显示信息 @echo Building CoreBSP 创建目录 mkdir -p $(COREBSP_BUILD)/data
corebsp_scons_action 主体部分
corebsp_scons_done 显示信息 @echo Completed CoreBSP
1.3.3.5.1.1.1 corebsp_scons_start
2.3.3.5.1.1.1 corebsp_scons_action
corebsp_scons_action 规则在文件 ./AMSS/products/7x30/core/bsp/build/dmss_rules.min:263 中,它完成核心bsp的编译。
./AMSS/products/7x30/core/bsp/tools/emmcbld/build/emmcbld.mbn
./AMSS/products/7x30/core/bsp/tools/flash/ehostdl/build/enandprg_AABBQOLYM.mbn
./AMSS/products/7x30/build/ms/bin/AABBQOLY/adsp.mbn
./AMSS/products/7x30/core/bsp/amsslibs/build/qdsp5/AMSS_AABBQOLYM.mbn
./AMSS/products/7x30/core/bsp/tools/flash/hostdl/build/nandprg_AABBQOLYM.mbn
./AMSS/products/7x30/build/ms/bin/AABBQOLY/partition.mbn
./AMSS/products/7x30/core/bsp/bootloaders/partition/build/partition_AABBQOLYM.mbn
./AMSS/products/7x30/build/ms/bin/AABBQOLY/osbl.mbn
./AMSS/products/7x30/core/bsp/bootloaders/osbl/build/osbl_AABBQOLYM.mbn
./AMSS/products/7x30/build/ms/bin/AABBQOLY/fsbl.mbn
./AMSS/products/7x30/core/bsp/bootloaders/fsbl/build/fsbl_AABBQOLYM.mbn
./AMSS/products/7x30/build/ms/bin/AABBQOLY/dbl.mbn
./AMSS/products/7x30/core/bsp/bootloaders/dbl/build/dbl_AABBQOLYM_preamble.mbn
./AMSS/products/7x30/core/bsp/bootloaders/dbl/build/dbl_AABBQOLYM.mbn
以上各部分都是在此过程中完成。
corebsp_scons_action : corebsp_genincpaths corebsp_genuses
@echo -------------------------------------------------------------------
$(scons_builder)
@echo -------------------------------------------------------------------
corebsp_genincpaths :
产生基于 AMSS 的头文件信息,通过下面命令完成。
perl $(COREBSP_BUILD)/scripts/genpaths.pl -min incpaths.min -buildid $(BUILD) -makeflags "$(MAKEFLAGS)" > $(COREBSP_BUILD)/data/incpaths$(BUILD_LC).py
$(COREBSP_BUILD)/scripts/genpaths.pl
为文件:
./AMSS/products/7x30/core/bsp/build/scripts/genpaths.pl
$(COREBSP_BUILD)/data/incpaths$(BUILD_LC).py
为文件:
./AMSS/products/7x30/core/bsp/build/data/incpathsaaabqmazm.py
corebsp_genuses:
$(scons_builder)
$(scons_builder) 的调用在文件 ./AMSS/products/7x30/core/bsp/build/dmss_rules.min:180:中
define scons_builder
-chmod +x $(COREBSP_BUILD)/../tools/SCons/scons
cd $(COREBSP_BUILD);
../tools/SCons/scons$(SCONS_EXT) $(PLATFORM) CHIPSET=$(CHIPSET) BUILD_ID=$(BUILDID) BUILD_VER=$(VERSION)
MSM_ID=$(BUILD_MSM_ID) HAL_PLATFORM=$(HAL_PLAT) BUILD_ASIC=$(BUILD_ASIC) TARGET_FAMILY=$(TARGET_FAMILY)
--verbose=$(VERBOSE) --frommake $(MAKE_FLAGS)
endef
COREBSP_BUILD 等于 ${SRCROOT}/core/bsp/build
./AMSS/products/7x30/core/bsp/tools/SCons/scons
所以 scons_builder 实际执行了以下命令:
chmod +x ./AMSS/products/7x30/core/bsp/tools/SCons/scons
cd ./AMSS/products/7x30/core/bsp/build
./AMSS/products/7x30/core/bsp/tools/SCons/scons modem CHIPSET=msm7x30 BUILD_ID=AAABQMAZ BUILD_VER=1220 MSM_ID=7x30 HAL_PLATFORM=7x30 BUILD_ASIC=7X30A TARGET_FAMILY=7630 --verbose=0 –frommake
1.3.3.5.1.1.2.1 命令 pboot_gen_elf image_header pboot_add_hash 解析
pboot_gen_elf image_header pboot_add_hash 是编译过程中用到的几个工具
编译过程中常用的几个工具
命令 ./AMSS/products/7x30/tools/headergen/pboot_gen_elf 用法:
pboot_gen_elf [-d] elf_file scl_file output_elf output_hash
或者:
pboot_gen_elf [-d] elf_file output_hash
-d - debug 模式
elf_file - 格式为ELF的输入文件,它由linker生成
scl_file - input progressive boot scatter load file
output_elf - output ELF file
output_hash - output hash table
例如:
PBOOT_GEN_ELF=./AMSS/products/7x30/tools/headergen/pboot_gen_elf
elf_file=./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/CORELIBS_AABBQMAZM.pbn
output_hash=./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/CORELIBS_AABBQMAZM.hash
$PBOOT_GEN_ELF $elf_file $output_hash
命令 ./AMSS/products/7x30/tools/headergen/image_header 用法:
image_header flash_type header_type input_code_file output_header_file secure_type [dbl_preamble_file or elf_src_file]
flash_type - flash 类型:nand 或者 nor
header_type - 头类型可以为: dbl, dbl_preamble, osbl, appsbl, apps, amsshash, hostdl, ehostdl, dsp1hash, dsp2hash
input_code_file - 用于生成文件头的输入文件
output_header_file - 生成的文件头
secure_type - 'secure' or 'nonsecure'
dbl_preamble_file - 当 header_type 等于 'dbl_preamble' 的时候指向 dbl preamble 文件的路径
elf_src_file - 当 header_type 等于 'hash' 的时候指向 elf file corresponding to hash table 的路径
例如:
=============
IMAGE_HEADER=./AMSS/products/7x30/tools/headergen/image_header
flash_type=nand
header_type=amsshash
input_code_file=./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/CORELIBS_AABBQMAZM.hash
output_header_file=./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/CORELIBS_AABBQMAZM.hash.hd
secure_type=nonsecure
dbl_preamble_file=
elf_src_file=./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/CORELIBS_AABBQMAZM.pbn
$IMAGE_HEADER $flash_type $header_type $input_code_file $output_header_file $secure_type $elf_src_file
命令 AMSS/products/7x30/tools/headergen/pboot_add_hash 用法:
把 hash 头和 hash 表插入到 ELF文件作为起始段 ,在物理内存中它实际在最后。
pboot_add_hash [-d] elf_file hash_table output_elf
-d - debug 模式
elf_file - the ELF file
hash_table - hash table (signed or not)
output_elf - final output
PBOOT_ADD_HASH=./AMSS/products/7x30/tools/headergen/pboot_add_hash
elf_file=./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/CORELIBS_AABBQMAZM.pbn
hash_table=./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/CORELIBS_AABBQMAZM.hash_nonsec.mbn
output_elf=./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/CORELIBS_AABBQMAZM.mbn
$PBOOT_ADD_HASH $elf_file $hash_table $output_elf
1.3.3.5.1.1.2.2env.BinBuilder 过程解析
1.3.3.5.1.1.2.3 env.MbnBuilder 过程解析
mbn 类型的文件是我们最终烧写到板子上的镜像文件
在文件: ./AMSS/products/7x30/core/bsp/build/scripts/mbn_builder.py 中有 mbn 文件的编译规则,要注意的是,不同的 modem 源代码版本,它里面的规则有可能不一样。
1220 以及之前的版本,编译规则中有:
def mbn_generate(env):
#-------------------------------------------------------------------------
# MBN builder definition
#-------------------------------------------------------------------------
mbn_act = env.GetBuilderAction(mbn_builder)
mbn_bld = env.Builder(action = mbn_act,
emitter = mbn_emitter,
suffix = '.mbn')
env.Append(BUILDERS = {'MbnBuilder' : mbn_bld})
mbn_dummy_act = env.GetBuilderAction(mbn_dummy_file_gen)
mbn_dummy_bld = env.Builder(action = mbn_dummy_act, suffix = '.mbn')
env.Append(BUILDERS = {'MbnDummyBuilder' : mbn_dummy_bld})
1240 后的版本为:
def mbn_generate(env):
env.AddMethod(mbn_builder, "MbnBuilder")
#-------------------------------------------------------------------------
# MBN builder definition
#-------------------------------------------------------------------------
stage1_mbn_act = env.GetBuilderAction(stage1_mbn_builder)
stage1_mbn_bld = env.Builder(action = stage1_mbn_act,
emitter = stage1_mbn_emitter,
suffix = '.mbn')
env.Append(BUILDERS = {'Stage1MbnBuilder' : stage1_mbn_bld})
stage2_mbn_act = env.GetBuilderAction(stage2_mbn_builder)
stage2_mbn_bld = env.Builder(action = stage2_mbn_act,
emitter = stage2_mbn_emitter,
suffix = '.mbn')
env.Append(BUILDERS = {'Stage2MbnBuilder' : stage2_mbn_bld})
mbn_dummy_act = env.GetBuilderAction(mbn_dummy_file_gen)
mbn_dummy_bld = env.Builder(action = mbn_dummy_act, suffix = '.mbn')
env.Append(BUILDERS = {'MbnDummyBuilder' : mbn_dummy_bld})
MbnBuilder 方法,它对应的函数为 mbn_builder, 该函数也在文件:./AMSS/products/7x30/core/bsp/build/scripts/mbn_builder.py 中:
def mbn_builder(target, source, env):
...
source_base = os.path.splitext(str(source[0]))[0]
target_base = os.path.splitext(str(target[0]))[0]
source_full = str(source[0])
target_full = str(target[0])
1.3.3.5.1.1.2.4 env.MbnDummyBuilder 过程解析
./AMSS/products/7x30/core/bsp/build/scripts/mbn_builder.py:160:
。。。
mbn_dummy_act = env.GetBuilderAction(mbn_dummy_file_gen)
mbn_dummy_bld = env.Builder(action = mbn_dummy_act, suffix = '.mbn')
env.Append(BUILDERS = {'MbnDummyBuilder' : mbn_dummy_bld})
。。。
def mbn_dummy_file_gen(target, source, env):
target_str = str(target[0])
file = open (target_str, "w")
file.write("nDummy file created " + target_str + "n")
file.close()
return None
# 生成 fsbl elf
FSBL_elf = env.Program('${TARGET_NAME}', FSBL_objs, LIBS=FSBL_libs, LIBPATH=libs_path)
FSBL_bin = env.BinBuilder('${TARGET_NAME}', FSBL_elf)
# Generate dummy fsbl mbn
FSBL_mbn = env.MbnDummyBuilder('${TARGET_NAME}', None)
install_target_mbn = env.InstallAs('${MBN_ROOT}/fsbl.mbn', FSBL_mbn)
1.3.3.5.1.1.2.5fsbl.mbn 生成过程解析
./AMSS/products/7x30/core/bsp/bootloaders/fsbl/build/SConscript:203:
# 生成 fsbl elf
FSBL_elf = env.Program('${TARGET_NAME}', FSBL_objs, LIBS=FSBL_libs, LIBPATH=libs_path)
# Generate fsbl bin
FSBL_bin = env.BinBuilder('${TARGET_NAME}', FSBL_elf)
# Generate fsbl mbn
#FSBL_mbn = env.MbnBuilder('${TARGET_NAME}', FSBL_bin,
# IMAGE_TYPE="fsbl", FLASH_TYPE=env['FLASH_TYPE'])
# 生成 dummy fsbl mbn
FSBL_mbn = env.MbnDummyBuilder('${TARGET_NAME}', None)
install_target_mbn = env.InstallAs('${MBN_ROOT}/fsbl.mbn', FSBL_mbn)
1.3.3.5.1.1.2.6 dbl.mbn 生成过程解析
./AMSS/products/7x30/core/bsp/bootloaders/dbl/build/SConscript:230:
DBL_elf = env.Program('${TARGET_NAME}',DBL_objs , LIBS=DBL_libs, LIBPATH=libs_path)
DBL_bin = env.BinBuilder('${TARGET_NAME}', DBL_elf)
DBL_mbn = env.MbnBuilder(env.subst('${TARGET_NAME}'), DBL_bin, IMAGE_TYPE="dbl", FLASH_TYPE="nand")
1.3.3.5.1.1.2.7 AMSS_AABBQOLYM.mbn 生成过程解析
./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/SConscript:252:
target_mbn = env.MbnBuilder('${TARGET_NAME}', target_pbn, IMAGE_TYPE="amss_mbn",
1.3.3.5.1.1.2.8 adsp.mbn 生成过程解析
生成 adsp.mbn 的 scons 脚本为:
./AMSS/products/7x30/core/bsp/amsslibs/build/qdsp5/SConscript
adsp_bin_path = env.subst("${BUILD_ROOT}/multimedia/adspinfo/adsp.bin")
adsp_mbn_path = env.subst("${BUILD_ROOT}/core/bsp/amsslibs/build/qdsp5/adsp.mbn")
install_temp_adsp_mbn = env.InstallAs(adsp_mbn_path, adsp_bin_path)
ADSP_mbn = env.MbnBuilder('${TARGET_NAME}', adsp_mbn_path, IMAGE_TYPE="qdsp5", FLASH_TYPE=env['TARGET_FLASH_TYPE'])
install_adsp_mbn = env.InstallAs('${MBN_ROOT}/adsp.mbn', ADSP_mbn)
首先安装文件:
AMSS/products/7x30/multimedia/adspinfo/adsp.bin
到:
AMSS/products/7x30/core/bsp/amsslibs/build/qdsp5/adsp.mbn
此时的 adsp.mbn 仅仅是文件 adsp.bin 的拷贝。
然后调用 env.MbnBuilder 由文件 AMSS/products/7x30/core/bsp/amsslibs/build/qdsp5/adsp.mbn生成:./AMSS/products/7x30/core/bsp/amsslibs/build/qdsp5/AMSS_AABBQOLYM.mbn
AMSS_AABBQOLYM.mbn 是 adsp.mbn 加了40个字节的头信息,最后安装此 AMSS_AABBQOLYM.mbn 到
AMSS/products/7x30/build/ms/bin/AABBQOLY/adsp.mbn
其中 env.MbnBuilder 执行的是文件:
./AMSS/products/7x30/core/bsp/build/scripts/mbn_builder.py:299 中的函数:
def mbn_builder(target, source, env)
AMSS/products/7x30/tools/headergen/image_header nand adspq5 AMSS/products/7x30/core/bsp/amsslibs/build/qdsp5/adsp.mbn AMSS/products/7x30/core/bsp/amsslibs/build/qdsp5/AMSS_AABBQOLYM.hd nonsecure
flash_type: nand
header_type: adspq5
code_file_name: /home/shared/qualcommon/HY11-N1496-2_1.2.40/AMSS/products/7x30/core/bsp/amsslibs/build/qdsp5/adsp.mbn
output_file_name: /home/shared/qualcommon/HY11-N1496-2_1.2.40/AMSS/products/7x30/core/bsp/amsslibs/build/qdsp5/AMSS_AABBQOLYM.hd
secure_type: nonsecure
image_size = 0x614AB4, code_size= =0x614AB4
1.3.3.5.1.1.2.9osbl.mbn 生成过程解析
./AMSS/products/7x30/core/bsp/bootloaders/osbl/build/SConscript:246:
OSBL_mbn = env.MbnBuilder('${TARGET_NAME}', OSBL_bin,
1.3.3.5.1.1.2.10enandprg_AABBQOLYM.mbn 生成过程解析
./AMSS/products/7x30/core/bsp/tools/flash/ehostdl/build/SConscript:389:
# Generate enandprg.elf
enandprg_elf = env.Program('${TARGET_NAME}', source=[], LIBS=libs, LIBPATH=libs_path)
env.Depends(enandprg_elf, target_scl)
Clean(enandprg_elf, env.subst('${TARGET_NAME}.map'))
Clean(enandprg_elf, env.subst('${TARGET_NAME}.sym'))
# 把生成的 elf 文件拷贝到相应位置
install_enandprg_elf = env.Install("${BUILD_ROOT}/core/storage/flash/tools/src/hostdl",enandprg_elf)
# Generate ehostdl bin
target_bin = env.BinBuilder('${TARGET_NAME}', enandprg_elf)
# 生成 ehostdl mbn
target_mbn = env.MbnBuilder('${TARGET_NAME}', target_bin, IMAGE_TYPE="ehostdl", FLASH_TYPE="nand")
1.3.3.5.1.1.2.11 nandprg_AABBQOLYM.mbn 生成过程解析
./AMSS/products/7x30/core/bsp/tools/flash/hostdl/build/SConscript:401:
# Generate nandprg.elf
nandprg_elf = env.Program('${TARGET_NAME}', source=[], LIBS=libs, LIBPATH=libs_path)
env.Depends(nandprg_elf, target_scl)
Clean(nandprg_elf, env.subst('${TARGET_NAME}.map'))
Clean(nandprg_elf, env.subst('${TARGET_NAME}.sym'))
# 把生成的 elf 文件拷贝到相应位置
install_nandprg_elf = env.Install("${BUILD_ROOT}/core/storage/flash/tools/src/hostdl", nandprg_elf)
# Generate hostdl bin
target_bin = env.BinBuilder('${TARGET_NAME}', nandprg_elf)
# Generate hostdl mbn
target_mbn = env.MbnBuilder('${TARGET_NAME}', target_bin,IMAGE_TYPE="hostdl", FLASH_TYPE="nand")
# Generate nandprg.hex
nprg_hex = env.NPRGHexBuilder('NPRG${MSM_ID}_${BUILD_ID}', target_mbn,HOSTDL_ADDR=CODE_HDR_ADDR)
install_nandprg_hex = env.InstallAs('${MBN_ROOT}/NPRG${MSM_ID}.hex', nprg_hex)
1.3.3.5.1.1.2.12 emmcbld.mbn 生成过程解析
生成 emmcbld.mbn 的 scons 脚本为:
./AMSS/products/7x30/core/bsp/tools/emmcbld/build/SConscript:289:
libs = root_env['LIBS']
libs_path = env['LIBPATH']
# Source PATH
EMMCBLD_SRC = "${BUILD_ROOT}/core/storage/tools/emmcbld"
。。。
env.VariantDir('.', EMMCBLD_SRC, duplicate=0)
env.Replace(TARGET_NAME = 'emmcbld')
env.Replace(TARGET_BLD_KCFG = 'M')
env.Replace(TARGET_IMAGE = 'MODEM_PROC')
# 生成 scatter load 文件
target_scl = env.SclBuilder('${TARGET_NAME}', '${BUILD_ROOT}/core/storage/tools/emmcbld/emmcbld_in.scl')
# 生成 emmcbld elf 文件
target_elf = env.Program('${TARGET_NAME}', emmcbld_obj, LIBS=libs, LIBPATH=libs_path)
env.Depends(target_elf, target_scl)
Clean(target_elf, env.subst('${TARGET_NAME}.map'))
Clean(target_elf, env.subst('${TARGET_NAME}.sym'))
# 生成 Generate emmcbld bin 文件
target_bin = env.BinBuilder('${TARGET_NAME}', target_elf)
# 生成 Generate emmcbld mbn 文件
target_mbn = env.MbnBuilder('${TARGET_NAME}', target_bin, IMAGE_TYPE="emmcbld", FLASH_TYPE="nand")
# 生成 emmcbld.hex 文件
mprg_hex = env.NPRGHexBuilder('MPRG${MSM_ID}', target_mbn, HOSTDL_ADDR=CODE_HDR_ADDR)
install_emmcbld_hex = env.InstallAs('${MBN_ROOT}/MPRG${MSM_ID}.hex', mprg_hex)
通过语句:
target_elf = env.Program('${TARGET_NAME}', emmcbld_obj, LIBS=libs, LIBPATH=libs_path) 编译 emmcbld 相关代码生成 ./AMSS/products/7x30/core/bsp/tools/emmcbld/build/emmcbld.elf LIBS 为程序需要引入的库,库的路径为 LIBPATH 例如:
如果程序引入了其它的库,库名为libbar.a,库的目录为/usr/local/lib:
Program('hello',Glob("*.c"),LIBS='bar',LIBPATH='/usr/local/lib')
env.Depends(target_elf, target_scl)明确以来关系,表明生成 mmcbld.elf 需要 emmcbld.scl
Clean(target_elf, env.subst('${TARGET_NAME}.map'))
Clean(target_elf, env.subst('${TARGET_NAME}.sym'))
Clean 调用的是文件:
./AMSS/products/7x30/core/bsp/tools/SCons/Environment.py:1814:中的函数
def Clean(self, targets, files):
flash_type: nand
header_type: emmcbld
code_file_name: /home/shared/HY11-N1496-3_1.2.50/AMSS/products/7x30/core/bsp/tools/emmcbld/build/emmcbld.bin
output_file_name: /home/shared/HY11-N1496-3_1.2.50/AMSS/products/7x30/core/bsp/tools/emmcbld/build/emmcbld.hd
secure_type: nonsecure
image_size = 0x23E88, code_size= =0x23E88
=== Generating tool/emmcbld/MPRG7x30.hex
Install file: "/home/shared/HY11-N1496-3_1.2.50/AMSS/products/7x30/core/bsp/tools/emmcbld/build/MPRG7x30.hex" as "/home/shared/HY11-N1496-3_1.2.50/AMSS/products/7x30/build/ms/bin/AABBQOLY/MPRG7x30.hex"
3.3.3.5.1.1.1 corebsp_scons_done
1.3.3.5.1.2 corebsp
1.3.3.5.2 corebsp_create_incpaths
1.3.3.5.3 corebsp_setup
1.3.3.6 libs
.PHONY: setup
setup : corebsp_create_incpaths create_incpaths amsssetup amsslinkaddress firmware
...
#生成 Library
ifneq ($(USES_OBJECT_ONLY), yes)
libs : $(LIBDIR)/exist copybar firmware prereqs $(LIBRARIES)
@if test -f dmss_lib.mak; then $(MAKE) --no-print-directory -f dmss_lib.mak; fi
else
libs : $(LIBDIR)/exist copybar $(LIBRARIES)
@if test -f dmss_lib.mak; then $(MAKE) --no-print-directory -f dmss_lib.mak; fi
endif
...
ifeq ($(IMAGE), APPS_PROC)
$(TARGETDIR)/exist $(LIBDIR)/exist $(MBNPATH)/exist:
else
$(TARGETDIR)/exist $(LIBDIR)/exist:
endif
@echo ---------------------------------------------------------------
@echo Creating path for ${@D}
@echo
@if test ! -f $@ && test ! -d ${@D}; then mkdir -p ${@D}; mkdir -p ${@D}; fi
@echo Building ${@D} > $@
@echo ---------------------------------------------------------------
...
1.3.3.7 copybar规则解析
1.3.3.8 exe规则解析
1.3.3.8.1 CORELIBS_AABBQOLYM.mbn生成过程解析
1.3.3.8.2 amss.mbn 生成过程解析
# Create PBN, MBN, etc..
install_target_reloc = env.InstallAs(AMSS_RELOC, target_elf)
# Build env pbn files
target_pbn = env.PbnBuilder('${TARGET_NAME}', ["${BUILD_MS_ROOT}/quartz_cfg_${BUILD_ID}",install_target_reloc])
install_target_pbn = env.InstallAs(BOOTING_PBN, target_pbn)
# Build CMM scripts
quartz_constant_cmm = env.QuartzConstBuilder('quartz_const_${TARGET_NAME}', ["${L4_ROOT}/build_${TARGET_BLD_KCFG}/ms/quartz_constants_${TARGET_BLD_KCFG}.cmm",install_target_pbn,"${BUILD_MS_ROOT}/quartz_cfg_${BUILD_ID}.xml",])
# install scripts
install_quartz_constant_cmm = env.InstallAs("${BUILD_MS_ROOT}/quartz_constants_${TARGET_BLD_KCFG}.cmm",quartz_constant_cmm)
install_loadsyms_cmm = env.Install("${BUILD_MS_ROOT}","${L4_ROOT}/build_${TARGET_BLD_KCFG}/ms/loadsyms_${TARGET_BLD_KCFG}.cmm",)
install_loadsyms_men = env.Install("${BUILD_MS_ROOT}","${L4_ROOT}/build_${TARGET_BLD_KCFG}/ms/loadsyms_${TARGET_BLD_KCFG}.men",)
install_cmm_scripts = [install_quartz_constant_cmm,install_loadsyms_cmm,install_loadsyms_men,]
# Build env mbn files
target_mbn = env.MbnBuilder('${TARGET_NAME}', target_pbn, IMAGE_TYPE="amss_mbn",FLASH_TYPE=env['TARGET_FLASH_TYPE'])
1.3.3.9 bldprod规则解析
1.3.3.10 create_mem_feat_html规则解析
此规则在 文件中
./AMSS/products/7x30/core/bsp/build/SConstruct:22:print "
Loading CBSP build system"
./AMSS/products/7x30/core/bsp/coreimg/build/SConscript:24:
print " Loading CBSP Image build system"
./AMSS/products/7x30/core/bsp/tools/flash/build/SConstruct:31:
print " Loading CBSP build system"
./AMSS/products/7x30/core/bsp/tools/boot/build/SConstruct:31:
print " Loading CBSP build system"
./AMSS/products/7x30/core/bsp/bootloaders/build/SConstruct:31:
print " Loading CBSP build system"
perl ./AMSS/products/7x30/build/ms/cleanup_xml.pl -i
./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/quartz_cfg_AAABQMAZM.xml
./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/quartz_cfg_machine_AAABQMAZM.xml
./AMSS/products/7x30/build/ms/quartz_cfg_AABBQMAZM.xml
./AMSS/products/7x30/build/ms/quartz_cfg_AABBQOLYM.xml
./AMSS/products/7x30/build/ms/quartz_cfg_AAABQMAZM.xml
./AMSS/products/7x30/build/ms/quartz_cfg_machine_AABBQOLYM.xml
./AMSS/products/7x30/build/ms/quartz_cfg_machine_AAABQMAZM.xml
./AMSS/products/7x30/build/ms/quartz_cfg_machine_AABBQMAZM.xml
./AMSS/products/7x30/build/ms/quartz_cfg_machine.xml
./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/CORELIBS_AAABQMAZM.mbn
./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/CORELIBS_AAABQMAZM.hash_nonsec.mbn
./AMSS/products/7x30/core/bsp/build/scripts/mbn_builder.py
if env.subst("$IMAGE_TYPE") != "amss_mbn":
target_bin_nonsec = os.path.join(target_bin_base, target_bin_dir,
str(os.path.split(target_base)[1]) + "_nonsec.mbn")
else:
target_bin_nonsec = os.path.join(target_bin_base, target_bin_dir,
str(os.path.split(target_base)[1]) + ".hash_nonsec.mbn")
quartz_xml = env.QuartzXMLBuilder('quartz_cfg_${TARGET_NAME}',
['${BUILD_MS_ROOT}/quartz_cfg.xml', quartz_machine_xml],
#-------------------------------------------------------------------------
# Build env pbn files
#-------------------------------------------------------------------------
target_pbn = env.PbnBuilder(
'${TARGET_NAME}', [quartz_xml, install_target_reloc])
# Copy qcoreimg_M.pbn to platforml4build_Mbootimg.pbn for RUMI */
install_target_pbn = env.InstallAs(
'${L4_ROOT}/build_${TARGET_BLD_KCFG}/bootimg.pbn', target_pbn)
target_mbn = env.MbnBuilder('${TARGET_NAME}', target_pbn, IMAGE_TYPE="amss_mbn",
FLASH_TYPE=env['TARGET_FLASH_TYPE'])
install_target_mbn = env.InstallAs('${MBN_ROOT}/amss.mbn', target_mbn)
因为有:
ifeq ($(USES_HW6500),yes)
BOOT = $(SRCROOT)/drivers/boot
else
ifeq ($(IMAGE), APPS_PROC)
BOOT = $(SRCROOT)/core/api/boot/appsproc/
APPSBL = $(BOOT)
else
BOOT=$(SRCROOT)/core/api/boot/
BOOT +=$(SRCROOT)/core/api/boot/amssboot/
endif
endif
且我们定义 APPS_MODEM ,所以使用的是:
BOOT=$(SRCROOT)/core/api/boot/
BOOT +=$(SRCROOT)/core/api/boot/amssboot/
boot_reset_handler.s 使用的是:
./AMSS/products/7x30/core/boot/amssboot/shared/src/boot_reset_handler.s
...
EXPORT Reset_Handler
EXPORT soft_breakpoints_enabled
Reset_Handler
;------------------------------------------------------------------
; process init - initializes the AMSS process
; returns the number of bytes to pop off the stack
;------------------------------------------------------------------
ldr r0, [sp]
blx process_init
add sp, sp, r0
soft_breakpoints_enabled ; All pages of apps code have been paged in.
;------------------------------------------------------------------
; Pop argc and argv and launch into main. If main is compiled with
; thumb mode, blx will ensure that we properly change to thumb mode
;------------------------------------------------------------------
ldmia sp!, {r0}
mov r1, sp
blx main
...
./AMSS/products/7x30/core/boot/amssboot/shared/src/boot_vectors.s:49: IMPORT Reset_Handler
./AMSS/products/7x30/core/boot/amssboot/shared/src/boot_vectors.s:102: DCD Reset_Handler
./AMSS/products/7x30/core/bsp/amsslibs/build/qdsp5/SConscript:102: install_temp_adsp_mbn = env.InstallAs(adsp_mbn_path, adsp_bin_path)
./AMSS/products/7x30/core/bsp/amsslibs/build/qdsp5/SConscript:108: install_adsp_mbn = env.InstallAs('${MBN_ROOT}/adsp.mbn', ADSP_mbn)
./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/SConscript:193: install_target_reloc = env.InstallAs(AMSS_RELOC, target_elf)
./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/SConscript:203: install_target_pbn = env.InstallAs(BOOTING_PBN, target_pbn)
./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/SConscript:215: install_quartz_constant_cmm = env.InstallAs(
./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/SConscript:261: install_target_mbn = env.InstallAs("${MBN_ROOT}/amss.mbn", target_mbn)
./AMSS/products/7x30/core/bsp/coreimg/build/arm11/CoreImage.py:240: install_target_mbn = env.InstallAs('${MBN_ROOT}/amss.mbn', target_mbn)
1.3.3.10.1
1.3.3.11 partition规则解析
1.3.3.11.1 eMCC 启动和 NAND 启动的分区格式是不一样的,如果是 eMCC 启动,多了编译选项:
USES_SDCC_BOOT=yes USES_HSU_MS_FD_BOOT=yes
如果 USES_HSU_MS_FD_BOOT=yes
=== Compiling boot/osbl/fd_storage_scsi.c
=== Compiling boot/osbl/fd_storage_usb.c
如果 USES_SDCC_BOOT=yes
那么会进行 partition 规则的处理,它会覆盖掉 corebsp_build 规则阶段生成的 partition.mbn
./AMSS/products/7x30/build/ms/dmss_rules.min
-----------
。。。
partition :
@echo Generate partition.bin.....
@$(GENERATE_PARTITION)
。。。
不同 modem 版本中,GENERATE_PARTITION 的定义会不同
HY11-N0723-1_1.2.00 中为:
-------
define GENERATE_PARTITION
@echo ------------------------------------------------------------------
@echo Changing to Tools directory...
@pwd
cd $(TOOLSDIR_JSDCC); make; make genpart
endef
-------
HY11-N1496-2_1.2.40 中为:
-------
define GENERATE_PARTITION
@echo ------------------------------------------------------------------
@echo Changing to Tools directory...
@pwd
cd $(TOOLSDIR_JSDCC); make; make genpart
perl $(TOOLSDIR_JSDCC)/partition_extract_mbr.pl 2 0 $(TOOLSDIR_JSDCC)/
rm -f $(MBNPATH)/partition.mbn
rm -f $(MBNPATH)/ENPRG7x30.hex
cp -f $(TOOLSDIR_JSDCC)/partition.mbn $(MBNPATH)/
cp -f $(MBNPATH)/MPRG7x30.hex $(MBNPATH)/ENPRG7x30.hex
cp -f $(MBNPATH)/MPRG7x30.hex $(MBNPATH)/NPRG7x30.hex
endef
------
partition 规则主要完成以下功能:
1) 编译 ./AMSS/products/7x30/core/storage/tools/jsdcc/partition_load_pt 代码,生成 loadpt 和 msp
2) 解析 loadpt 解析 partition.xml 文件,把分区信息保存成二进制文件 partition.bin
3) 由 partition.bin 文件生成 partition.mbn,然后拷贝到 ./AMSS/products/7x30/build/ms/bin/AAABQMAZ/partition.mbn
-----
cd $(TOOLSDIR_JSDCC); make; make genpart 命令会到目录:
./AMSS/products/7x30/core/storage/tools/jsdcc/ 下执行 make; make genpart
因为有:
./AMSS/products/7x30/core/storage/tools/jsdcc/partition_load_pt/Makefile
。。。
all: $(TARGET_LOADPT)$(EXE) $(TARGET_MSP)$(EXE)
genpart:
./$(TARGET_LOADPT)$(EXE)
。。。
所以 make 命令会生成 loadpt 和 mps
make genpart 执行 loadpt 命令
-------------
loadpt 命令解析 partition.xml 文件分析:
fp_input = fopen("partition.xml", "rt"); 打开文件:
AMSS/products/7x30/core/storage/tools/jsdcc/partition_load_pt/partition.xml
#define INPUT_BUFFER_SIZE 10240
input_buf = malloc(INPUT_BUFFER_SIZE);
申请一个大小为 10240的缓冲区,对 partition.xml 文件内容进行解析,然后以串的形式保存在变量: input_buf 中。
fp_bin_out = fopen("partition.bin", "wb");
生成一个 partition.bin 文件,用于保存二进制的分区信息
parse_element(input_buf, LEVEL_IMAGE);
对每个分区描述符进行解析,然后保存到文件 partition.bin 中。
---------------
命令 perl $(TOOLSDIR_JSDCC)/partition_extract_mbr.pl 2 0 $(TOOLSDIR_JSDCC)/ 会生成文件:
./AMSS/products/7x30/core/storage/tools/jsdcc/partition_load_pt/partition.mbn
---------------
./AMSS/products/7x30/core/bsp/tools/emmcbld/build/MPRG7x30.hex
./AMSS/products/7x30/build/ms/bin/AABBQOLY/MPRG7x30.hex
在 HY11-N0216-4_1.2.20 版本中不存在文件
./AMSS/products/7x30/core/bsp/tools/emmcbld/build/MPRG7x30.hex
1.4 高通平台 7630 启动流程分析
1.4.1 启动流程概述
开机后,首先从 rom 中的 pbl 开始执行,pbl 装载 dbl
1.4.2 pbl 流程
pbl 是固化在高通芯片中的一段程序,没有相应的源代码。
1.4.3 dbl 流程
pbl运行以后,它会装载 dbl,dbl是从其__main 函数开始执行,此函数在汇编文件 dbl.s 中。
./AMSS/products/7x30/core/boot/secboot2/dbl/shared/src/dbl.s
__main
_main
...
ldr r5, =dbl_main_ctl
blx r5
...
通过 dbl_main_ctl 调用会进入 c 函数, dbl_main_ctl 函数在文件:
./AMSS/products/7x30/core/boot/secboot2/dbl/shared/src/dbl_mc.c:282中:
void dbl_main_ctl(boot_pbl_shared_data_type *pbl_shared)
...
调用表 dbl_init_func_tbl 中的每个函数
for ( i=0; dbl_init_func_tbl[i] != NULL; i++ )
{
dbl_init_func_tbl[i](&dbl_shared_data);
}
...
#经过一系列的初始化,dbl 会把控制权传递给 osbl
dbl_shared_data.entry_ptr(dbl_shared_data.dbl_data_for_osbl);
...
dbl_init_func_tbl 表在文件:
./AMSS/products/7x30/core/boot/secboot2/dbl/shared/src/dbl_mc.c:122 中,其中的函数:
dbl_load_osbl_image 会完成 osbl 的装载
dbl_load_osbl_image 函数在文件:
./AMSS/products/7x30/core/boot/secboot2/dbl/shared/src/dbl_loader.c:322 中:
void dbl_load_osbl_image(dbl_shared_data_type *shared_data)
{
dbl_error_type ret_value = DBL_ERR_NONE;
ret_value = dbl_load_image(shared_data, OSBL_IMG);
DBL_VERIFY((ret_value == DBL_ERR_NONE), (uint32)ret_value);
} /* dbl_load_osbl_image */
dbl_load_osbl_image
ret_value = dbl_load_image(shared_data, OSBL_IMG);
shared_data->dbl_state = DBL_STATE_LOAD_OSBL_IMG;
ret_value = dbl_load_hdr_and_image( shared_data,img_type,MIBIB_OSBL_PARTI_NAME,MI_OSBL_MAGIC1,MI_OSBL_MAGIC2);
shared_data->entry_ptr = (void (*)(void*))(image_hdr.image_dest_ptr);
dbl_shared_data.entry_ptr(dbl_shared_data.dbl_data_for_osbl)
在调用 dbl_shared_data.entry_ptr 之前,已经对该函数指针进行了初始化:
shared_data->entry_ptr = (void (*)(void*))(image_hdr.image_dest_ptr);
它实际上是指向 osbl 镜像的起始地址,所以执行之后,系统进入 osbl 阶段
1.4.4 osbl 流程
osbl 的入口函数 __main 在汇编文件:
./AMSS/products/7x30/core/boot/secboot2/osbl/shared/src/osbl.s:86: 中
...
IMPORT osbl_main_ctl
...
AREA OSBL_ENTRY, CODE, READONLY
CODE32
ENTRY
__main
_main
...
ldr r5, =osbl_main_ctl
blx r5
...
__main 函数会调用 osbl_main_ctl ,此函数在文件:
./AMSS/products/7x30/core/boot/secboot2/osbl/shared/src/osbl_mc.c:234 中。
void osbl_main_ctl(boot_dbl_if_shared_info_type *dbl_shared_info_ptr)
{
...
#Process the target-dependent OSBL procedures
osbl_do_procedures( &bl_shared_data,osbl_main_procs );
...
//把控制权给 AMSS
bl_shared_data.amss_entry_ptr();
}
在此阶段,osbl 通过 osbl_main_procs 中定义的 osbl_load_appsbl 函数把应用程序的控制权交给了android 系统,modem 端的控制权通过 bl_shared_data.amss_entry_ptr() 交割 AMSS,他们分别在两个处理器上同时运行,两个处理期间通过 smd 进行通信。
osbl_main_procs 在文件:
./AMSS/products/7x30/core/boot/secboot2/osbl/target/msm7x30/src/osbl_mc_target.c:524中,它定义了一些初始化函数:
osbl_procedure_func_type osbl_main_procs[] =
{
...
//初始化 迷你usb 充电硬件
osbl_hw_init,
...
//在 osbl 阶段会提升系统时钟
#ifndef RUMIBUILD
osbl_increase_clk_speed,
#endif
...
//初始化 osbl 模并且锁住接口
osbl_init_modules,
...
初始化 flash 设备
osbl_flash_init,
...
//检测是否通过sd卡更新镜像文件
osbl_sd_image_upgrade,
...
//初始化数据结构,以便装载 AMSS 镜像
osbl_init_amss_image,
...
#ifdef FEATURE_FOTA
/*-----------------------------------------------------------------------
* Initialize FOTA
*-----------------------------------------------------------------------*/
osbl_fota_init,
#endif /* FEATURE_FOTA */
//amss 镜像进行授权鉴定
osbl_auth_amss_image,
//如果有 adsp 那么进行相应处理
#ifdef FEATURE_OSBL_LOAD_AND_BOOT_ADSP
//装载 adsp 镜像
osbl_load_adsp,
//授权
osbl_auth_adsp,
#endif
#ifdef FEATURE_SDCC_BOOT
//装载 amss 镜像
osbl_load_amss_image,
...
#endif
#ifndef FEATURE_STANDALONE_MODEM
//从flash 设备装载 appsboot
osbl_load_appsbl,
...
//从flash中装载 OS 镜像
* Load the OS image from flash
osbl_load_apps_os,
//引导 aARM 处理器
osbl_boot_aarm,
#endif /* FEATURE_STANDALONE_MODEM */
对于 nand 启动,AMSS 应该在 apps 引导以后再装载
#ifndef FEATURE_SDCC_BOOT
// nand 启动,装载 amss 镜像
osbl_load_amss_image,
#endif
...
};
1.4.4.1 osbl 装载 appsbl 过程分析
osbl 通过 osbl_load_appsbl 函数装载应用程序的 boot loader 到指定的 RAM 中
osbl_load_appsbl 在文件:
./AMSS/products/7x30/core/boot/secboot2/osbl/shared/src/osbl_aarm_boot.c:119 中
void osbl_load_appsbl( bl_shared_data_type *bl_shared_data )
{
...
/*从 flash 中装载 appsbl 头和镜像到 RAM 中*/
osbl_load_header_and_image_with_cookie( APPSBL_IMG, &appsbl_image_header_with_cookie );
...
/*如果 boot loader 没有装载到地址 0x0, 那么将会拷贝 appsbl 向量表到地址 0x0, appsbl 镜像的向量表总是在在镜像的头 64字节中*/
if ( apps_image_start_addr != 0x0 )
{
/* 为 L4 with kernel entry 初始化复位向量,其他的向量赋值为 无限循环*/
复位向量的初始化值与 appsbl 镜像起始地址有关,复位的时候此值会被放入到 PC 寄存器
向量 0x00000020 中保存 appsbl 镜像的起始地址
向量 0x00000000 中的值为 0xE59FF018
address 0x00000000: ldr pc, [pc, #0x18]
address 0x00000020: apps_image_start_addr */
uint32 *vector_ptr = (uint32*) 0x00000020;
*vector_ptr = apps_image_start_addr;
for ( --vector_ptr; vector_ptr; vector_ptr-- )
{
*vector_ptr = 0xEAFFFFFE; /* Infinite loop */
}
*vector_ptr = 0xE59FF018; /* ldr pc, [pc, #0x18] */
}
} /* osbl_load_appsbl() */
osbl_load_header_and_image_with_cookie 函数完成 appsbl 镜像头和镜像的装载,它首先会尝试从 mibi 中装载 appsbl 镜像头,如果当前是 nor non-partition table 设备,那么装载将会成功,如果不成功,那么认为 appsbl 头位于它分区的起始位置,将其读出。
1.4.5 appsbl 流程(源代码在 android中)
appsbl 是 applications ARM boot loader 的简称,不同的软件框架,此分区来自不同的源代码
在android 系统中 appsbl 代码为 bootable/bootloader/lk
brew 框架的系统中 appsbl 代码在 ./AMSS/products/7x30/core/boot/appsproc/target/msm7x30/src
brew 框架系统,入口函数 __main -> appsbl_main_ctl 在文件:
./AMSS/products/7x30/core/boot/appsproc/target/msm7x30/src/appsbl_handler.s 中。
android 系统中有:
vendor/qcom/msm7630_surf/AndroidBoard.mk:25:
include bootable/bootloader/lk/AndroidBoot.mk
bootable/bootloader/lk/arch/arm/system-onesegment.ld
system-onesegment.ld 中 ENTRY(_start) 指定了 appsbl 分区从 _start 函数开始执行,此函数在文件 ./bootable/bootloader/lk/arch/arm/crt0.S:25 中:
...
.text
.globl _start
_start:
b reset
...
bl kmain
...
kmain 会跳转到 C 文件中执行,此函数文件
bootable/bootloader/lk/kernel/main.c 中:
void kmain(void)
thread_resume(thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
static int bootstrap2(void *arg)
{
arch_init();
platform_init();
target_init();
apps_init();
return 0;
}
apps_init 在文件:bootable/bootloader/lk/app/app.c:33 中:
/* one time setup */
void apps_init(void)
{
const struct app_descriptor *app;
/* call all the init routines */
for (app = &__apps_start; app != &__apps_end; app++) {
if (app->init)
app->init(app);
}
/* start any that want to start on boot */
for (app = &__apps_start; app != &__apps_end; app++) {
if (app->entry && (app->flags & APP_FLAG_DONT_START_ON_BOOT) == 0) {
start_app(app);
}
}
}
因为:bootable/bootloader/lk/include/app.h:45 中有:
#define APP_START(appname) struct app_descriptor _app_##appname __SECTION(".apps") = { .name = #appname,
#define APP_END };
bootable/bootloader/lk/app/aboot/aboot.c 中有:
APP_START(aboot)
.init = aboot_init,
APP_END
所以有:
struct app_descriptor _app_aboot __SECTION(".apps") =
{
.name = aboot,
.init = aboot_init,
};
所以 apps_init 函数中的: app->init 实际上调用的是文件:
bootable/bootloader/lk/app/aboot/aboot.c:398 中的函数 aboot_init
1.4.5.1 aboot_init 过程分析(需要侧重关心的部分)
aboot_init 阶段我们应该关心 fastboot 模式 和 appsbl 对 android 系统的引导过程。
void aboot_init(const struct app_descriptor *app)
{
unsigned reboot_mode = 0;
page_size = flash_page_size();
page_mask = page_size - 1;
if (keys_get_state(KEY_HOME) != 0)
boot_into_recovery = 1;
if (keys_get_state(KEY_BACK) != 0)
goto fastboot;
if (keys_get_state(KEY_CLEAR) != 0)
goto fastboot;
reboot_mode = check_reboot_mode();
if (reboot_mode == RECOVERY_MODE){
boot_into_recovery = 1;
}else if(reboot_mode == FASTBOOT_MODE){
goto fastboot;
}
recovery_init();
//从falsh上读取 linux 然后引导
boot_linux_from_flash();
dprintf(CRITICAL, "ERROR: Could not do normal boot. Reverting "
"to fastboot mode.n");
fastboot:
display_init();
dprintf(INFO, "Diplay initializedn");
udc_init(&surf_udc_device);
fastboot_register("boot", cmd_boot);
fastboot_register("erase:", cmd_erase);
fastboot_register("flash:", cmd_flash);
fastboot_register("continue", cmd_continue);
fastboot_register("reboot", cmd_reboot);
fastboot_register("reboot-bootloader", cmd_reboot_bootloader);
fastboot_publish("product", "swordfish");
fastboot_publish("kernel", "lk");
fastboot_init((void*) SCRATCH_ADDR, 100 * 1024 * 1024);
udc_start();
}
recovery_init() 调用的是文件 bootable/bootloader/lk/app/aboot/recovery.c中的函数:
/* Read and write the bootloader command from the "misc" partition.
* These return zero on success.
*/
从 misc 分区读取
struct bootloader_message {
char command[32];
char status[32];
char recovery[1024];
};
/* Read and write the bootloader command from the "misc" partition.
* These return zero on success.
*/
int get_bootloader_message(struct bootloader_message *out);
int set_bootloader_message(const struct bootloader_message *in);
/* Write an update to the cache partition for update-radio or update-hboot.
* Note, this destroys any filesystem on the cache partition!
* The expected bitmap format is 240x320, 16bpp (2Bpp), RGB 5:6:5.
*/
int write_update_for_bootloader(
const char *update, int update_len,
int bitmap_width, int bitmap_height, int bitmap_bpp,
const char *busy_bitmap, const char *error_bitmap);
ROM上又分为几个分区:boot, system, recovery, cache, userdata和misc。在boot上存着bootloader和Linux Kernel,system上面是Android系统,userdata包含登录信息/个人软件和设置等。recovery区里放着的是如何控制系统恢复的工具,如Google官方的stock恢复器。系统开机的时候,bootloader会首先检查硬件配置,然后将Radio Firmware写入RAM,接着调进kernel,最后再装载Android OS进入桌面
misc - misc分区,一般不会去动它,和我们没有太大关系
recovery -recovery分区
boot - 存储linux系统内核的分区,包括 kernel 和 ramdisk 两部分
system -系统分区,储存着Android系统的数据,刷 ROM 主要刷的是这个
cache -缓存分区,刷ROM时最好一起擦一下
Dalvik-cache- 这个是Android使用的Java虚拟机的缓存分区,刷ROM时最好一起擦一下
userdata - 用户自己使用的数据部分,存储我们自己的软件设置等等,恢复出厂设置的时候,这个分区会被格式化
还有Radio,这个部分通常负责无线信号,可以理解为手机信号收发部分的驱动,不过N1的视频编码器也集成在这里面,Radio可以随便刷,不过某些特定的ROM可能会指定Radio版本。
最后是SPL/Bootloader,这个我们一般不会用到它也不会修改它,除了第一次解锁的时候(不过解锁信息储存在哪里,现在xda上也没有定论,似乎不是在SPL里面,这个大致相当于电脑上的 BIOS,负责整个手机的最底层引导,坏了可能导致变砖。
recovery 分区的 init.rc 文件比较简单
./out/target/product/msm7630_surf/recovery/root/init.rc
service recovery /sbin/recovery
service adbd /sbin/adbd recovery
on property:persist.service.adb.enable=1
start adbd
on property:persist.service.adb.enable=0
stop adbd
它只启动了 /sbin/recovery /sbin/adbd
Recovery 可执行程序的mian函数在
bootable/recovery/recovery.c
ui_init(); 初始化 recovery 模式的界面
get_args(&argc, &argv); 获取按键选择
prompt_and_wait()
install_package()
handle_update_package()
try_update_binary(path, zip)
handle_firmware_update(firmware_type, firmware_filename, zip)
remember_firmware_update(type, data, data_size)
update_type = type;
update_data = data;
update_length = length;
maybe_install_firmware_update(send_intent);
write_update_for_bootloader() 写入数据
snprintf(boot.command, sizeof(boot.command), "update-%s", update_type);
set_bootloader_message(&boot)
才是真正的更新 radio.img
1、下载最新的CursorSense的ROM:CursorSense32A-Mod-0.9.1.1-signed,和要求的RADIO(radio6.35.07.29.img),SPL(hboot1.76.2007.img),HERO的RECOVERY(recovery-RA-hero-v1.5.2.img)
2、在FASTBOOT下用下面的命令开刷(文件改过名):
fastboot flash hboot hboot.img
fastboot flash radio radio.img
fastboot erase system -w
fastboot erase boot
fastboot erase recovery
fastboot flash recovery recovery.img
1.4.5.1.1 fastboot 模式分析
1.4.5.1.1.1 什么是 fastboot 模式
fastboot 是android 系统的软件烧写模式,通过它我们可以为系统烧写软件
参考文档:
工程模式與FASTBOOT
http://android.cool3c.com/article/2260
1.4.5.1.1.2 fastboot 模式与 recovery 模式的区别
fastboot 模式 和 recovery 模式都是 android系统的软件烧写或者升级方式,通过他们可以为机器烧写软件。
他们有如下区别:
1. 代码来自不同分区,fastboot 在 appsbl 分区 ,recovery 是单独的一个分区
2. fastboot 比 recovery 功能更强,它可以用来烧写 recovery 分区
fastboot 可以做的事情:
1. 重启机器
2.烧写分区
3. 擦除分区
4. 重启 appsbl
5. 系统更新等
常有如下命令:
fastboot reboot 重启机器
fastboot flash boot boot.img 烧写引导分区
fastboot flash system system.img 烧写系统分区
fastboot flash userdata data.img 烧写数据分区
fastboot flash recovery recovery.img 烧写恢复模式分区
fastboot flash splash1 mysplash.rgb565 烧写开机画面
fastboot erase system 擦除系统分区
fastboot update update.zip update.zip 是 boot.img, system.img和recovery.img的zip压缩包
以上子命令不一定存在,要根绝实际情况确定。fastboot 中是通过 fastboot_register 方式注册了一系列可用的子命令,如:
fastboot_register("boot", cmd_boot);
fastboot_register("erase:", cmd_erase);
fastboot_register("flash:", cmd_flash);
fastboot_register("continue", cmd_continue);
fastboot_register("reboot", cmd_reboot);
fastboot_register("reboot-bootloader", cmd_reboot_bootloader);
fastboot_register("getvar:", cmd_getvar);
fastboot_register("download:", cmd_download);
我们可以根绝实际情况修改 fastboot 代码,让其支持更多命令,如:
fastboot flashall 在当前目录寻找各种所有的image文件,在刷完所有分区后重启手机
recovery 分区只能对 system ,data,cache boot 等分区进行烧写,sd卡上放 update.zip 的升级方式就可以通过 recovery 的方式完成。
除了 fastboot 模式可以烧写 recovery ,在 android 系统的命令模式下可以通过 flash_image 命令
./out/target/product/msm7630_surf/symbols/system/bin/flash_image 进行烧写。
flash_image recovery /sdcard/recovery.img 红色部分是你解压出的文件名包含后缀名
reboot recovery
之后就能看到新的recovery 了
E/flash_image( 35): can't find recovery partition
参考资料:
最新Amon-RA 1.3.2 Recovery原创教程(完成)
http://www.androidin.net/bbs/thread-29285-1-1.html
1.4.5.1.1.3 怎样进入 fastboot 模式
在系统启动的 appsboot 阶段,通过以下几种方式可以进入 fastboot 模式
1. 通过按键,如: KEY_BACK 或者 KEY_CLEAR 等
2. 当前系统的重启模式,如果为 FASTBOOT_MODE
3. 引导linux失败
unsigned check_reboot_mode(void)
{
unsigned mode[2] = {0, 0};
unsigned int mode_len = sizeof(mode);
unsigned smem_status;
smem_status = smem_read_alloc_entry(SMEM_APPS_BOOT_MODE,
&mode, mode_len );
if(smem_status)
{
dprintf(CRITICAL, "ERROR: unable to read shared memory for reboot moden");
return 0;
}
return mode[0];
}
bootable/bootloader/lk/platform/msm_shared/smem.h:83: SMEM_APPS_BOOT_MODE = 106
按键进入 fastboot 模式要根据实际情况决定,因为这些在代码中都是可以更改的,参考文档:
市面常见机器进入 Recovery 模式及 Fastboot 模式的方法:http://android.cool3c.com/article/12221
1.4.5.1.1.4 android 系统手机刷机过程分析(补充知识)
将以 G1 为样机分析刷机过程
放到SD卡根目录(不要改名,直接丢进去)
打开终端输入
su(回车r)
mount -o rw,remount -t yaffs2 /dev/block/mtdblock3 /system (回车)
cd sdcard (回车r)
flash_image recovery recovery-RAv1.2.1G.img (回车)
以上是从一个帖子里找来的。上面说不要改名,我改了名字刷成功了。
1.4.5.1.2 appsbl 引导 android 系统
appsbl 对 android 系统的引导是从 boot_linux_from_flash 开始,它首先引导 linux 内核,然后由 linux 内核装载引导上层的 android 系统。
boot_linux_from_flash() 函数在文件:
bootable/bootloader/lk/app/aboot/aboot.c:182 中。
它实际上是从 boot 分区中读取 boot.img (内核+ramdisk)然后引导执行,具体过程如下:
int boot_linux_from_flash(void)
{
struct boot_img_hdr *hdr = (void*) buf;
unsigned n;
struct ptentry *ptn;
struct ptable *ptable;
unsigned offset = 0;
const char *cmdline;
首先判断是否为 eMMC启动
if (target_is_emmc_boot()) {
hdr = (struct boot_img_hdr *)EMMC_BOOT_IMG_HEADER_ADDR;
if (memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
dprintf(CRITICAL, "ERROR: Invalid boot image headern");
return -1;
}
goto continue_boot;
}
获取分区表
ptable = flash_get_ptable();
if (ptable == NULL) {
dprintf(CRITICAL, "ERROR: Partition table not foundn");
return -1;
}
如果不是进入 recovery 模式
if(!boot_into_recovery)
{
ptn = ptable_find(ptable, "boot");
if (ptn == NULL) {
dprintf(CRITICAL, "ERROR: No boot partition foundn");
return -1;
}
}
//进入 recovery 模式
else
{
ptn = ptable_find(ptable, "recovery");
if (ptn == NULL) {
dprintf(CRITICAL, "ERROR: No recovery partition foundn");
return -1;
}
}
//读取 boot.img
if (flash_read(ptn, offset, buf, page_size)) {
dprintf(CRITICAL, "ERROR: Cannot read boot image headern");
return -1;
}
offset += page_size;
if (memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
dprintf(CRITICAL, "ERROR: Invaled boot image headorn");
return -1;
}
if (hdr->page_size != page_size) {
dprintf(CRITICAL, "ERROR: Invaled boot image pagesize. Device pagesize: %d, Image pagesize: %dn",page_size,hdr->page_size);
return -1;
}
//获取 kernel 镜像文件地址
n = ROUND_TO_PAGE(hdr->kernel_size, page_mask);
if (flash_read(ptn, offset, (void *)hdr->kernel_addr, n)) {
dprintf(CRITICAL, "ERROR: Cannot read kernel imagen");
return -1;
}
offset += n;
//获取 ramdisk 镜像文件地址
n = ROUND_TO_PAGE(hdr->ramdisk_size, page_mask);
if (flash_read(ptn, offset, (void *)hdr->ramdisk_addr, n)) {
dprintf(CRITICAL, "ERROR: Cannot read ramdisk imagen");
return -1;
}
offset += n;
continue_boot:
dprintf(INFO, "nkernel @ %x (%d bytes)n", hdr->kernel_addr,
hdr->kernel_size);
dprintf(INFO, "ramdisk @ %x (%d bytes)n", hdr->ramdisk_addr,
hdr->ramdisk_size);
if(hdr->cmdline[0]) {
cmdline = (char*) hdr->cmdline;
} else {
cmdline = DEFAULT_CMDLINE;
}
dprintf(INFO, "cmdline = '%s'n", cmdline);
/* TODO: create/pass atags to kernel */
//开始引导内核
dprintf(INFO, "nBooting Linuxn");
boot_linux((void *)hdr->kernel_addr, (void *)TAGS_ADDR,
(const char *)cmdline, board_machtype(),
(void *)hdr->ramdisk_addr, hdr->ramdisk_size);
return 0;
}
boot_linux 调用的文件:
bootable/bootloader/lk/app/aboot/aboot.c:94 中的函数:
void boot_linux(void *kernel, unsigned *tags,
const char *cmdline, unsigned machtype,
void *ramdisk, unsigned ramdisk_size)
{
...
void (*entry)(unsigned,unsigned,unsigned*) = kernel;
...
entry(0, machtype, tags);
}
entry(0, machtype, tags); 正式进入内核,将由kernel 完成 android 系统的启动。
====================================
osbl_load_appsbl:
This function loads the applications ARM boot loader to its
destination RAM. It may load the aARM from flash or from data
contained within the OEM SBL image depending on OEM security
requirements.
osbl_load_apps_os:
This function loads the APPS image from flash to its destination
address in RAM. A cookie read from the APPSBL header is checked for
the size of OS image and magic number. If the magic number matches and
the size of apps image is greater than 0, the image is loaded.
osbl_load_apps_os 函数在文件:
./AMSS/products/7x30/core/boot/secboot2/osbl/shared/src/osbl_aarm_boot.c:394 中:
void osbl_load_apps_os( bl_shared_data_type *bl_shared_data )
/* Initialize unified boot interface */
unified_boot_init(&appsbl_image_header_with_cookie);
./AMSS/products/7x30/core/boot/tools/headergen/shared/src/image_header.c:492:
boot_cookie.OS_type = atoi(argv[i+5]);
header[12] = boot_cookie.OS_type; /* OS type to boot */
nand_tools 工具来自源代码:
编译脚本:
./AMSS/products/7x30/core/bsp/tools/flash/nand_exe/build/SConscript
========================================
env.Replace(TARGET_NAME = 'nand_tools')
nand_tools_exe = env.Program('${TARGET_NAME}', source=[], LIBS=libs, LIBPATH=libs_path)
# copy elf and reloc to needed locations for AMSS tools to load on target
install_target_exe = env.Install(SRCPATH, nand_tools_exe)
========================================
nand_tools 工具语法:
./AMSS/products/7x30/core/bsp/tools/flash/nand_exe/build/nand_tools -fp flash_page_size -fb flash_block_size -fd flash_device_size -d device_bootloader_fname -u usr_partition_fname -m mibib_partition_fname -p binary_folder_path
每一个烧写的 *.mbn 都有一个标准的头,它由函数
/*----------------------------------------------------------------------
Fill up header structure
----------------------------------------------------------------------*/
header[0] = id;
header[2] = image_source;
header[3] = image_dest;
header[4] = image_size;/* image_size */
header[5] = code_size; /* code_size */
header[6] = image_dest+code_size; /* signature_ptr */
header[7] = signature_size; /* signature_size */
header[8] = image_dest+code_size+signature_size;/* cert_chain_ptr */
header[9] = cert_chain_size; /* cert_chain_size*/
header[10] = UNIFIED_BOOT_COOKIE_MAGIC_NUMBER; /* boot cookie magic number */
header[11] = 0; /* cookie version number */
header[12] = boot_cookie.OS_type; /* OS type to boot */
header[13] = 0; /* start address of apps partition in storage device */
header[14] = boot_cookie.boot_apps_size_entry; /* size in bytes of apps kernel to be loaded */
header[15] = boot_cookie.boot_apps_ram_loc; /* location in RAM to load apps kernel */
header[16] = 0; /* reserve pointer */
header[17] = 0; /* reserve for future use */
header[18] = 0; /* reserve for future use */
header[19] = 0; /* reserve for future use */
printf("image_size = 0x%X, code_size= =0x%Xn", image_size, code_size);
/*----------------------------------------------------------------------
Open output header file
----------------------------------------------------------------------*/
因为文件:
./AMSS/products/7x30/build/ms/boot_targets_nonsec.min:346
./AMSS/products/7x30/build/ms/boot_targets_sec.min:498
中有:
GEN_AMSS_HEADER = $(HEADERGEN)/image_header $(FLASH_TYPE) amss $(MBNPATH)/amss.mbn $(MBNPATH)/amsshd.mbn
语法如下:
Usage: ./AMSS/products/7x30/tools/headergen/image_header flash_type header_type input_code_file
output_header_file secure_type [dbl_preamble_file or elf_src_file]
例如:
./AMSS/products/7x30/tools/headergen/image_header nand amss ./AMSS/products/7x30/build/ms/bin/AAABQMAZ/amss.mbn amssh.mbn dbl_preamble_file
./AMSS/products/7x30/tools/headergen/image_header "nand" amss ./AMSS/products/7x30/build/ms/bin/AAABQMAZ/amss.mbn ./aaahd.mbn
文件: ./AMSS/products/7x30/build/ms/dmss_flags.min:131: 中有:
ifeq ($(USES_NOR16_CFG_DATA)$(USES_NOR32_CFG_DATA),yes)# NAND or NOR
FLASH_TYPE=nor
else
FLASH_TYPE=nand
endif
从我们的环境变量可以知道使用的是 nand flash
#pragma RUNLOCAL
$(MBNPATH)/amsshd.mbn: $(IMAGE_HEADER) $(MBNPATH)/amss.mbn
@echo ---------------------------------------------------------------
@echo Generating image header for AMSS.
@echo
@$(GEN_AMSS_HEADER)
@echo ---------------------------------------------------------------
1.4.5.1.2.1 Android 系统启动过程中存在的问题
1.4.5.1.1.1.1 linker 问题导致系统无法启动
高通 sdk 打印信息:
D/qemud ( 37): fdhandler_accept_event: accepting on fd 10
D/qemud ( 37): created client 0xe078 listening on fd 8
D/qemud ( 37): client_fd_receive: attempting registration for service 'boot-properties'
D/qemud ( 37): client_fd_receive: -> received channel id 1
D/qemud ( 37): client_registration: registration succeeded for client 1
I/qemu-props( 47): connected to 'boot-properties' qemud service.
I/qemu-props( 47): received: qemu.sf.lcd_density=160
I/qemu-props( 47): received: dalvik.vm.heapsize=16m
D/qemud ( 37): fdhandler_accept_event: accepting on fd 10
D/qemud ( 37): created client 0xe078 listening on fd 11
D/qemud ( 37): fdhandler_event: disconnect on fd 11
D/qemud ( 37): fdhandler_accept_event: accepting on fd 10
D/qemud ( 37): created client 0xe078 listening on fd 11
D/qemud ( 37): client_fd_receive: attempting registration for service 'gsm'
D/qemud ( 37): client_fd_receive: -> received channel id 2
D/qemud ( 37): client_registration: registration succeeded for client 2
通过ps可以看出,主要是因为 zygote 未能正常启动,手动启动该服务:
/system/bin/app_process -Xzygote /system/bin --zygote &
弹出一些错误信息:
# link_image[1729]: 71 could not load needed library 'libandroid_runtime.so' for '/system/bin/app_process' (link_image[1729]: 71 could not load needed library 'libnativehelper.so' for 'libandroid_runtime.so' (link_image[1729]: 71 could not load needed library 'libicudata.so' for 'libnativehelper.so' (alloc_mem_region[823]: OOPS: 71 cannot map library 'libicudata.so'. no vspace available.)))CANNOT LINK EXECUTABLE
从以上信息可以断定,是应用程序在linker的时候未能装载需要的库,导致服务终止。
因为我们目前编译的sdk和generic版本都是给予 armv5te ,而高通是 armv7 所以暂时不建议修改代码
我们可以先从网上 sdk 的 elair版本中考取 linker 文件,拷贝到:
out/target/product/generic/system/bin/ 然后重新打包 system.img : make snod
bionic/linker/linker.c
#define LINKER_BASE ((LINKER_TEXT_BASE) & 0xfff00000)
#define LINKER_TOP (LINKER_BASE + (LINKER_AREA_SIZE))
======标准代码========
LINKER_TEXT_BASE := 0xB0000100
LINKER_AREA_SIZE := 0x01000000
#define LIBBASE 0x80000000
#define LIBLAST 0x90000000
LINKER_BASE=0xB0000000
======高通======
LINKER_TEXT_BASE := 0x70000100
LINKER_AREA_SIZE := 0x01000000
#define LIBBASE 0x40000000
#define LIBLAST 0x50000000
#define R_ARM_REL32 3
LINKER_BASE=0x70000000
===============
R_ARM_ABS32 32bit 绝对地址重定位引用
R_ARM_PC24 24bit PC相对地址重定位引用
R_ARM_ABS32 32bit 绝对地址重定位引用
R_ARM_REL32 32bit 相对地址重定位引用
REL 是 relative 的缩写,是以当前指令结束时的EIP为参考地址
ABS 是 absolute 的缩写,指绝对地址.
rel32 立即数
r32 寄存器
m32 内存访问
1.4.6 AMSS 流程
osbl 阶段,通过函数 osbl_load_amss_image 装载 amss 镜像文件
void osbl_load_amss_image( bl_shared_data_type *bl_shared_data )
{
...
/* 获取 elf 文件的入口点 */
bl_shared_data->amss_entry_ptr = (amss_entry_ptr_type) boot_sec_elf_get_entry_point( bl_shared_data->amss_elf_if );
...
} /* osbl 装载 amss 镜像文件 */
在 osbl_main_ctl 函数中通过 bl_shared_data.amss_entry_ptr() 把控制权交给了 AMSS。
在文件:
AMSS/products/7x30/core/kernel/arch/arm/pistachio/src/gnu/linker.lds:33: 中有:
ENTRY(_start)
所以可以确定 AMSS 的镜像是从 _start 函数开始执行,该函数在文件:
AMSS/products/7x30/core/kernel/arch/arm/pistachio/src/head.spp:51: 中
。。。
BEGIN_PROC(_start)
。。。
/* Jump to startup_system */
adr r0, __phys_addr_ram
bl arch_init
。。。
Amss 镜像由几部分组成,
AMSS/products/7x30/core/kernel/tools/amss.py
def get_amss_kernel_platform_src(build_asic, build_target, platform_dir):
platform_src = ["%s/src/" % platform_dir + fn for fn in ["plat_asm.spp", "timer.cc", "irq.cc", "plat.cc", "init_warm.cc", "head.spp" ]]
AMSS/products/7x30/core/kernel/arch/arm/pistachio/src/head.spp:51:
BEGIN_PROC(_start)
TASK_COMMON_SOURCES = [
'${BUILDPATH}/mobile.c',
'${BUILDPATH}/task.c',
'${BUILDPATH}/task_iram.c'
]
task_objs = env.Object(TASK_COMMON_SOURCES)
task_lib = env.Library('${BUILDPATH}/task', task_objs)
./AMSS/products/7x30/core/debugtools/task/build/corelibs/arm11/task.lib
env.AddLibsToImage(['MODEM_IMAGE', 'CBSP_MODEM_IMAGE'],
[task_lib,
task_dog_lib,
task_dog_keepalive_modem_lib,
task_dog_keepalive_client_lib])
./AMSS/products/7x30/core/bsp/build/scripts/utils.py:59:
env.AddMethod(add_libs_to_image, "AddLibsToImage")
./AMSS/products/7x30/core/bsp/build/scripts/utils.py:140:
def add_libs_to_image(env, targets, libs):
./AMSS/products/7x30/core/bsp/amsslibs/build/arm11/SConscript:65:env.Replace(MODEM_IMAGE = env.subst('${PROC}'))
./AMSS/products/7x30/core/bsp/build/msm7x30_modem.mak:34:PROC = MULTI_PROC
IMAGE=MODEM_PROC
./AMSS/products/7x30/modem/rfa/rf/task/common/inc/rf_task.h:79:TASK_START_SIG 0x8000
./AMSS/products/7x30/core/boot/appsproc/target/msm7x30/src/process.c:31: SMSM RESET state to process_restart from err.c.
./AMSS/products/7x30/core/debugtools/err/src/err.c:808: process_restart();
err_fatal_jettison_core
-> err_fatal_handler
代码运行到了Main()之后,在这个函数里面将完成操作系统(rex)的初始化工作,其实现方法是调用rex_init()。Rex_init()完成的工作很简单:
完成操作系统必要的一些数据结构(timer链表、任务链表等))的初始化之外;
接下来,它创建了三个任务,分别是:rex_idle_task、rex_dpc_task和tmc_task。
Idle任务没什么好解释的,目前这个任务为空,什么也没做,dpc_task目前不知道是做什么的,暂时可以不用管。前面的这两个任务都属于操作系统层面的,由操作系统来维护,和手机软件关系不大。哪一个和手机软件关系大呢?答案是:tmc_task。大家可以把这个当作操作系统的入口(主)任务,也可以把它当作整个手机软件的入口任务。即AMSS软件里的所有其它任务的创建和维护就是由这个tmc_task来完成的。
到此为止,整个AMSS软件还并没有跑起来,只是跑到了tmc_task里面了。在tmc_task里面,会调用tmc_init()来完成整个AMSS软件包的初始化工作,其中最重要的一项工作就是调用tmc_define_tasks()将AMSS软件包所有需要的任务都创建起来了。比如说slee_task、dog_task、cm_task、wms_task、ui_task等。这些任务,一般不需要直接和AL层软件打交道,但请大家记住,手机上所有功能的实现最根本点就是由这些服务组件(Service Task)来完成的。将来大家跟踪一个具体的功能模块时,比如说通话模块,如果需要,可以再去深入研究它的具体实现。
好了,到现在为止,所有的AMSS核心软件就全部跑起来了(手机的功能模块,在软件方面就体现为OS层面的一个任务)。但现在大家还根本看不到Brew和AEE的影子。呵呵,各位不要急。到了这个层面之后,我想稍微多说几句。最早的Qualcomm平台,比如说5xxx系列,是根本没有Brew的,那个时候的AL(Application Layer)层软件开发,是直接调用底层Service task所提供的API来完成相应的工作的。从这种角度来看的话,显然那时的开发是比较郁闷和难度较高的。不过,到了65xx之后,Qualcomm平台引入了Brew,手机开发商就没必要去从这么底层(Service API)的层面进行手机开发了,他们完全可以基于Brew来实现一台手机的所有功能(Qualcomm给我们的参考代码,就是全Brew平台的)。
Brew的运行环境AEE是如何跑起来的呢?关键在于ui_task(),由于ui_task和我们手机开发的关系非常密切,其地位也相当重要,所以,后文我将单独对它进行一个深入的研究与分析。到目前为止,大家只需要知道ui_task将AEE加载起来了,并且,它起到了一个中间层的作用,即所有AMSS底层服务组件的消息,都将经由ui_task而转到AEE,并最终转到具体的App(Applet)的执行代码里面(HandleEvent())。
注意:
上述的开机过程,在每一次按开机键都需要走一遍,即关机之后,整个系统的所有功能都将消失,而不像有些手机,看起来是关了机,但实际上底层还是有一些软件模块在跑。为什么可以肯定地说上述开机过程每次都必须走一遍,原因很简单,因为我们的平台软件是基于Nand Flash启动的,所有的代码都需要Copy到SDRAM才能运行,而关机断电之后,SDRAM里的东东会全部丢失,所以,毫无疑问,上述的过程必须每次开机都执行;
关机的过程相对比较简单,系统检测到关机中断之后,将调用tmc_powerdown_handler()来完成关机动作,它将把所有AMSS的任务都Stop掉,并最后调用rex_exit()退出Rex,从而完成整个关机动作。
显然,关机动作前,如果有必要,每一个任务必须将它希望保存的信息保存到Flash上面,以便下次开机时可以得到这些信息;
开机流程简图
EMBED Visio.Drawing.11
图1 Qualcomm平台开机框图
说明:
Tmc是操作系统层面和AMSS软件关系最密切的一个任务,不过需要OEM商在此处修改的地方应该不多;
ui_task是在操作系统层面,OEM商需要重点研究清楚的一个任务,它是连接底层Task和上层AL的一个中间层,有可能需要加入OEM商的操作流程;
CoreApp是在Brew层面的一个AL层的入口Applet,它其着管理整个上层AL层软件的作用,根据产品需求,这个App需要定做;
AEE是整个上层App的运行环境,目前Qualcomm没有公开它的源码,但它的运行机制,Amoi需要好好研究清楚,我将在另外一篇《Qualcomm平台AEE运行机制深入分析与研究》中探讨它的运行机理和调度机制,大家有兴趣可以参考此文;
Boot代码深入分析
Boot代码大部分是用汇编语言写的,也有小部分,可能需要由OEM商修改,所以用C语言来写。另外,Boot代码属于Driver范围,所以大家可以在drivers/boot目录里面找到相应的代码。Boot的代码组织得非常模块化,整个boot的入口点是在Boot_function_table.s里面,这个汇编代码里面实际上是将Boot需要完成的任务封装成了不同的函数,由不同的函数来完成相应的工作,接下来,我将深入分析这些函数所完成的工作,如下所述。
mmu_enable_instruction_cache;
这个只有在Nand启动模式时才需要,打开ARM的指令Cache.
boot_hw_ctrl_init
此函数主要是完成两条总线(EBI1、EBI2)控制器的初始化,这个函数执行完了 之后,系统就可以知道两条总线上连接了哪些设备,同时也可以找得到这些 设备,不过,至于单个设备自身的初始化,则不在这里.
[注]
这个函数很重要,OEM商如果需要加新的设备到系统中(挂在两条总线上),则需
要定做此模块,目前阶段主要是内存。另外,如前文所述,这个函数是由C语言
来写的,主要目的就是为了方便OEM商定做。内存设备的修改,可以在这个模块
里找到相应的数据结构,相对还是比较简单的。
boot_hw_tlmm_init
1.晶振时钟的初始化;
2.中断表的初始化;
3.GPIO的初始化;
4.Msm本身的驱动,除了EBI2;
boot_rom_test
这个函数非常简单,只是做一个很简单的Rom检查.(比对两个标志位来检查,并
没有一块一块地去检查)。
boot_ram_test
Ram自检,具体算法其实也很简单,就是读、写内存以判断是否成功.
boot_ram_init
1.拷贝手机代码从Nand Flash到SDRAM。
a.Image__BB_RAM__Base:Core Code;
b.Image__APP_RAM__Base:App Code;
[注]
上述动作是分块进行的,原因是因为Qualcomm支持分块Boot Load.
2.将Image__ZI_REGION__ZI区域初始化为0;
3.初始化OEM要求的动态Heap;
4.至于代码段里的数据初始化,直接在Image里就完成了(编译器完成);
boot_stack_initialize
ARM栈初始化,主要是为分块代码加载而预留的.
boot_cache_mmu_init
ARM Mmu初始化
注意:
到此为止,整个Boot的工作就告完结了,那么,它又是如何跳到AMSS的main
入口点呢?原因很简单,ARM编译器在链接的时候会自动做出一个__rt_entry(),
由此函数来完成ARM库函数的初始化,并最后将代码执行点跳转到main()。而
__rt_entry()会在boot_reset_handler.s里调用,具体细节,大家可以不用太过关心,
只需要明白,Boot跑完之后,手机软件就跑到了main里就Ok了。
Ui_task的深入分析
从大的方向来讲,ui_task只完成两件事,一件是必要的初始化工作(这个也是我们所关心的,即ui_task到底完成了哪些工作);另外一件事就是各种信号量的事件处理,这也是我们比较关心的,即ui_task到底将哪些事件转发给了上层App。搞清楚了上述两点,我们也就能大致把ui_task的承上启下的工作机理研究清楚。
ui_Init;
初始化过程中,ui_task主要完成了如下几件事。
创建一个用于Kick Watchdog的定时器,这样WatchDog能够及时得到Kick,假如今后发现手机在ui_task里面自动重启,很有可能就是这个定时器的Timeout设置得过短而造成的;
注册通话相关的回调,主要是和紧急呼叫相关;
电话本初始化,之所以要进行这个工作,主要是加快开机之后AL层软件操作电话本的速度,但这样将有可能导致开机速度过慢,如果开机速度过慢,可以考虑进入待机界面之后,在后台开一个task去完成这项工作;
初始化Sound设备;
向底层服务任务wms_task注册wms回调,这个回调是在IWms组件里实现的。从这种角度来看,u帮我们把wms_task和IWMS组件联系起来了,但并没有去将AL层软件和IWMS联系起来,这个工作将是由AL层软件自己去完成。当然,注册回调的这个工作也是可以在AL层完成,之所以在这里完成,而不是在AL层完成,其主要目的是这个工作可以做到与AL层无关,即AL层不需要关心这个事情,但这个事情是短消息功能得于实现的必须步骤;
注册键盘消息回调;
通过这个回调,所有的按键消息都将经由底层的hs_task传到此回调函数里。然后回调函数将把所有的按键信息放到一个全局变量ui_key_buffer里面,接着发送一个UI_KEY_SIG信号给ui_task通知它去处理按键信息,至于ui_task如何处理按键消息的,后面的ui_handleSignals里会有详细描述。
初始化Lcd,这个工作不是LCD硬件设备的真正初始化,只是一些UI需要用到的LCD数据结构的初始化,和我们关系不大;
[注]
硬件的初始化,全部都在hs_task里面完成,从这种角度来看的话,系统能跑到ui_task里面,表明所有的硬件设备的驱动都已经成功加载。
置开机标志ui_powerup为True;
注册IPC信号量UI_IPC_SIG,这个可以暂时不管;
bridle_InitSWITable的初始化,这个目标,暂时不知道,也可以先略过;
初始化资源文件,其主要工作就是在Rom里面建立资源文件的符号链表,这样就可以让系统找到这些资源文件了(资源文件是被编译在代码段的,假如不这样做的话,系统将找不到这些资源文件);
Brew运行环境AEE的初始化:AEE_Init,这个函数看不到代码,大家只需要知道,到了这一步,整个Brew也就Run起来了,在AEE初始化完成之后,它将自动启动一个Applet,即CoreStartApp,而CoreStartApp将把CoreApp启动起来;
到此为止,ui_task的初始化工作完成;
[注意]
1) 从上述的ui_task的初始化工作可以看出,ui_task并没有完成手机AL层软件的
基本功能的初始化,比如说Sim卡检测、网络初始化等,这些工作,应该是在
CoreApp里完成的
2) 真正和手机功能相关的初始化工作,是在CoreApp里完成的,这个Applet的工
作机理,后面也会有详细描述;
ui_HandleSignals;
ui_task主要完成如下事件的处理。
看门狗喂食;
TASK_STOP_SIG信号,任务Stop,目前这个任务为空,没做任何事;
TASK_OFFLINE_SIG的处理,这几个任务都属于操作系统层面的事件,目前我们可以暂时不管;
处理关机信号:CoreAppHandleStopSig(),这个只是处理ui_task在关机前需要完成的任务,比如说发送一个消息给CoreApp让它关掉自己,然后将ui_task关闭;
[A]
系统的真正关机信号是由tmc来处理,当它发现需要关机时,调用tmc_powerdown_handler来完成相应的工作,在这里就是给所有的任务发送TASK_STOP_SIG的信号。
[A]
深层次的关机处理,不需要我们了解,也没必要去知道,我们只需要知道在ui_task里面把该关的关掉就Ok了。
[A]
关机是一个层层深入的过程,每一个App或者任务只需要负责将它们自己创建的资源释放掉就Ok了。而关机的导引线,显然是在CoreApp里截获到关机键之后发送出来的,事实上也是如此。
网络掉线时,发送掉线信号给CoreApp;
[A]
其实这个信号完全可以在CoreApp里面,自己去注册,然后及时更新自己的网络状态,就不知有没有这种接口函数。
处理按键消息,其主要完成如下的工作:
打开背光;
特理按键到虚键值的转换;
按键声音的处理;
将按键消息传送到AEE执行环境,由它去负责按键的派发;
[注]
1.背光的打开是由ui默认完成的,那这样的话,假如我不想按键时有背光,是否可行?看来就得修改此处的代码;
2.AEE的按键派发机制如何?它能否保证处于显示最上层的App永远是可以得到Key的App,即假如一个Applet将自身Hide,它是否依然可以得到Key,而其它的Applet是否就不可以得到了?很怕也像EMP一样出现焦点丢失的情况;
处理AEE_APP_SIG信号量,完成AEE的调度工作,这个任务是ui完成的最重要的一项工作,因为上层的App需要定时进行调度,目前看来,这个调度工作是由AEE_APP_SIG触发的,而AEE_APP_SIG这个信号量,则由操作系统层面的一个定时器定时发送的。现在大家只要了解,AEE_Dispatch会定时调用就Ok了,至于更详细的AEE调度机制,可以参考我的另外一篇《AEE运行机制深入分析与研究》;
处理AEE_SIO_SIG信号量,这个看不到代码,暂时略过不管;
结论
通过上述对于ui_task的分析,可以看出,ui_task真正和手机功能有关系的(即可能需要定制或者修改的地方),主要就是初始化资源文件和处理按键消息这两部分。至于其它部分,目前都不需要Amoi关心。手机真正功能的实现,比如说开机Logo的显示、Sim卡的检查、Pin码校验等,都是在CoreApp里面完成的。
其它
CoreApp的深入分析
目前参考代码里面的CoreApp所完成的工作比较多且杂,主要说来有如下几件事。
系统组件初始化;
开机Logo的显示;
Sim卡检测和Pin码校验;
系统状态信息更新;
电池状态;
网络信号;
网络模式;
IAnnunciator的维护与更新;
通话处理,打电话的输入框;
主菜单处理;
手机各种设置功能的处理;
关机键的处理;
目前CoreApp里面的代码,完成了太多的事,其实完全可以剥离成不同的模块来完成,大致可以分成如下几个部分。
总控模块;(CoreApp)
总控模块,主要完成手机按下开机键之后的各种初始化工作,同时此模块也是整个手机的控制中心,由它来完成手机的一些全局性工作,主要有如下几项。
系统初始化、Sim卡检测和Pin码校验;
开机Logo或者开机动画的显示;
底层服务程序的启动;(WmsApp、DialApp等);
系统配置信息的统一管理;
由于写配置信息到NV上面是一件非常慢的工作,每次上层App改变配置之后都去操作NV,很影响速度。所以,可以在内存中开一个配置信息的Buffer,上层App操作的实际上是这个Buffer,然后由Core在空闲的时候再统一写到NV上去。
关机处理;
[注]
由于CoreApp是在Idle Applet的界面之下,所以,为了能够实现“一键回菜单”的功用,有可能需要修改ui_task里面的Key处理函数,将所有的Key消息转发给Core,这样Core就可以得到所有的Key事件了。(现在的ui_task只把Key事件发送给了AEE,而AEE只会将Key事件发送给当前活动Applet)。
Idle模块;
主要完成待机界面的画图工作,主要有两部分:
系统信息指示栏;
待机界面(位图、动画、时钟、日历等);
软键
[注]
Idle只负责界面工作,不负责具体的系统状态信息的获取工作,这个工作将由其它模块完成。
Polling
手机状态信息查询模块,主要是完成手机各种状态信息的更新与维护。主要有如下几种:
电池强度;
网络信号强度;
网络模式(C/G);
PLMN网络名;
短消息、通话状态、闹铃;(这个由专门的模块完成,不在Polling之列);
各种外设信息;(USB、耳机插入等);
其它各种杂项信息;
Menu模块
菜单模块主要分两部分,一部分是主菜单的实现,另一个子菜单的实现。一般来讲,手机上的菜单系统应该是由Menu模块去统一完成,而不是由每一个子程序去手动完成。菜单模块一般只需要负责到主菜单、二级菜单和三级菜单就Ok了。三级菜单之后的界面,就由每一个App单独去维护了。
其它功能App模块;
每一个功能模块,由一个专门的App来完成,这样的话,模块的独立性强,便于单独开发。模块间通过App启动和消息传送的方式来发生关系和进行模块间通信。
后记
到此为止,Qualcomm整个手机从按下开机键到跑到主菜机界面,整个流程一目了然。对于Amoi而言,目前需要关心和定做的部分其实不多,最头疼的 当属CoreApp的改造工作,当然这个就是后话了,笔者将在今后的文章中加以详述。
希望本文对于大家理解Qualcomm手机软件的运行流程有一定的帮助,如果有什么问题,请直接联系我,最后谢谢大家耐心把本文看完,谢谢。
参考文档
a) 80-V1072-1_E_Boot_Block_Downloader.pdf
b) 80-V5316-1_K_QCT_Ext_API_RG.pdf
c) driver/boot目录源码
d) service/tmc目录源码
e) app/core目录源码
REX启动分析——基于Qualcomm平台
http://hi.baidu.com/gcmao/blog/item/5ef1ea2c12da08341e308914.html
Qualcomm手机开机全过程
Qualcomm手机开机全过程大揭密(四)
http://www.1mp.cn/DataShow.aspx?id=1642
Qualcomm手机开机全过程大揭密
chh@amoi.com.cn
2004-11-13
摘要:
本文试图通过代码来深入剖析Qualcomm手机开机的整个过程,即从按下开机键一直到出现待机界面,Qualcomm的手机软件在整个流程中究竟完成了哪些工作。本文的主要目标是理清手机的初始化流程,并为今后Amoi定做初始化工作提供一个参考。
关键字:开机、Rex、TMC、ui_task、CoreApp
开机的简要流程分析
Qualcomm的平台软件支持两种启动方式:一种是Nor Flash启动方式,另外一种就
是Nand Flash启动方式。Nor Flash启动方式就相当于硬件直接找到一个入口点开始执行代码,相比较而言会 比较简单,且Amoi没有采用此种方式,所以本文对于这种方式不做详细分析。另外一种就是Nand Flash启动方式,这种方式和PC的启动方式比较相像,也是Amoi采用的Boot方式,下面将详细分析在此方式下面的开机过程。
按下开机键之后,将产生一个时钟中断,从而通知AMSS主芯片的Boot Load硬件去将放置于Nand Flash上面的第一个Block(8K)里面的Boot代码Copy到内核内存(RAM,这个内存应该是CPU自带的内存,同后面提到的SDRAM有一定区别,可以把它当作CPU的Cache)的0xFFFF0000地址,并开始执行Boot代码。Boot的主要任务是完成整个系统的硬件初始化工作(类似于PC上面的BIOS所完成的硬件自检工作,至于Boot的详细工作机制,后文会有详细描述)。Boot所完成的工作里面,最重要的一件事就是会将整个手机软件代码(AMSS软件包)拷贝到SDRAM中,并最后将控制权交给AMSS软件。说白了,就是Boot执行完成之后,代码的执行点将由Boot跳转到AMSS软件的的入口点函数main().(此函数在mobile.c里实现)。
代码运行到了Main()之后,在这个函数里面将完成操作系统(rex)的初始化工作,其实现方法是调用rex_init()。Rex_init()完成的工作很简单:
完成操作系统必要的一些数据结构(timer链表、任务链表等))的初始化之外;
接下来,它创建了三个任务,分别是:rex_idle_task、rex_dpc_task和tmc_task。
Idle任务没什么好解释的,目前这个任务为空,什么也没做,dpc_task目前不知道是做什么的,暂时可以不用管。前面的这两个任务都属于操作系统层面的,由操作系统来维护,和手机软件关系不大。哪一个和手机软件关系大呢?答案是:tmc_task。大家可以把这个当作操作系统的入口(主)任务,也可以把它当作整个手机软件的入口任务。即AMSS软件里的所有其它任务的创建和维护就是由这个tmc_task来完成的。
到此为止,整个AMSS软件还并没有跑起来,只是跑到了tmc_task里面了。在tmc_task里面,会调用tmc_init()来完成整个AMSS软件包的初始化工作,其中最重要的一项工作就是调用tmc_define_tasks()将AMSS软件包所有需要的任务都创建起来了。比如说slee_task、dog_task、cm_task、wms_task、ui_task等。这些任务,一般不需要直接和AL层软件打交道,但请大家记住,手机上所有功能的实现最根本点就是由这些服务组件(Service Task)来完成的。将来大家跟踪一个具体的功能模块时,比如说通话模块,如果需要,可以再去深入研究它的具体实现。
好了,到现在为止,所有的AMSS核心软件就全部跑起来了(手机的功能模块,在软件方面就体现为OS层面的一个任务)。但现在大家还根本看不到Brew和AEE的影子。呵呵,各位不要急。到了这个层面之后,我想稍微多说几句。最早的Qualcomm平台,比如说5xxx系列,是根本没有Brew的,那个时候的AL(Application Layer)层软件开发,是直接调用底层Service task所提供的API来完成相应的工作的。从这种角度来看的话,显然那时的开发是比较郁闷和难度较高的。不过,到了65xx之后,Qualcomm平台引入了Brew,手机开发商就没必要去从这么底层(Service API)的层面进行手机开发了,他们完全可以基于Brew来实现一台手机的所有功能(Qualcomm给我们的参考代码,就是全Brew平台的)。
Brew的运行环境AEE是如何跑起来的呢?关键在于ui_task(),由于ui_task和我们手机开发的关系非常密切,其地位也相当重要,所以,后文我将单独对它进行一个深入的研究与分析。到目前为止,大家只需要知道ui_task将AEE加载起来了,并且,它起到了一个中间层的作用,即所有AMSS底层服务组件的消息,都将经由ui_task而转到AEE,并最终转到具体的App(Applet)的执行代码里面(HandleEvent())。
注意:
上述的开机过程,在每一次按开机键都需要走一遍,即关机之后,整个系统的所有功能都将消失,而不像有些手机,看起来是关了机,但实际上底层还是有一些软件模块在跑。为什么可以肯定地说上述开机过程每次都必须走一遍,原因很简单,因为我们的平台软件是基于Nand Flash启动的,所有的代码都需要Copy到SDRAM才能运行,而关机断电之后,SDRAM里的东东会全部丢失,所以,毫无疑问,上述的过程必须每次开机都执行;
关机的过程相对比较简单,系统检测到关机中断之后,将调用tmc_powerdown_handler()来完成关机动作,它将把所有AMSS的任务都Stop掉,并最后调用rex_exit()退出Rex,从而完成整个关机动作。
显然,关机动作前,如果有必要,每一个任务必须将它希望保存的信息保存到Flash上面,以便下次开机时可以得到这些信息;
开机流程简图
EMBED Visio.Drawing.11
图1 Qualcomm平台开机框图
说明:
Tmc是操作系统层面和AMSS软件关系最密切的一个任务,不过需要OEM商在此处修改的地方应该不多;
ui_task是在操作系统层面,OEM商需要重点研究清楚的一个任务,它是连接底层Task和上层AL的一个中间层,有可能需要加入OEM商的操作流程;
CoreApp是在Brew层面的一个AL层的入口Applet,它其着管理整个上层AL层软件的作用,根据产品需求,这个App需要定做;
AEE是整个上层App的运行环境,目前Qualcomm没有公开它的源码,但它的运行机制,Amoi需要好好研究清楚,我将在另外一篇《Qualcomm平台AEE运行机制深入分析与研究》中探讨它的运行机理和调度机制,大家有兴趣可以参考此文;
Boot代码深入分析
Boot代码大部分是用汇编语言写的,也有小部分,可能需要由OEM商修改,所以用C语言来写。另外,Boot代码属于Driver范围,所以大家可以在drivers/boot目录里面找到相应的代码。Boot的代码组织得非常模块化,整个boot的入口点是在Boot_function_table.s里面,这个汇编代码里面实际上是将Boot需要完成的任务封装成了不同的函数,由不同的函数来完成相应的工作,接下来,我将深入分析这些函数所完成的工作,如下所述。
mmu_enable_instruction_cache;
这个只有在Nand启动模式时才需要,打开ARM的指令Cache.
boot_hw_ctrl_init
此函数主要是完成两条总线(EBI1、EBI2)控制器的初始化,这个函数执行完了 之后,系统就可以知道两条总线上连接了哪些设备,同时也可以找得到这些 设备,不过,至于单个设备自身的初始化,则不在这里.
[注]
这个函数很重要,OEM商如果需要加新的设备到系统中(挂在两条总线上),则需
要定做此模块,目前阶段主要是内存。另外,如前文所述,这个函数是由C语言
来写的,主要目的就是为了方便OEM商定做。内存设备的修改,可以在这个模块
里找到相应的数据结构,相对还是比较简单的。
boot_hw_tlmm_init
1.晶振时钟的初始化;
2.中断表的初始化;
3.GPIO的初始化;
4.Msm本身的驱动,除了EBI2;
boot_rom_test
这个函数非常简单,只是做一个很简单的Rom检查.(比对两个标志位来检查,并
没有一块一块地去检查)。
boot_ram_test
Ram自检,具体算法其实也很简单,就是读、写内存以判断是否成功.
boot_ram_init
1.拷贝手机代码从Nand Flash到SDRAM。
a.Image__BB_RAM__Base:Core Code;
b.Image__APP_RAM__Base:App Code;
[注]
上述动作是分块进行的,原因是因为Qualcomm支持分块Boot Load.
2.将Image__ZI_REGION__ZI区域初始化为0;
3.初始化OEM要求的动态Heap;
4.至于代码段里的数据初始化,直接在Image里就完成了(编译器完成);
boot_stack_initialize
ARM栈初始化,主要是为分块代码加载而预留的.
boot_cache_mmu_init
ARM Mmu初始化
注意:
到此为止,整个Boot的工作就告完结了,那么,它又是如何跳到AMSS的main
入口点呢?原因很简单,ARM编译器在链接的时候会自动做出一个__rt_entry(),
由此函数来完成ARM库函数的初始化,并最后将代码执行点跳转到main()。而
__rt_entry()会在boot_reset_handler.s里调用,具体细节,大家可以不用太过关心,
只需要明白,Boot跑完之后,手机软件就跑到了main里就Ok了。
Ui_task的深入分析
从大的方向来讲,ui_task只完成两件事,一件是必要的初始化工作(这个也是我们所关心的,即ui_task到底完成了哪些工作);另外一件事就是各种信号量的事件处理,这也是我们比较关心的,即ui_task到底将哪些事件转发给了上层App。搞清楚了上述两点,我们也就能大致把ui_task的承上启下的工作机理研究清楚。
ui_Init;
初始化过程中,ui_task主要完成了如下几件事。
创建一个用于Kick Watchdog的定时器,这样WatchDog能够及时得到Kick,假如今后发现手机在ui_task里面自动重启,很有可能就是这个定时器的Timeout设置得过短而造成的;
注册通话相关的回调,主要是和紧急呼叫相关;
电话本初始化,之所以要进行这个工作,主要是加快开机之后AL层软件操作电话本的速度,但这样将有可能导致开机速度过慢,如果开机速度过慢,可以考虑进入待机界面之后,在后台开一个task去完成这项工作;
初始化Sound设备;
向底层服务任务wms_task注册wms回调,这个回调是在IWms组件里实现的。从这种角度来看,u帮我们把wms_task和IWMS组件联系起来了,但并没有去将AL层软件和IWMS联系起来,这个工作将是由AL层软件自己去完成。当然,注册回调的这个工作也是可以在AL层完成,之所以在这里完成,而不是在AL层完成,其主要目的是这个工作可以做到与AL层无关,即AL层不需要关心这个事情,但这个事情是短消息功能得于实现的必须步骤;
注册键盘消息回调;
通过这个回调,所有的按键消息都将经由底层的hs_task传到此回调函数里。然后回调函数将把所有的按键信息放到一个全局变量ui_key_buffer里面,接着发送一个UI_KEY_SIG信号给ui_task通知它去处理按键信息,至于ui_task如何处理按键消息的,后面的ui_handleSignals里会有详细描述。
初始化Lcd,这个工作不是LCD硬件设备的真正初始化,只是一些UI需要用到的LCD数据结构的初始化,和我们关系不大;
[注]
硬件的初始化,全部都在hs_task里面完成,从这种角度来看的话,系统能跑到ui_task里面,表明所有的硬件设备的驱动都已经成功加载。
置开机标志ui_powerup为True;
注册IPC信号量UI_IPC_SIG,这个可以暂时不管;
bridle_InitSWITable的初始化,这个目标,暂时不知道,也可以先略过;
初始化资源文件,其主要工作就是在Rom里面建立资源文件的符号链表,这样就可以让系统找到这些资源文件了(资源文件是被编译在代码段的,假如不这样做的话,系统将找不到这些资源文件);
Brew运行环境AEE的初始化:AEE_Init,这个函数看不到代码,大家只需要知道,到了这一步,整个Brew也就Run起来了,在AEE初始化完成之后,它将自动启动一个Applet,即CoreStartApp,而CoreStartApp将把CoreApp启动起来;
到此为止,ui_task的初始化工作完成;
[注意]
1) 从上述的ui_task的初始化工作可以看出,ui_task并没有完成手机AL层软件的
基本功能的初始化,比如说Sim卡检测、网络初始化等,这些工作,应该是在
CoreApp里完成的
2) 真正和手机功能相关的初始化工作,是在CoreApp里完成的,这个Applet的工
作机理,后面也会有详细描述;
ui_HandleSignals;
ui_task主要完成如下事件的处理。
看门狗喂食;
TASK_STOP_SIG信号,任务Stop,目前这个任务为空,没做任何事;
TASK_OFFLINE_SIG的处理,这几个任务都属于操作系统层面的事件,目前我们可以暂时不管;
处理关机信号:CoreAppHandleStopSig(),这个只是处理ui_task在关机前需要完成的任务,比如说发送一个消息给CoreApp让它关掉自己,然后将ui_task关闭;
[A]
系统的真正关机信号是由tmc来处理,当它发现需要关机时,调用tmc_powerdown_handler来完成相应的工作,在这里就是给所有的任务发送TASK_STOP_SIG的信号。
[A]
深层次的关机处理,不需要我们了解,也没必要去知道,我们只需要知道在ui_task里面把该关的关掉就Ok了。
[A]
关机是一个层层深入的过程,每一个App或者任务只需要负责将它们自己创建的资源释放掉就Ok了。而关机的导引线,显然是在CoreApp里截获到关机键之后发送出来的,事实上也是如此。
网络掉线时,发送掉线信号给CoreApp;
[A]
其实这个信号完全可以在CoreApp里面,自己去注册,然后及时更新自己的网络状态,就不知有没有这种接口函数。
处理按键消息,其主要完成如下的工作:
打开背光;
特理按键到虚键值的转换;
按键声音的处理;
将按键消息传送到AEE执行环境,由它去负责按键的派发;
[注]
1.背光的打开是由ui默认完成的,那这样的话,假如我不想按键时有背光,是否可行?看来就得修改此处的代码;
2.AEE的按键派发机制如何?它能否保证处于显示最上层的App永远是可以得到Key的App,即假如一个Applet将自身Hide,它是否依然可以得到Key,而其它的Applet是否就不可以得到了?很怕也像EMP一样出现焦点丢失的情况;
处理AEE_APP_SIG信号量,完成AEE的调度工作,这个任务是ui完成的最重要的一项工作,因为上层的App需要定时进行调度,目前看来,这个调度工作是由AEE_APP_SIG触发的,而AEE_APP_SIG这个信号量,则由操作系统层面的一个定时器定时发送的。现在大家只要了解,AEE_Dispatch会定时调用就Ok了,至于更详细的AEE调度机制,可以参考我的另外一篇《AEE运行机制深入分析与研究》;
处理AEE_SIO_SIG信号量,这个看不到代码,暂时略过不管;
结论
通过上述对于ui_task的分析,可以看出,ui_task真正和手机功能有关系的(即可能需要定制或者修改的地方),主要就是初始化资源文件和处理按键消息这两部分。至于其它部分,目前都不需要Amoi关心。手机真正功能的实现,比如说开机Logo的显示、Sim卡的检查、Pin码校验等,都是在CoreApp里面完成的。
其它
CoreApp的深入分析
目前参考代码里面的CoreApp所完成的工作比较多且杂,主要说来有如下几件事。
系统组件初始化;
开机Logo的显示;
Sim卡检测和Pin码校验;
系统状态信息更新;
电池状态;
网络信号;
网络模式;
IAnnunciator的维护与更新;
通话处理,打电话的输入框;
主菜单处理;
手机各种设置功能的处理;
关机键的处理;
目前CoreApp里面的代码,完成了太多的事,其实完全可以剥离成不同的模块来完成,大致可以分成如下几个部分。
总控模块;(CoreApp)
总控模块,主要完成手机按下开机键之后的各种初始化工作,同时此模块也是整个手机的控制中心,由它来完成手机的一些全局性工作,主要有如下几项。
系统初始化、Sim卡检测和Pin码校验;
开机Logo或者开机动画的显示;
底层服务程序的启动;(WmsApp、DialApp等);
系统配置信息的统一管理;
由于写配置信息到NV上面是一件非常慢的工作,每次上层App改变配置之后都去操作NV,很影响速度。所以,可以在内存中开一个配置信息的Buffer,上层App操作的实际上是这个Buffer,然后由Core在空闲的时候再统一写到NV上去。
关机处理;
[注]
由于CoreApp是在Idle Applet的界面之下,所以,为了能够实现“一键回菜单”的功用,有可能需要修改ui_task里面的Key处理函数,将所有的Key消息转发给Core,这样Core就可以得到所有的Key事件了。(现在的ui_task只把Key事件发送给了AEE,而AEE只会将Key事件发送给当前活动Applet)。
Idle模块;
主要完成待机界面的画图工作,主要有两部分:
系统信息指示栏;
待机界面(位图、动画、时钟、日历等);
软键
[注]
Idle只负责界面工作,不负责具体的系统状态信息的获取工作,这个工作将由其它模块完成。
Polling
手机状态信息查询模块,主要是完成手机各种状态信息的更新与维护。主要有如下几种:
电池强度;
网络信号强度;
网络模式(C/G);
PLMN网络名;
短消息、通话状态、闹铃;(这个由专门的模块完成,不在Polling之列);
各种外设信息;(USB、耳机插入等);
其它各种杂项信息;
Menu模块
菜单模块主要分两部分,一部分是主菜单的实现,另一个子菜单的实现。一般来讲,手机上的菜单系统应该是由Menu模块去统一完成,而不是由每一个子程序去手动完成。菜单模块一般只需要负责到主菜单、二级菜单和三级菜单就Ok了。三级菜单之后的界面,就由每一个App单独去维护了。
其它功能App模块;
每一个功能模块,由一个专门的App来完成,这样的话,模块的独立性强,便于单独开发。模块间通过App启动和消息传送的方式来发生关系和进行模块间通信。
后记
到此为止,Qualcomm整个手机从按下开机键到跑到主菜机界面,整个流程一目了然。对于Amoi而言,目前需要关心和定做的部分其实不多,最头疼的 当属CoreApp的改造工作,当然这个就是后话了,笔者将在今后的文章中加以详述。
希望本文对于大家理解Qualcomm手机软件的运行流程有一定的帮助,如果有什么问题,请直接联系我,最后谢谢大家耐心把本文看完,谢谢。
参考文档
f) 80-V1072-1_E_Boot_Block_Downloader.pdf
g) 80-V5316-1_K_QCT_Ext_API_RG.pdf
h) driver/boot目录源码
i) service/tmc目录源码
j) app/core目录源码
1.5 android 系统重启关机流程分析
1.5.1 c语言中调用 reboot 函数
bionic/libc/unistd/reboot.c:33:
int reboot (int mode)
{
return __reboot( LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, mode, NULL );
}
1.5.2 通过 adb 让系统重启
adb reboot recovery 进入 recovery 模式
adb reboot bootloader 进入 fastboot 模式
adb reboot-bootloader
adb reboot 不带参数 系统正常重启
adb 是pc端工具,adbd是服务端,运行在手机
adbd 读取 socket 解析由 adb 传过来的命令串
int service_to_fd(const char *name)
if(!strncmp(name, "reboot:", 7)) {
void* arg = strdup(name + 7);
if(arg == 0) return -1;
ret = create_service_thread(reboot_service, arg);
system/core/adb/services.c:176:
void reboot_service(int fd, void *arg)
{
。。。
ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
LINUX_REBOOT_CMD_RESTART2, (char *)arg);
。。。
}
bionic/libc/kernel/common/linux/reboot.h
#define LINUX_REBOOT_CMD_RESTART 0x01234567
#define LINUX_REBOOT_CMD_HALT 0xCDEF0123
kernel/include/linux/reboot.h:33:
#define LINUX_REBOOT_CMD_RESTART2 0xA1B2C3D4
arg 对应字符串: recovery bootloader
./kernel/arch/arm/mach-msm/pm2.c
system/core/adb/commandline.c
if (!strcmp(argv[0], "reboot-bootloader"))
snprintf(command, sizeof(command), "reboot:bootloader");
如果输入 adb reboot-bootloader adb 会对该命令进行转换 相当于执行 adb reboot bootloader
1.5.3 fastboot 模式下系统重启
fastboot reboot 系统正常重启
fastboot reboot-bootloader 重启进入fastboot 模式
fastboot 是 appboot 提供的功能,可以用它来烧写 system 等镜像文件
bootable/bootloader/lk/app/aboot/aboot.c
APP_START(aboot)
.init = aboot_init,
void aboot_init(const struct app_descriptor *app)
{
。。。
fastboot_register("reboot", cmd_reboot);
fastboot_register("reboot-bootloader", cmd_reboot_bootloader);
。。。
}
void cmd_reboot(const char *arg, void *data, unsigned sz)
{
dprintf(INFO, "rebooting the devicen");
fastboot_okay("");
reboot_device(0);
}
void cmd_reboot_bootloader(const char *arg, void *data, unsigned sz)
{
dprintf(INFO, "rebooting the devicen");
fastboot_okay("");
reboot_device(FASTBOOT_MODE);
}
bootable/bootloader/lk/target/msm7630_surf/init.c:311:
void reboot_device(unsigned reboot_reason)
bootable/bootloader/lk/target/msm7627_ffa/init.c:174:
void reboot_device(unsigned reboot_reason)
void reboot_device(unsigned reboot_reason)
{
reboot(reboot_reason);
}
调用的是c函数:
bionic/libc/unistd/reboot.c:33:
int reboot (int mode)
{
return __reboot( LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, mode, NULL );
}
bootable/bootloader/lk/app/aboot/aboot.c:59:
#define FASTBOOT_MODE 0x77665500
if (!strcmp(cmd, "bootloader")) {
restart_reason = 0x77665500;
}
1.5.4 系统关机
正常按键关机
./frameworks/policies/base/phone/com/android/internal/policy/impl/PhoneWindowManager.java
void showGlobalActionsDialog()
mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());
调用文件:
./frameworks/policies/base/phone/com/android/internal/policy/impl/GlobalActions.java
中的函数:
public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned)
mDialog = createDialog();
调用本文件中的函数:
private AlertDialog createDialog()
public void onPress() {
ShutdownThread.shutdownAfterDisablingRadio(mContext, true);
}
调用文件:
./frameworks/policies/base/phone/com/android/internal/policy/impl/ShutdownThread.java
中的函数:
public static void shutdownAfterDisablingRadio(final Context context, boolean confirm)
beginShutdownSequence(context)
调用本文件中的函数:
private static void beginShutdownSequence(Context context)
sInstance.start()
进入关机线程的run函数:
public void run() {
首先关蓝牙,关射频,然后再关电源
...
sBluetooth.disable(false)
...
sPhone.setRadio(false)
...
SystemClock.sleep(PHONE_STATE_POLL_SLEEP_MSEC);
...
Power.shutdown()
}
frameworks/base/core/java/android/os/Power.java:92:
public static native void shutdown();
frameworks/base/core/jni/android_os_Power.cpp:107:
{ "shutdown", "()V", (void*)android_os_Power_shutdown },
jni 调用
static void android_os_Power_shutdown(JNIEnv *env, jobject clazz)
{
sync();
#ifdef HAVE_ANDROID_OS
reboot(RB_POWER_OFF);
#endif
}
因为有 bionic/libc/include/sys/reboot.h:42:
#define RB_POWER_OFF LINUX_REBOOT_CMD_POWER_OFF
所以实际相对执行
reboot(LINUX_REBOOT_CMD_POWER_OFF);
__reboot( LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_POWER_OFF, NULL );
这里的 __reboot 是libc中的系统调用
bionic/libc/arch-x86/syscalls/__reboot.S
/* autogenerated by gensyscalls.py */
#include <sys/linux-syscalls.h>
.text
.type __reboot, #function
.globl __reboot
.align 4
.fnstart
__reboot:
.save {r4, r7}
stmfd sp!, {r4, r7}
ldr r7, =__NR_reboot
swi #0
ldmfd sp!, {r4, r7}
movs r0, r0
bxpl lr
b __set_syscall_errno
.fnend
1.5.5 内核中的系统调用 reboot
__NR_reboot 执行的是内核中的系统调用:
kernel/kernel/sys.c:310:
SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
void __user *, arg)
{
char buffer[256];
int ret = 0;
/* We only trust the superuser with rebooting the system. */
if (!capable(CAP_SYS_BOOT))
return -EPERM;
/* For safety, we require "magic" arguments. */
if (magic1 != LINUX_REBOOT_MAGIC1 ||
(magic2 != LINUX_REBOOT_MAGIC2 &&
magic2 != LINUX_REBOOT_MAGIC2A &&
magic2 != LINUX_REBOOT_MAGIC2B &&
magic2 != LINUX_REBOOT_MAGIC2C))
return -EINVAL;
/* Instead of trying to make the power_off code look like
* halt when pm_power_off is not set do it the easy way.
*/
if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off)
cmd = LINUX_REBOOT_CMD_HALT;
lock_kernel();
switch (cmd) {
case LINUX_REBOOT_CMD_RESTART:
kernel_restart(NULL);
break;
case LINUX_REBOOT_CMD_CAD_ON:
C_A_D = 1;
break;
case LINUX_REBOOT_CMD_CAD_OFF:
C_A_D = 0;
break;
case LINUX_REBOOT_CMD_HALT:
kernel_halt();
unlock_kernel();
do_exit(0);
panic("cannot halt");
case LINUX_REBOOT_CMD_POWER_OFF:
kernel_power_off();
unlock_kernel();
do_exit(0);
break;
case LINUX_REBOOT_CMD_RESTART2:
if (strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1) < 0) {
unlock_kernel();
return -EFAULT;
}
buffer[sizeof(buffer) - 1] = '