第一品级——内核运营分析之成立si工程和剖析stext运营内核函数(四)

目标:

Hadoop是1个由Apache基金聚会地方支付的分布式系统基础架构。

(一)成立Source Insight
工程,方便前面分析哪些运维水源的

用户能够在不打听分布式底层细节的意况下,开发分布式程序。丰盛利用集群的威力举行神速运算和储存。

(二)分析uboot传递参数,链接脚本怎么样进入stext的 

 Hadoop完成了2个分布式文件系统(Hadoop Distributed File
System),简称HDFS。HDFS有高容错性的特点,并且陈设用来配置在物美价廉的(low-cost)硬件上;而且它提供高吞吐量(high
throughput)来访问应用程序的多少,适合这么些拥有超大数据集(large data
set)的应用程序。HDFS放宽了(relax)POSIX的渴求,能够以流的款式拜访(streaming
access)文件系统中的数据。

(三) 分析stext函数怎么着运转水源:

Hadoop的框架最宗旨的陈设正是:HDFS和MapReduce。HDFS为海量的数目提供了蕴藏,则MapReduce为海量的数码提供了计算。

 

优点

Hadoop是三个力所能及对大批量多少进行分布式处理的软件框架。 Hadoop
以一种保证、高效、可伸缩的主意进行数量处理。

Hadoop
是保证的,因为它要是总结元素和存款和储蓄会破产,因而它保护四个工作多少副本,确定保证能够针对破产的节点重新分布处理。

Hadoop 是神速的,因为它以互动的主意行事,通过并行处理加速处理速度。

Hadoop 依然可伸缩的,能够处理 PB 级数据。

除此以外,Hadoop 注重于社区服务,由此它的资本比较低,任何人都可以使用。

Hadoop是3个力所能及让用户轻松架构和行使的分布式计算平台。用户能够轻松地在Hadoop上付出和平运动作处理海量数据的应用程序。它不可缺少有以下多少个亮点:

  1. 高可相信性。Hadoop按位存款和储蓄和拍卖数量的能力值得人们相信。

  2. 高扩展性。Hadoop是在可用的处理器集簇间分配数据并形成总结职务的,那一个集簇能够方便地壮大到数以千计的节点中。

  3. 高效性。Hadoop能够在节点之间动态地活动数据,并确认保障各样节点的动态平衡,因此处理速度相当慢。

  4. 高容错性。Hadoop能够活动保存数据的多少个副本,并且能够自行将破产的职务重新分配。

  5. 低成本。与1体机、商用数据仓库以及QlikView、Yonghong
    Z-Suite等数据集市比较,hadoop是开源的,项目标软件花费由此会大大下降。

Hadoop带有用Java语言编写的框架,由此运营在 Linux
生产平台上是非凡不错的。Hadoop 上的应用程序也得以使用其余语言编写,比如
C++。

hadoop大数据处理的含义

Hadoop得以在大数额处理利用湖北中国广播集团泛应用得益于其本人在多少提取、变
形和加载(ETL)方面上的先天优势。Hadoop的分布式架构,将大数量处理引擎尽也许的临近存款和储蓄,对诸如像ETL那样的批处理操作相对合适,因为类似
那样操作的批处理结果能够一直走向存款和储蓄。Hadoop的MapReduce功用实现了将单个职务打碎,并将散装职分(Map)发送到几个节点上,之后再以
单个数据集的样式加载(Reduce)到数据仓Curry。

     (三.1)
关闭irq和fiq,设置svc管理格局

子项目

Hadoop Common:
在0.20及在此以前的本子中,包蕴HDFS、MapReduce和别的类型集体内容,从0.二一发端HDFS和MapReduce被分别为单独的子项目,其他内容为Hadoop
Common

HDFS: Hadoop分布式文件系统(Distributed File System) - HDFS (Hadoop
Distributed File System)

MapReduce:并行总括框架,0.20前应用 org.apache.hadoop.mapred
旧接口,0.20版本初步引入org.apache.hadoop.mapreduce的新API

HBase: 类似谷歌BigTable的分布式NoSQL列数据库。(HBase和Avro已经于2010年12月变为头等
Apache 项目)

Hive:数据仓库工具,由推文(Tweet)进献。

Zookeeper:分布式锁设施,提供类似谷歌Chubby的法力,由照片墙进献。

Avro:新的数额类别化格式与传输工具,将稳步替代Hadoop原有的IPC机制。

Pig: 大数量解析平台,为用户提供多种接口。

Ambari:Hadoop管理工具,能够便捷的监督、布置、管理集群。

Sqoop:于在HADOOP与历史观的数据库间进行数量的传递。

 

老伯总计

通过地点相关阅读,让大家领略到hadoop是叁个大幅度的工具集,里面有分布式文件存款和储蓄,并行云计算,分布式事务锁,大数据解析等壹多元工具,确实够你喝1壶的!

理所当然,要是您以为它好,依然越早迈出第三步越好!

 

     (三.二)判断是或支撑这一个CPU

 

   
 (3.3)判断是或不是支持那么些单板(通过uboot传入的机械ID判断)

 

   
 (三.肆)创立页表,为后边的MMU做准备

 

     (3.5)
使能MMU并跳到__switch_data处,复制数据段,清除bss段,设置栈,调用start_kernel第一个C函数


 

壹 成立基础source
sight 工程

1.壹点击 “add all”
添加全数文件,前面再慢慢删去Arch目录和Include目录中与2440芯片没用的公文。

 图片 1

1.2 点击Remove Tree
删除Arch文件夹,再添加与2440荣辱与共的硬件大旨代码以及任何公用的代码

  Arch:包涵了阳台,处理器相关的代码,并包涵boot文件夹。

壹.2.1 点击Add
Tree添加以下子目录:

           linux-二.6.2二.6/arch/arm/boot   (运维配置文件) 

           linux-二.6.22.6/arch/arm/common      (公共文件)  

           linux-二.陆.22.6/arch/arm/configs    (配置文件)  

           linux-二.陆.22.6/arch/arm/kernel         (内核文件)         

           linux-2.6.22.6/arch/arm/lib            (固件库)  

           linux-2.6.22.6/arch/arm/mach-s3c2440  (machine
设备,2440设备库)  

           linux-贰.陆.2二.6/arch/arm/mach-s三c二四十  
(2440中部分调用了二4十设备库)  

           linux-贰.6.2二.6/arch/arm/Mm     (内存管理文件)  

           linux-2.6.22.6/arch/arm/nwfpe             

           linux-贰.陆.2贰.6/arch/arm/oprofile         (质量分析工具文件)  
             

           linux-2.陆.2二.6/arch/arm/plat-s3c二4xx    (s三c二四体系平台文件)  
   

           linux-贰.6.22.6/arch/arm/tools     (常用工具文件)            
             

           linux-二.陆.2二.6/arch/arm/vfp   (浮点运算文件)                              

一.三 点击Remove Tree
删除Include文件夹,再添加与2440有关的头文件

Include: 包罗了中央的大多数include文件,别的对于每一个协助的种类布局分别有三个子目录 

一.三.1点击Add All
添加 linux-二.六.2二.6/include/asm-arm目录下文件(不包涵子目录全体文件),如下图所示:

 图片 2

 

一.三.贰 点击Add Tree添加以下子目录:  
     
 

         
 linux-二.陆.22.6/include/asm-arm/arch-s3c贰四10     (二肆十计算机架构)      
    

         
 linux-②.陆.2二.6/include/asm-arm/hardware    (硬件相关头文件)

         
 linux-二.陆.2二.6/include/asm-arm/mach             (具体的装置文件)

         
 linux-二.陆.2②.6/include/asm-arm/plat-s叁c二四xx   (s叁c二四种类平台头文件)
 

壹.三.三重回到 linux-二.六.22.6/include目录下,点击Add
Tree添加除了asm-xx开首的其他通用文件: 
   

            linux-贰.陆.22.6/include/acpi  
          (高级配置与电源接口文件)  

           
linux-2.6.22.6/include/config 

           
linux-2.6.22.6/include/crypto 

           
linux-2.6.22.6/include/keys

           
linux-2.6.22.6/include/linux

           
linux-2.6.22.6/include/math-emu

            linux-2.6.22.6/include/mtd  
   

           
linux-2.6.22.6/include/net 

           
linux-2.6.22.6/include/pcmcia

           
linux-2.6.22.6/include/rdma

           
linux-2.6.22.6/include/rxrpc

           
linux-2.6.22.6/include/scsi

           
linux-2.6.22.6/include/sound

           
linux-2.6.22.6/include/video

 图片 3
                     

1.4 最后点击synchronize files  
 创造source insight工程

 

 

二.内核运营之分析uboot传递参数和链接脚本

二.1内核在uboot运营从前是跻身do_boom_linux函数

(do_boom_linux函数运转水源详解:http://www.cnblogs.com/lifexy/p/7310279.html)

do_boom_linux代码如下:

theKernel = (void (*)(int, int, unsigend int))0x30008000;

// 设置theKernel地址=0x30008000,用于后面启动内核

/*设置atag参数*/

setup_start_tag (void);                      //从0X30000100地址处开始保存start_tag数据,

setup_memory_tags (void);         //保存memory_tag数据,让内核知道内存多大 setup_commandline_tag (“boottargs=noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0”);  

 /*保存命令行bootargs参数,让内核知道根文件系统位置在/dev/mtdblock3,指定开机运行第一个脚本/linuxrc,指定打印串口0*/

setup_end_tag (void);                        //初始化tag结构体结束

theKernel(0,362,0x300000100);        //362:机器ID,  0x300000100: params(atag)参数地址

/*传递参数跳转执行到0x30008000启动内核,           */

/*相当于: mov r0,#0                                */

/*ldr r1,=362                                       */

/*ldr r2,= 0x300000100                             */

/*mov pc,#0x30008000                            */

TAG参数内部存款和储蓄器布局图如下:

 图片 4

二.二然新素不相识析链接脚本arm/arm/kernel/vmlinux.lds

OUTPUT_ARCH(arm)                    //设置输出文件的体系架构

 ENTRY(stext)                          //设置stext全局符号为入口地址

 jiffies = jiffies_64;

SECTIONS
{
. = (0xc0000000) + 0x00008000;               

/*设置内核虚拟地址=0xc0000000+0x00008000 */
.text.head : {
  _stext = .;
  _sinittext = .;
  *(.text.head)         //添加所有.text.head段
}
.init : { /* Init code and data                */
   *(.init.text)
  _einittext = .;
  __proc_info_begin = .;
   *(.proc.info.init)               //存放处理器相关的信息初始化
  __proc_info_end = .;
  __arch_info_begin = .;
   *(.arch.info.init)              //存放与架构(arch)相关的信息(info)初始化
  __arch_info_end = .;
...  ...

从vmlinux.lds中汲取linux内核运维第二步是跻身stext入口函数。

那正是说stext入口函数又在何地定义的吧?

搜索ENTRY(stext)得出,它在arch/arm/kernel/head.S中,

stext函数的在放置条件是:MMU, D-cache,
关闭; r0 = 0, r壹 = machine nr, r二 = atags prointer.代码如下:

/*

 * Kernel startup entry point.                      //内核 启动 入口 点

 * ---------------------------

 *

 * This is normally called from the decompressor code.  The requirements

 * are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0,  

/* 前置条件是:MMU, D-cache, 关闭; r0 = 0, r1 =机器ID, r2 =atag参数地址.*/

 * r1 = machine nr.

* This code is mostly position independent, so if you link the kernel at

 * 0xc0008000, you call this at __pa(0xc0008000).

* See linux/arch/arm/tools/mach-types for the complete list of machine

 * numbers for r1.

 *

 * We're trying to keep crap to a minimum; DO NOT add any machine specific

 * crap here - that's what the boot loader (or in extreme, well justified

 * circumstances, zImage) is for.

 */

 section ".text.head", "ax"                      /* 定义一个.text.head段,段的属性a是允许段,x可 执行 */ 

         .type  stext, %function                /*定义了由bootloader进入内核的入口stext */

ENTRY(stext)

... ...

 

它的功力是收获计算机类型和机器类型消息,并创建临时的页表,然后打开MMU作用(因为基本代码中全是0XCxxxxxxx地址),并跳进第贰个C语言函数start_kernel。

所以,基本运维后率先步
进入arch/arm/kernel/head.S的stext函数中.

3内核运转之stext函数分析(arch/arm/kernel/head.S)

stext函数内容,如下图:

(壹) 关闭irq和fiq,设置svc管理情势

(二)判断是或支持这一个CPU

(三)判断是不是帮助这几个单板(通过uboot传入的机械ID判断)

(四)创设页表,为后边的MMU做准备

(5)
使能MMU并跳到__switch_data处,复制数据段,清除bss段,设置栈,调用start_kernel第一个C函数

图片 5

   

stext函数代码如下:  

section ".text.head", "ax"                          /* 定义一个.text.head段,段的属性a是允许段,x可 执行 */ 

         .type   stext, %function                     /*定义了由bootloader进入内核的入口stext */

ENTRY(stext)                                    //入口地址stext函数

      /*msr cpsr_c,0xD3   关闭irq和fiq,设置svc管理模式  */

         msr    cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ ensure svc mode 

                                                          @ and irqs disabled

     /*获取cpu ID */

         mrc    p15, 0, r9, c0, c0              @ get processor id

     /*查找内核是否支持r9这个cpuID,若不支持r5=0,支持r5=处理器ID*/

         bl       __lookup_processor_type             @ r5=procinfo r9=cpuid

         movs  r10, r5                                      @ invalid processor (r5=0)?

      /*不支持则跳转到__error_p,死循环*/

         beq     __error_p                         @ yes, error 'p'

     /*查找内核是否支持uboot传入的r1机器ID(362),若不支持r5=0,支持r5=机器ID*/

         bl       __lookup_machine_type              @ r5=machinfo

         movs  r8, r5                              @ invalid machine (r5=0)?

     /*不支持则跳转到__error_a,死循环*/

         beq     __error_a                         @ yes, error 'a'

 /*跳转到__create_page_tables 创建页表,为后面的MMU做准备*/

         bl       __create_page_tables               

 

三.一分析下边”__lookup_machine_type函数”是如何通过搜寻r1机器ID(36二)是或等于单板机器ID的,代码如下(位于arch/arm/kernel):

3:       .long  .
         .long  __arch_info_begin
         .long  __arch_info_end


__lookup_machine_type:

         /*(b:bank)r3=后面的符号3处. 虚拟地址,由于mmu未启动,所以=物理地址*/
adr     r3, 3b               
         ldmia  r3, {r4, r5, r6}/* r4=3b处的虚拟地址 ,r5=__arch_info_begin处的虚拟地址,r6=__arch_info_end处的虚拟地址   */
         sub     r3, r3, r4                         @ get offset between virt&phys //得到虚拟地址(virtual)与物理地址(physical)的偏移值
         add     r5, r5, r3                         @ convert virt addresses to  //找到arch_info_begin处的物理地址
         add     r6, r6, r3                         @ physical address space    //找到__arch_info_end处的物理地址
1:       ldr      r3, [r5, #MACHINFO_TYPE]      @ get machine type   //r3=r5+偏移地址里内容= 单板机器ID
         teq     r3, r1                                  //判断r1(365)和单板机器ID是否相等,相等说明内核支持该单板
         beq     2f                                   @ found   //相等则直接返回到stext函数继续执行
         add     r5, r5, #SIZEOF_MACHINE_DESC      @ next machine_desc
         cmp    r5, r6

         blo     1b
         mov   r5, #0                             @ unknown machine  //r5=0,不支持该单板
2:       mov   pc, lr                       //退出

其中__arch_info_begin和__arch_info_end是在链接脚本arm/arm/kernel/vmlinux.lds中定义:

305  __arch_info_begin = .;           //__arch_info_begin=信息开始地址
306     *(.arch.info.init)              //存放架构相关的信息初始化
307  __arch_info_end = .;           //__arch_info_end =信息结束地址

通过grep  “.arch.info.init” 
-nPRADO个中.arch.info.init段在include/asm-ram/mach/arch.h中伍叁行处定义:

 图片 6

代码如下:

#define MACHINE_START(_type,_name)                     //定义了一个MACHINE_START宏, _type:CPU名字,_name:开发板名字
static const struct machine_desc __mach_desc_##_type \      //##:连词符号
 __used                                                                \
 __attribute__((__section__(".arch.info.init"))) = {       \  //强制将  MACHINE_START宏里的成员组成.arch.info.init段
         .nr               = MACH_TYPE_##_type,          \ 
         .name           = _name,


#define MACHINE_END                               \       //定义宏MACHINE_END=   };

};

搜索MACHINE_STA奇骏T宏发现arch/arm目录下各类文件都使用了这么些宏定义,由于大家采用的是S3C2440和SMDKs3c2440

 图片 7

就此得出使用宏#define
MACHINE_START(_type,_name)的是:

1 MACHINE_START(S3C2440, "SMDK2440")       
2     /* Maintainer: Ben Dooks <ben@fluff.org> */
3     .phys_io  = S3C2410_PA_UART,
4     .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
5     .boot_params  = S3C2410_SDRAM_PA + 0x100,
6
7     .init_irq   = s3c24xx_init_irq,
8     .map_io          = smdk2440_map_io,
9     .init_machine  = smdk2440_machine_init,
10   .timer             = &s3c24xx_timer,
11  MACHINE_END

 

内部地方第贰段使用的宏即是事先在arch.h中定义的MACHINE_START(_type,_name),其中_type替换成S3C2440,
_name替换成”SMDK2440″.

第11段的MACHINE_END在被arch.h中定义为等于“};”

最终

将宏定义代入上边MACHINE_STA奥迪Q7T(S3C2440,
“SMDK2440”)处的1一段代码中,展开如下所示:

static const struct  machine_desc  __mach_desc_ S3C2440  //定义一个machine_desc型结构体,名字为__mach_desc_ S3C2440
 __used                                                                \
 __attribute__((__section__(".arch.info.init"))) = {        //强制将MACHINE_START宏里的成员组成.arch.info.init段
         .nr               = MACH_TYPE_ S3C2440,  // __mach_desc_ S3C2440.nr= MACH_TYPE_ S3C2440  机器ID
         .name           = "SMDK2440",              //__mach_desc_ S3C2440. name = "SMDK2440"  机器ID名字   

       /* Maintainer: Ben Dooks <ben@fluff.org> */
    /*.phys_io  =0X50000000,存放物理IO基地址*/
       .phys_io  = S3C2410_PA_UART,         

 /* .io_pg_offst存放物理IO偏移地址*/  
       .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,   





/*其中S3C2410_SDRAM_PA=0X30000000, .boot_params= 0X30000100,所以我们uboot传入的atag参数地址必须是0X30000100*/
.boot_params  = S3C2410_SDRAM_PA + 0x100, 

.init_irq = s3c24xx_init_irq,        
       .map_io          = smdk2440_map_io,     
       .init_machine  = smdk2440_machine_init,    
      .timer             = &s3c24xx_timer,   
  };                                        // MACHINE_END替换成  };

 

从上边能够看到首如果开始化了machine_desc结构体,然后将其放在.arch.info.init段上,让
内核运营时将uboot传递进入的ID与那么些段上的ID实行相比较是或不是吻合,支不协助该单板伊始化。

因为不一样的单板都有两样MACHINE_START(_type,_name)以及硬件上也许不尽相同,所以需求开首化的始末也不如

重回stext函数中继续往下看:

ldr   r13, __switch_data             @ address to jump to after
//MMU使能之后会跳转(jump)到__switch_data@ mmu has been enabled 

adr  lr, __enable_mmu              @ return (PIC) address//使能MMU
add pc, r10, #PROCINFO_INITFUNC  

 

何以使能MMU后会跳转到__switch_data?

在__enable_mmu函数中最前边能够见到使能MMU后,会将r一叁赋给PC,跳转到了__switch_data,代码如下:

__enable_mmu: 
      ...  .... 
      mov    r3, r3
      mov    r3, r3
      mov    pc, r13

 

跳转到了__switch_data中,其中 __switch_data
是__mmap_switched的虚拟地址,所以最终跳转到__mmap_switched中.

__switch_data函数代码如下:

__switch_data:
         .long  __mmap_switched                          //进入__mmap_switched函数
         .long  __data_loc                       @ r4              
         .long  __data_start                     @ r5
         .long  __bss_start                      @ r6
         .long  _end                               @ r7
         .long                                       @ r4
         .long  __machine_arch_type                  @ r5
         .long  cr_alignment                         @ r6
         .long  init_thread_union + THREAD_START_SP @ sp

__mmap_switched:
         adr     r3, __switch_data + 4           //r3=__data_loc段内容
/*其中
__data_loc 是数据存放的位置
__data_start 是数据开始的位置    
__bss_start 是bss开始的位置
_end 是bss结束的位置, 也是内核结束的位置
这几个符号都在arch/arm/kernel/vmlinux.lds中定义的变量
*/

         ldmia  r3!, {r4, r5, r6, r7}   //r4=__data_loc ,  r5=__data_start ,  r6=__bss_start ,r7=_end ,  r3= processor_id
         cmp    r4, r5                                        // __data_loc段不等于__data_start段则执行下面1处的内容
1:       cmpne  r5, r6                  // 比较r5(__data_start段)和r6(__bss_start段)
         ldrne   fp, [r4], #4                
         strne   fp, [r5], #4                //str r4,[r5] 将整个段里内容从 __data_loc段 复制到__data_start段
         bne     1b                      //r5不等于r6,则继续复制   


         mov   fp, #0                             @ Clear BSS (and zero fp)  //清除bss段
1:       cmp    r6, r7                   //比较r6(__bss_start t段)和r7(_end段)
         strcc   fp, [r6],#4               // 清除bss段
         bcc     1b                     //(cc:小于)r6<r7,继续清除bss段 


         ldmia  r3, {r4, r5, r6, sp}       //r4=r3= processor_id, r5=__machine_arch_type,r6= cr_alignment,
//设置栈sp= init_thread_union + THREAD_START_SP,方便执行C函数start_kernel
         str      r9, [r4]                            @ Save processor ID
         str      r1, [r5]                            @ Save machine type
         bic     r4, r0, #CR_A                           @ Clear 'A' bit
         stmia  r6, {r0, r4}                      @ Save control register values

         b        start_kernel                   //然后执行start_kernel函数

 

最后跳到start_kernel函数,此函数代码用纯C来贯彻,它会调用各类平台的连带初始化函数

下一节始于分析start_kernel函数