2017年11月23日 星期四

ARM64 Linux的啟動分析

ARM64 Linux的啟動分析

原文 https://blog.csdn.net/leoufung/article/details/50582640
1. 找到Linux啟動流程
Linux啟動,會啟動內核編譯後的文件vmlinux
vmlinux是一個ELF文件,按照./arch/arm64/kernel/vmlinux.lds設定的規則進行連結的./arch/arm64/kernel/vmlinux.lds 是 ./arch/arm64/kernel/vmlinux.lds.S編譯之後生成的
通過readelf可以看到vmlinux的入口地址為:0xfffffe0000080000

這個地址是怎麼來的,對應內核代碼中的哪個代碼呢?最簡單的方法是反彙編
對vmlinux反彙編的命令為:objdump -dxh vmlinux > vmlinux.s
在查找地址0xfffffe0000080000:grep fffffe0000080000 vmlinux.s
可以看到linux的第一條指令為:x13, x18, #0x16,對應的符號是:.head.text efi_head _text

查看ARM64的head.S可以看到如下代碼
/*
* Kernel startup entry point.
*
*
* The requirements are:
* MMU = off, D-cache = off, I-cache = on or off,
* x0 = physical address to the FDT blob.
*
* This code is mostly position independent so you call this at
* __pa(PAGE_OFFSET + TEXT_OFFSET).
*
* Note that the callee-saved registers are used for storing variables
* that are useful before the MMU is enabled. The allocations are described
* in the entry routines.
*/
__HEAD
/*
* DO NOT MODIFY. Image header expected by Linux boot-loaders.
*/
#ifdef CONFIG_EFI
efi_head:
/*
* This add instruction has no meaningful effect except that
* its opcode forms the magic "MZ" signature required by UEFI.
*/
add x13, x18, #0x16
b stext
#else
b stext // branch to kernel start, magic
.long 0 // reserved
#endif
HEAD為一個宏定義:#define __HEAD .section ".head.text","ax"
如此就都對應上了:
第一個地址為__HEAD下面的指令,即efi_head標號內容
第一個指令為add x13, x18,#0x16
緊接著就跳轉到傳統的啟動地方b stext
Stext 最後會調用啟動內核函數 start_kernel
其實,總結一句話,就是在head.S中,緊挨著_HEAD下面的就是第一條執行的指令
在看ARM32的
__HEADENTRY(stext) ……
所以,加載vmlinux後,第一個就開始執行stext
2. Vmlinux地址連結原理
前面講了,vmlinux是按照vmlinux.lds連結的,vmlinux.lds是由vmlinux.lds.S生成的
看看vmlinux.lds.S就可以理解了
 

TEXT_OFFSET是在Makefile中定義的
vim ./arch/arm64/Makefile

可以是隨機的,一般情況下定義為固定的0x80000

3. 地址的跳轉
上電,CPU跳轉到固定的一個地址執行UEFI代碼
UEFI從vmlinux的頭讀取到入口地址為0xfffffe0000080000
因為已經使能過了MMU,所以找到虛擬地址0xfffffe0000080000,跳轉到內核入口,開始加重內核

linux內核啟動地址的確定

linux內核啟動地址的確定http://blog.csdn.net/zht_sir /archive/2007/04/07/1555621 .aspx

                                              
                                                內核編譯鏈接過程是依靠vmlinux.lds文件 ,以arm為例vmlinux.lds文件位於kernel /arch/arm/vmlinux.lds,
                                                vmlinux-armv.lds的生成過程在kernel /arch/arm/Makefile中
ifeq ($(CONFIG_CPU_32),y)
PROCESSOR     = armv
TEXTADDR     = 0xC0008000
LDSCRIPT     = arch/arm/vmlinux-armv.lds.in
endif
arch/arm/vmlinux.lds: $(LDSCRIPT) dummy
    @sed 's/TEXTADDR/$(TEXTADDR)/;s /DATAADDR/$(DATAADDR)/' $(LDSCRIPT) >$@
查看arch/arm/vmlinux.lds 中
OUTPUT_ARCH(arm)
ENTRY(stext)
SECTIONS
{
    . = 0xC0008000;
    .init : {            /* Init code and data        */
        _stext = .;
        __init_begin = .;
            *(.text.init)
        __proc_info_begin = .;
            *(.proc.info)
        __proc_info_end = .;
        __arch_info_begin = .;
            *(.arch.info)
        __arch_info_end = .;
        __tagtable_begin = .;
            *(.taglist)
        __tagtable_end = .;
            *(.data.init)
        . = ALIGN(16);
        __setup_start = .;
            *(.setup.init)
        __setup_end = .;
        __initcall_start = .;
            *(.initcall.init)
        __initcall_end = .;
        . = ALIGN(4096);
        __init_end = .;
    }
    /DISCARD/ : {            /* Exit code and data        */
        *(.text.exit)
        *(.data.exit)
        *(.exitcall.exit)
    }
    .text : {            /* Real text segment        */
        _text = .;        /* Text and read-only data    */
            *(.text)
            *(.fixup)
            *(.gnu.warning)
            *(.rodata)
            *(.rodata.*)
            *(.glue_7)
            *(.glue_7t)
        *(.got)            /* Global offset table        */
        _etext = .;        /* End of text section        */
    }
    .kstrtab : { *(.kstrtab) }
    . = ALIGN(16);
    __ex_table : {            /* Exception table        */
        __start___ex_table = .;
            *(__ex_table)
        __stop___ex_table = .;
    }
    __ksymtab : {            /* Kernel symbol table        */
        __start___ksymtab = .;
            *(__ksymtab)
        __stop___ksymtab = .;
    }
    . = ALIGN(8192);
    .data : {
        /*
         * first, the init task union, aligned
         * to an 8192 byte boundary.
         */
        *(.init.task)
        /*
         * then the cacheline aligned data
         */
        . = ALIGN(32);
        *(.data.cacheline_aligned)
        /*
         * and the usual data section
         */
        *(.data)
        CONSTRUCTORS
        _edata = .;
    }
    .bss : {
        __bss_start = .;    /* BSS                */
        *(.bss)
        *(COMMON)
        _end = . ;
    }
                    /* Stabs debugging sections.    */
    .stab 0 : { *(.stab) }
    .stabstr 0 : { *(.stabstr) }
    .stab.excl 0 : { *(.stab.excl) }
    .stab.exclstr 0 : { *(.stab.exclstr) }
    .stab.index 0 : { *(.stab.index) }
    .stab.indexstr 0 : { *(.stab.indexstr) }
    .comment 0 : { *(.comment) }
}
arch/arm/Makefile中:
vmlinux: arch/arm/vmlinux.lds
arch/arm/vmlinux.lds: $(LDSCRIPT) dummy
    @sed 's/TEXTADDR/$(TEXTADDR)/;s /DATAADDR/$(DATAADDR)/' $(LDSCRIPT) >$@
MAKEBOOT     = $(MAKE) -C arch/$(ARCH)/boot
bzImage zImage zinstall Image bootpImage install: vmlinux
    @$(MAKEBOOT) $@
但在kernel/arch/arm/boot/Makefile
ifeq ($(CONFIG_ARCH_S3C2410),y)
ZTEXTADDR     = 0x30008000
ZRELADDR     = 0x30008000
endif
zImage:    $(CONFIGURE) compressed/vmlinux
    $(OBJCOPY) -O binary -R .note -R .comment -S compressed/vmlinux $@
compressed/vmlinux: $(TOPDIR)/vmlinux dep
    @$(MAKE) -C compressed vmlinux
在compressed目錄下的Makefile中
ZLDFLAGS     = -p -X -T vmlinux.lds
SEDFLAGS    = s/TEXT_START/$(ZTEXTADDR)/;s /LOAD_ADDR/$(ZRELADDR)/;s/BSS _START/$(ZBSSADDR)/
all:        vmlinux
vmlinux:    $(HEAD) $(OBJS) piggy.o vmlinux.lds
        $(LD) $(ZLDFLAGS) $(HEAD) $(OBJS) piggy.o $(LIBGCC) -o vmlinux
vmlinux.lds:    vmlinux.lds.in Makefile $(TOPDIR)/arch/$(ARCH)/boot /Makefile $(TOPDIR)/.config
        @sed "$(SEDFLAGS)"  $@
                                              
                                                vmlinux-armv.lds.in文件的內容:
                                                OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
  . = LOAD_ADDR;
  _load_addr = .;
  . = TEXT_START;
  _text = .;
  .text : {
    _start = .;
    *(.start)
    *(.text)
    *(.fixup)
    *(.gnu.warning)
    *(.rodata)
    *(.rodata.*)
    *(.glue_7)
    *(.glue_7t)
    input_data = .;
    piggy.o
    input_data_end = .;
    . = ALIGN(4);
  }
  _etext = .;
  _got_start = .;
  .got            : { *(.got) }
  _got_end = .;
  .got.plt        : { *(.got.plt) }
  .data            : { *(.data) }
  _edata = .;
  . = BSS_START;
  __bss_start = .;
  .bss            : { *(.bss) }
  _end = .;
  .stack (NOLOAD)    : { *(.stack) }
  .stab 0        : { *(.stab) }
  .stabstr 0        : { *(.stabstr) }
  .stab.excl 0        : { *(.stab.excl) }
  .stab.exclstr 0    : { *(.stab.exclstr) }
  .stab.index 0        : { *(.stab.index) }
  .stab.indexstr 0    : { *(.stab.indexstr) }
  .comment 0        : { *(.comment) }
}
vmlinux.lds內容為
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
  . = 0x30008000;
  _load_addr = .;
  . = 0;
  _text = .;
  .text : {
    _start = .;
    *(.start)
    *(.text)
    *(.fixup)
    *(.gnu.warning)
    *(.rodata)
    *(.rodata.*)
    *(.glue_7)
    *(.glue_7t)
    input_data = .;
    piggy.o
    input_data_end = .;
    . = ALIGN(4);
  }
  _etext = .;
  _got_start = .;
  .got            : { *(.got) }
  _got_end = .;
  .got.plt        : { *(.got.plt) }
  .data            : { *(.data) }
  _edata = .;
  . = ALIGN(4);
  __bss_start = .;
  .bss            : { *(.bss) }
  _end = .;
  .stack (NOLOAD)    : { *(.stack) }
  .stab 0        : { *(.stab) }
  .stabstr 0        : { *(.stabstr) }
  .stab.excl 0        : { *(.stab.excl) }
  .stab.exclstr 0    : { *(.stab.exclstr) }
  .stab.index 0        : { *(.stab.index) }
  .stab.indexstr 0    : { *(.stab.indexstr) }
  .comment 0        : { *(.comment) }
}
                                                一般情況下都在生成vmlinux后,再對內核進行壓縮成為zI mage,壓縮的目錄是kernel/arch/arm /boot。
下載到flash中的是壓縮后的zImage文件 ,zImage是由壓縮后的vmlinux和解壓縮程序組成 ,如下圖所示:
                                                            |-----------------|\    |-----------------|
            |                 | \   |                 |
            |                 |  \  | decompress code |
            |     vmlinux     |   \ |-----------------|    zImage
            |                 |    \|                 |
            |                 |     |                 |
            |                 |     |                 |   
            |                 |     |                 |
            |                 |    /|-----------------|
            |                 |   /
            |                 |  /
            |                 | /
            |-----------------|/
          
zImage鏈接腳本也叫做vmlinux.lds ,位於kernel/arch/arm/boot /compressed。
是由同一目錄下的vmlinux.lds.in文件生成的
在kernel/arch/arm/boot/Makefile文 件中定義了:
ifeq ($(CONFIG_ARCH_S3C2410),y)
ZTEXTADDR     = 0x30008000
ZRELADDR     = 0x30008000
endif
                                                ZTEXTADDR就是解壓縮代碼的ram偏移地址 ,ZRELADDR是內核ram啟動的偏移地址,這里看到指定ZT EXTADDR的地址為30008000,
                                              

以上就是我對內核啟動地址的分析,總結一下內核啟動地址的設置:
                                                設置kernel/arch/arm/boot /Makefile文件中的
ifeq ($(CONFIG_ARCH_S3C2410),y)
ZTEXTADDR     = 0x30008000         
ZRELADDR     = 0x30008000
endif
# We now have a PIC decompressor implementation.  Decompressors running
# from RAM should not define ZTEXTADDR.  Decompressors running directly
# from ROM or Flash must define ZTEXTADDR (preferably via the config)
#
查看2410的datasheet ,發現內存映射的基址是0x3000 0000 ,那麼  0x30008000又是如何來的呢?
在內核文檔kernel/Document/arm /Booting 文件中有:
                                              
[url=http://59.69.74.87/lxr/http /source/Documentation/arm /Booting?v=2.6.11.7#L105][/url]
Calling the kernel image
                                              
                                              
Existing boot loaders: MANDATORY
New boot loaders: MANDATORY
                                              
There
are two options for calling the kernel zImage. If the zImage is stored
in flash, and is linked correctly to be run from flash, then it is
legal for the boot loader to call the zImage in flash directly.
                                              
The
zImage may also be placed in system RAM (at any location) and called
there. Note that the kernel uses 16K of RAM below the image to store
page tables. The recommended placement is 32KiB into RAM.
                                              
看來在image下面用了32K(0x8000)的空間存放內核頁 表,
0x30008000就是2410的內核在RAM中的啟動地址 ,這個地址就是這麼來的。
關於內核解壓縮的過程分析
                                              
                                                內核壓縮和解壓縮代碼都在目錄kernel/arch/arm /boot/compressed,
編譯完成后將產生vmlinux、head.o、misc.o 、head-s3c2410.o、piggy.o這幾個文件,
head.o是內核的頭部文件,負責初始設置;
misc.o將主要負責內核的解壓工作,它在head.o之后;
head-s3c2410.o文件主要針對的初始化 ,將在鏈接時與head.o合並;
piggy.o是一個中間文件,其實是一個壓縮的內核 (kernel/vmlinux),只不過沒有和初始化文件及解壓 文件鏈接而已;
vmlinux是沒有(zImage是壓縮過的內核 )壓縮過的內核,就是由piggy.o、head.o、misc .o、head-s3c2410.o組成的。
                                                在BootLoader完成系統的引導以后並將Linux內核調 入內存之后,調用bootLinux(),
這個函數將跳轉到kernel的起始位置。
如果kernel沒有壓縮,就可以啟動了。
如果kernel壓縮過,則要進行解壓,在壓縮過的kernel頭 部有解壓程序。
壓縮過得kernel入口第一個文件源碼位置在arch/arm /boot/compressed/head.S。
它將調用函數decompress_kernel() ,這個函數在文件arch/arm/boot/compresse d/misc.c中,
decompress_kernel()又調用proc _decomp_setup(),arch_decomp _setup()進行設置,
然后使用在打印出信息"Uncompressing Linux..."后,調用gunzip()。將內核放於指定的位 置。
                                              
以下分析head.S文件:
(1)對於各種Arm CPU的DEBUG輸出設定,通過定義宏來統一操作。
(2)設置kernel開始和結束地址,保存architectu re ID。
(3)如果在ARM2以上的CPU中,用的是普通用戶模式 ,則昇到超級用戶模式,然后關中斷。
(4)分析LC0結構delta offset,判斷是否需要重載內核地址(r0存入偏移量 ,判斷r0是否為零)。
   這里是否需要重載內核地址,我以為主要分析arch/arm /boot/Makefile、arch/arm/boot /compressed/Makefile
   和arch/arm/boot/compressed/vmlinux.lds.in三個文件,主要看vmlinux.lds.in鏈接文件的主要段的位置,
   LOAD_ADDR(_load_addr)=0x300080 00,而對於TEXT_START(_text、_start )的位置只設為0,BSS_START(__bss_start )=ALIGN(4)。
   對於這樣的結果依賴於,對內核解壓的運行方式,也就是說 ,內核解壓前是在內存(RAM)中還是在FLASH上,
   因為這里,我們的BOOTLOADER將壓縮內核 (zImage)移到了RAM的0x30008000位置 ,我們的壓縮內核是在內存(RAM)從0x30008000地址開 始順序排列,
                                                   因此我們的r0獲得的偏移量是載入地址(0x30008000 )。
接下來的工作是要把內核鏡像的相對地址轉化為內存的物理地址 ,即重載內核地址。
(5)需要重載內核地址,將r0的偏移量加到BSS region和GOT table中。
(6)清空bss堆棧空間r2-r3。
(7)建立C程序運行需要的緩存,並賦於64K的棧空間。
(8)這時r2是緩存的結束地址,r4是kernel的最后執行地 址,r5是kernel境象文件的開始地址。檢查是否地址有沖突。
   將r5等於r2,使decompress后的kernel地址就 在64K的棧之后。
(9)調用文件misc.c的函數decompress _kernel(),解壓內核於緩存結束的地方(r2地址之后) 。此時各寄存器值有如下變化:
   r0為解壓后kernel的大小
   r4為kernel執行時的地址
   r5為解壓后kernel的起始地址
   r6為CPU類型值(processor ID)
   r7為系統類型值(architecture ID)
(10)將reloc_start代碼拷貝之kernel之后 (r5+r0之后),首先清除緩存,而后執行reloc _start。
(11)reloc_start將r5開始的kernel重載於r 4地址處。
(12)清除cache內容,關閉cache,將r7中archi tecture ID賦於r1,執行r4開始的kernel代碼。
                                                下面簡單介紹一下解壓縮過程,也就是函數decompress _kernel實現的功能:
解壓縮代碼位於kernel/lib/inflate.c ,inflate.c是從gzip源程序中分離出來的 。包含了一些對全局數據的直接引用。
在使用時需要直接嵌入到代碼中。gzip壓縮文件時總是在前32K 字節的範圍內尋找重復的字符串進行編碼,
在解壓時需要一個至少為32K字節的解壓緩沖區,它定義為wind ow[WSIZE]。inflate.c使用get_byte( )讀取輸入文件,
它被定義成宏來提高效率。輸入緩沖區指針必須定義為inptr ,inflate.c中對之有減量操作。inflate .c調用flush_window()
來輸出window緩沖區中的解壓出的字節串,每次輸出長度用ou tcnt變量表示。在flush_window()中,還必
須對輸出字節串計算CRC並且刷新crc變量。在調用gunzip ()開始解壓之前,調用makecrc()初始化CRC計算表。
最后gunzip()返回0表示解壓成功。
                                                我們在內核啟動的開始都會看到這樣的輸出:
Uncompressing Linux...done, booting the kernel.
這也是由decompress_kernel函數內部輸出的 ,它調用了puts()輸出字符串,
puts是在kernel/include/asm-arm /arch-s3c2410/uncompress.h中實現的。
                                                執行完解壓過程,再返回到head.S中,啟動內核:
                                                call_kernel:    bl  cache_clean_flush
         bl  cache_off
         mov r0, #0
         mov r1, r7          @ restore architecture number
         mov pc, r4          @ call kernel
       
下面就開始真正的內核了。
linux2.6 啟動傳遞命令行分析
                                                內核在啟動時可以傳遞一個字符串命令行,來控制內核啟動的過程 ,例如:
"console=ttyS2,115200
[email=mem=64M@0xA0000000]mem=64M@0xA0000000[/email]
"
這里指定了控制台是串口2,波特率是115200 ,內存大小是64M,物理基地址是0xA0000000。
另外我們可以在內核中定義一些全局變量,使用這些全局變量控制內核 的配置,例如usb驅動中定義了
static int nousb; /* Disable USB when built into kernel image */
這個變量為1,則整個usb驅動不初始化,如果想將其置1 ,可在字符串命令行中添加nousb=1。
在操作該變量之前,還要讓系統知道該變量,方法是:
__module_param_call("",nousb ,param_set_bool,param_get_bool ,&nousb,0444);
__module_param_call這個宏定義在kernel \include\linux\moduleparam.h
原型如下:
#define __module_param_call(prefix, name, set, get, arg, perm)  \
static char __param_str_##name[] = prefix #name;  \
static struct kernel_param const __param_##name   \
__attribute_used__      \
    __attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \
= { __param_str_##name, perm, set, get, arg }

它定義了一個kernel_param類型的變量 ,這個變量被放到了段__param,
kernel_param結構體的定義是:
struct kernel_param {
const char *name;
unsigned int perm;
param_set_fn set;
param_get_fn get;
void *arg;
};
__param這個段的聲明有些平台是在arch/../.. /vmlinux.lds.S,而大多數平台是放到
kernel\include\asm-generic \vmlinux.lds.h中,定義如下:
__param : AT(ADDR(__param) - LOAD_OFFSET) {   \
  VMLINUX_SYMBOL(__start__ _param) = .;   \
  *(__param)      \
  VMLINUX_SYMBOL(__stop__ _param) = .;   \
}
內核啟動時就會對字符串命令進行解析,在kernel\init \main.c中,內核啟動函數start_kernel中
對外部數組進行了聲明:
                                                extern struct kernel_param __start___param[], __stop___param[];
然后調用函數parse_args對數組進行解析:
parse_args("Booting kernel", command_line, __start___param,
     __stop___param - __start___param,
     &unknown_bootoption);
                                                其中command_line就是要解析的字符串命令行 ,unknown_bootoption是函數指針 ,它用來獲取指定參數的=右邊的值。
parse_args就會在數組中找到和nousb名稱一樣的ke rnel_param變量,並調用它的set函數對其進行付值。

2017年11月19日 星期日

ERROR: Nothing PROVIDES 'w89359_libbcmdhd'

Bitbake recipe naming rule -.bb
could refer to version or repository type, such as git.
So, solution is to rename w89359_libbcmdhd_git.bb to w89359-libbcmdhd_git.bb.
And do 'rebake w89359-libbcmdhd'

2017年11月13日 星期一

Android如何优化启动时间(boot time)

尽可能地减少LA的启动时间在USER的构建。 并假设我们有一个非常稳定的USER构建软件,没有任何错误,甚至警告消息存在于启动阶段。



首先,我们需要检查驱动程序的初始化时间是否合理,因此可以应用这个补丁。
"kernel/init/main.c"
-bool initcall_debug;
+bool initcall_debug = 1;
core_param(initcall_debug, initcall_debug, bool, 0644);

然后下面的消息会在内核启动时输出,我们可以逐一检查它们,看看是否有些驱动程序的initcall需要太多的时间。



...
initcall returned 0 after

在这一步之后,我们确认每个驱动程序的init过程是合理的。
最后,不要忘记还原上面的测试补丁。



2.禁用串行控制台和早期的printk
串口控制台和早期的printk会相当慢的内核启动,所以我们可以考虑到
在发布版本中禁用它们。


2.1您可以确认在文件“AndroidBoard.mk”中使用了哪个内核defconfig。 看起来像 ”

msmxxxx-perf_defconfig"
ifeq ($(TARGET_BUILD_VARIANT),user)
KERNEL_DEFCONFIG := msmxxxx-perf_defconfig
else
KERNEL_DEFCONFIG := msmxxxx_defconfig
endif



然后删除以下两个配置在此defconfig禁用串行控制台。
-CONFIG_SERIAL_MSM_HSL_CONSOLE = y



2.2禁用earlyprintk
编辑文件“BoardConfig.mk”,并删除“earlyprintk = msm_hsl_uart,0xf991e000”从“
BOARD_KERNEL_CMDLINE“。




3.进一步收缩内核defconfig。
基于“msmxxxx-perf_defconfig”,尝试删除以下配置。

-CONFIG_CGROUP_DEBUG=y
-CONFIG_SERIAL_MSM_HSL_CONSOLE=y
-CONFIG_MSM_ADSPRPC=y
-CONFIG_REGULATOR_TPS65132=y
-CONFIG_PFT=y
-CONFIG_CORESIGHT=y
-CONFIG_CORESIGHT_EVENT=y
-CONFIG_CORESIGHT_FUSE=y
-CONFIG_CORESIGHT_CTI=y
-CONFIG_CORESIGHT_TMC=y
-CONFIG_CORESIGHT_TPIU=y
-CONFIG_CORESIGHT_FUNNEL=y
-CONFIG_CORESIGHT_REPLICATOR=y
-CONFIG_CORESIGHT_STM=y
-CONFIG_CORESIGHT_HWEVENT=y
-CONFIG_CORESIGHT_ETMV4=y
-CONFIG_CORESIGHT_MODEM_ETM=y
-CONFIG_CORESIGHT_WCN_ETM=y
-CONFIG_CORESIGHT_RPM_ETM=y

-CONFIG_CP_ACCESS64=y
-CONFIG_MSM_SMD_DEBUG=y
-CONFIG_MSM_DEBUG_LAR_UNLOCK=y
-CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC=y
-CONFIG_MSM_OCMEM_DEBUG=y
-CONFIG_MSM_OCMEM_NONSECURE=y
-CONFIG_LOCKUP_DETECTOR=y
-CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
-CONFIG_DEBUG_KMEMLEAK=y
-CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
-CONFIG_DEBUG_SPINLOCK=y
-CONFIG_DEBUG_MUTEXES=y
-CONFIG_DEBUG_ATOMIC_SLEEP=y
-CONFIG_DEBUG_STACK_USAGE=y
-CONFIG_DEBUG_MEMORY_INIT=y
-CONFIG_DEBUG_LIST=y
-CONFIG_FAULT_INJECTION=y
-CONFIG_FAIL_PAGE_ALLOC=y
-CONFIG_FAULT_INJECTION_DEBUG_FS=y
-CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y

-CONFIG_MSM_RTB=y
-CONFIG_MSM_RTB_SEPARATE_CPUS=y
-CONFIG_DYNAMIC_DEBUG=y
-CONFIG_PANIC_ON_DATA_CORRUPTION=y
-CONFIG_STRICT_MEMORY_RWX=y

然后,重新编译代码,并检查文件$ANDROID_TOP/out/target/product/$TARGET/obj/KERNEL_OBJ/.

查看更改是否生效。



4.在早期引导时将多个内核设置为在线
如果您应用此步骤,请特别注意,因为它可能会导致热问题。


4.1首先应用以下3个补丁。 由于芯片组之间的差异,你需要做一些轻微的改变
这些补丁。

https://www.codeaurora.org/cgit/quic/la//device/qcom/common/commit/?id=
6df8a1ba549e6bf64fae2a73e2f6e3249bd72701


https://www.codeaurora.org/cgit/quic/la//kernel/msm-3.10/commit/?id=
d77f3f9feded36585a41fa094b17493ee7bb6092


https://www.codeaurora.org/cgit/quic/la//platform/system/core/commit/?id=
7f29bccd05b584dfb2028ba8579e04eaf7628f46



4.2 编辑"bootargs" 在 "msmxxxx.dtsi"
+bootargs = "boot_cpus=0 androidboot.earlyboot_cpus=2,4,6 sched_enable_hmp=1";



注意:
这种变化将导致温度迅速上升,并且如果超过一些阈值,thermal thread将会
限制这些核心降低频率,甚至关闭它们。 所以如果你遇到热问题,请还原
代码更改。


5.对于Android和其他引导性能,您可以参考以下2个文档了解更多
信息。


2017年11月10日 星期五

談談autotools的--build, --target, 和 --host

原文 http://wen00072.github.io/blog/2015/02/06/talk-about-the-autotools-build-target-and-host/

組裝的時候,常常缺東缺西的。這時候就需要cross-compile一些套件頂一下,所以如果有人組裝過的話,應該會對下面的命令倍感親切。
1
$ ./configure --host=mipsel
如果組裝夠次數夠多,也會看到--target--build的參數似乎和這個有關。找時間稍微了解一下
對於–target目前手上的資料無法讓我完全理解,請注意!
根據Autoconf手冊說明,這些參數的預設值如下:
  • --build
    • 從config.guess中猜的
  • --host
    • 設成和--build相同
  • --target
    • 設成和--host相同
因為這樣的連動性,如果你要cross-compile,那麼下了--host後麻煩不要省掉--build,不然autotool會把build設成和host一樣。
Automake手冊裏面的定義
  • --build
    • 你build code,下xxx-gcc那台機器平台
  • --host
    • 產生的binary可以執行的平台
  • --target
    • 告訴gcc要產生什麼平台的機械碼
      • 一般來說會和--host一樣同樣的平台,根據上面的連動,你設了--host就可以省略這個選項
      • 特例是compile cross-compiler或是binutils,toolchain。這時候是指定build在host上,但是處理的對象是cross platform的機械碼
Autotool選擇gcc的方式如下
  • --host--build相同
    • 用你電腦上的gcc,來編譯autotool的套件。
  • --host--build不同
    • 你要自備cross-compiler
    • 如果有指定--target的為gcc的prefix
    • --host=xxx, --target=zzz,會使用zzz-gcc產生xxx平台的機械碼
    • 用該cross-compiler來編譯autotool的套件
    • 這時候要保證cross compiler可以吃的library也存在,常常會為了編一個套件cross compile一堆套件
看的有點混亂嘛?沒關係,autoconf 2.69手冊有提到,要cross-compile的話,唯一(if and only if)的條件就是指令--host指定和你現在的平台不同就好。

參考資料

編譯bluez-5.25 通過 Linux環境下運行

原文 http://blog.csdn.net/wang_shuai_ww/article/details/41774477

本次編譯的是bluez 5版本以上的,之前的版本不支持藍牙4.0,只有5版本以上支持4.0.我的Linux宿主機是Ubuntu14.04版本
本次編譯參考http://wiki.beyondlogic.org/index.php?title=Cross_Compiling_BlueZ_Bluetooth_tools_for_ARMhttp://wiki.beyondlogic.org/index.php?title=Cross_Compiling_BlueZ_Bluetooth_tools_for_ARM
在這個基礎上還做了一些小修改,避免一些錯誤。好開始記錄步驟,比較繁瑣,O(∩_∩)O。這裡也對原文做一些解釋。
zlib-1.2.8
zlib的編譯不需要指定--host,但是後面配置完成後需要修改Makefile檔,以進行交叉編譯。
源碼:wget http://zlib.net/zlib-1.2.8.tar.gz
配置:./configure --prefix=/wsh_space/my_install/bluez5
修改Makefile:
CC=arm-cortex_a9-linux-gnueabi-gcc
LDSHARED=arm-cortex_a9-linux-gnueabi-gcc -shared -Wl,-soname,libz.so.1,--version-script,zlib.map
CPP=arm-cortex_a9-linux-gnueabi-gcc -E
AR=arm-cortex_a9-linux-gnueabi-ar
RANLIB=arm-cortex_a9-linux-gnueabi-ranlib
編譯:
make
make install

libffi-3.0.13
源碼:wget ftp://sourceware.org/pub/libffi/libffi-3.0.13.tar.gz
配置:./configure --host=arm-cortex_a9-linux-gnueabi --prefix=/wsh_space/my_install/bluez5
編譯:
make
make install


glib-2.40.0
編譯glib依賴zlib, libffi and glibc >= 2.18,宿主機若是Ubuntu14.04,glibc的版本為2.19,這裡是滿足的。另外很可能會缺少glib-genmarshal ,我編譯時是缺少了,這個好解決,執行命令
sudo apt-get install libglib2.0-dev
安裝即可。如果安裝不上,那麼直接下載安裝包安裝,地址為:https://launchpad.net/ubuntu/+source/glib2.0,要下載三個安裝包:
libglib2.0-0_2.40.2-0ubuntu1_amd64.deb、libglib2.0-bin_2.40.2-0ubuntu1_amd64.deb、libglib2.0-dev_2.40.2-0ubuntu1_amd64.deb,依次安裝即可。注意這個包要取決於ubuntu的版本,比較煩人。
下面是具體的步驟:
源碼:wget http://ftp.gnome.org/pub/gnome/sources/glib/2.40/glib-2.40.0.tar.xz
配置:./configure --host=arm-cortex_a9-linux-gnueabi --prefix=/wsh_space/my_install/bluez5 PKG_CONFIG_PATH=/wsh_space/my_install/bluez5/lib/pkgconfig  glib_cv_stack_grows=no glib_cv_uscore=yes ac_cv_func_posix_getpwuid_r=yes ac_cv_func_posix_getgrgid_r=yes
編譯:
make
make install


D-Bus
D-Bus daemon會需要expat XML parser 庫,所以這裡需要先編譯expat庫。如果不安裝會出現下面的錯誤:
checking for XML_ParserCreate_MM in -lexpat... no
configure: error: Explicitly requested expat but expat not found


步驟如下
expat-2.1.0
源碼:wget http://sourceforge.net/projects/expat/files/expat/2.1.0/expat-2.1.0.tar.gz
配置:./configure --host=arm-cortex_a9-linux-gnueabi --prefix=/wsh_space/my_install/bluez5
編譯:
make
make install


D-Bus1.9.4
在使用原文中的配置時,編譯會報錯,如下:
corrupt.c:29:18: fatal error: glib.h: 沒有那個檔或目錄
/wsh_space/my_install/bluez5/include/glib-2.0/glib.h:30:26: fatal error: glib/galloca.h: 沒有那個檔或目錄
fatal error: glibconfig.h: 沒有那個檔或目錄
經過查看,是test目錄下檔引用的.h檔路徑不正確,可以一個一個修改路徑,但是相當繁瑣。
我的方法是,遮罩test,增加--disable-tests選項。
源碼:wget http://dbus.freedesktop.org/releases/dbus/dbus-1.9.4.tar.gz
配置:./configure --host=arm-cortex_a9-linux-gnueabi --prefix=/wsh_space/my_install/bluez5 --disable-tests
編譯:
make
make install


libical-1.0
bluez的編譯需要libical的支援,編譯libical需要cmake和g++,所以系統中需要這兩個工具,可以運行下面兩個命令進行安裝,需要保持網路暢通。
sudo apt-get install cmake
sudo apt-get install g++-arm-linux-gnueabi
然後就可進行編譯安裝了
源碼:wget http://downloads.sourceforge.net/freeassociation/libical-1.0.tar.gz
配置: export CC=arm-cortex_a9-linux-gnueabi-gcc
export CXX=arm-linux-gnueabi-g++
cmake -DCMAKE_INSTALL_PREFIX=/wsh_space/my_install/bluez5
注意這裡的命令是直接在命令列執行的。
編譯:
make
make install


Readline


編譯readline是需要ncurses的支援,如果沒有ncurses,編譯時會報下面的錯誤。
/usr/arm-linux-gnueabi/lib/libreadline.so: undefined reference to `PC'
/usr/arm-linux-gnueabi/lib/libreadline.so: undefined reference to `tgetflag'
/usr/arm-linux-gnueabi/lib/libreadline.so: undefined reference to `tgetent'
/usr/arm-linux-gnueabi/lib/libreadline.so: undefined reference to `UP'
/usr/arm-linux-gnueabi/lib/libreadline.so: undefined reference to `tputs'
/usr/arm-linux-gnueabi/lib/libreadline.so: undefined reference to `tgoto'
/usr/arm-linux-gnueabi/lib/libreadline.so: undefined reference to `tgetnum'
/usr/arm-linux-gnueabi/lib/libreadline.so: undefined reference to `BC'
/usr/arm-linux-gnueabi/lib/libreadline.so: undefined reference to `tgetstr'
引用ncurses的方法是,在make時添加SHLIB_LIBS=-lncurses選項

ncurses-5.9
源碼:wget http://ftp.gnu.org/pub/gnu/ncurses/ncurses-5.9.tar.gz
配置:./configure --host=arm-cortex_a9-linux-gnueabi --prefix=/wsh_space/my_install/bluez5 CXX="arm-linux-gnueabi-g++"
編譯:
make
make install


Readline6.3
配置時需要添加bash_cv_wcwidth_broken=yes選項,避免出現下面的錯誤:
checking for wcwidth broken with unicode combining characters...
configure: error: in `/.../readline-6.3':
configure: error: cannot run test program while cross compiling
源碼:wget ftp://ftp.cwru.edu/pub/bash/readline-6.3.tar.gz
配置:./configure --host=arm-cortex_a9-linux-gnueabi --prefix=/wsh_space/my_install/bluez5 bash_cv_wcwidth_broken=yes
編譯:
make SHLIB_LIBS=-lncurses
make install


Building BlueZ


bluez包含了藍牙所需的基本工具,如hciattach, hciconfig, hcitool and rfcomm等。
BlueZ 5.25 至少需要 GLib >= 2.28, D-Bus >= 1.6 and libudev >= 143,由於linudev是個相當麻煩的東西,為此在編譯bluez時,把它給遮罩了即可。
如果想下載,那麼下載地址為:http://pkgs.fedoraproject.org/repo/pkgs/udev/
源碼:wget http://www.kernel.org/pub/linux/bluetooth/bluez-5.25.tar.xz
配置:./configure --host=arm-cortex_a9-linux-gnueabi --prefix=/wsh_space/my_install/bluez5 PKG_CONFIG_PATH=/wsh_space/my_install/bluez5/lib/pkgconfig CC="arm-cortex_a9-linux-gnueabi-gcc -L/wsh_space/my_install/bluez5/lib -I/wsh_space/my_install/bluez5/include" --disable-systemd --disable-udev --disable-cups --disable-obex --enable-library
編譯:
make
應該會報錯,提示如下:
/usr/arm-linux-gnueabi/lib/libreadline.so: undefined reference to `PC'
/usr/arm-linux-gnueabi/lib/libreadline.so: undefined reference to `tgetflag'
/usr/arm-linux-gnueabi/lib/libreadline.so: undefined reference to `tgetent'
/usr/arm-linux-gnueabi/lib/libreadline.so: undefined reference to `UP'
/usr/arm-linux-gnueabi/lib/libreadline.so: undefined reference to `tputs'
/usr/arm-linux-gnueabi/lib/libreadline.so: undefined reference to `tgoto'
/usr/arm-linux-gnueabi/lib/libreadline.so: undefined reference to `tgetnum'
/usr/arm-linux-gnueabi/lib/libreadline.so: undefined reference to `BC'
/usr/arm-linux-gnueabi/lib/libreadline.so: undefined reference to `tgetstr'
主要時程式庫的問題,不知道為什麼不加入,可能再編譯readline時未加入。解決方法是:
在makefile的2004、2205、2211、2221、2227行添加-lncurses庫的應用即可。
make install DESTDIR=/wsh_space/my_install/bluez5
注意這裡的安裝會生成一個特殊的檔,如下圖所示:

在使用dbus-daemon時,是需要這個檔的,這個檔的結構如下圖:

另外還需要把安裝目錄下的var資料夾拷貝到wsh_space/my_install/bluez5目錄 下,如下圖:

在開發板使用時,需要把wsh_space資料夾拷貝到系統的根目錄下。
還需要一些庫檔,我時直接把整個安裝目錄拷貝到開發板的/usr/local/bluetooth下。
到此,完成,其他的測試可以參考原文。