精华内容
下载资源
问答
  • SPL

    2016-08-05 14:56:25
    SPL SPL是uboot第一阶段执行的代码. 主要负责搬移uboot第二阶段的代码到内存中运行. SPL是由固化在芯片内部的ROM引导的. 我们知道很多芯片厂商固化的ROM支持从nandflash, SDCARD等外部介质启动. 所谓启动, 就是从...

    SPL

    SPL是uboot第一阶段执行的代码. 主要负责搬移uboot第二阶段的代码到内存中运行. SPL是由固化在芯片内部的ROM引导的. 我们知道很多芯片厂商固化的ROM支持从nandflash, SDCARD等外部介质启动. 所谓启动, 就是从这些外部介质中搬移一段固定大小(4K/8K/16K等)的代码到内部RAM中运行. 这里搬移的就是SPL. 在最新版本的uboot中, 可以看到SPL也支持nandflash, SDCARD等多种启动方式.  当SPL本身被搬移到内部RAM中运行时, 它会从nandflash, SDCARD等外部介质中搬移uboot第二阶段的代码到外部内存中.

    SPL的文件组成

    当我们在uboot下执行make命令的时候, 它最核心的功能是执行Makefile中的all目标编译出相应的文件. 我们来看看这个all目标
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. all:        $(ALL-y) $(SUBDIR_EXAMPLES)  
    all依赖于$(ALL-y) 和 $(SUBDIR_EXAMPLES), 这里我只关注ALL-y, 如下:
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. # Always append ALL so that arch config.mk's can add custom ones  
    2. ALL-y += $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map  
    3.   
    4. ALL-$(CONFIG_NAND_U_BOOT) += $(obj)u-boot-nand.bin  
    5. ALL-$(CONFIG_ONENAND_U_BOOT) += $(obj)u-boot-onenand.bin  
    6. ALL-$(CONFIG_SPL) += $(obj)spl/u-boot-spl.bin  
    7. ALL-$(CONFIG_SPL_FRAMEWORK) += $(obj)u-boot.img  
    8. ALL-$(CONFIG_TPL) += $(obj)tpl/u-boot-tpl.bin  
    9. ALL-$(CONFIG_OF_SEPARATE) += $(obj)u-boot.dtb $(obj)u-boot-dtb.bin  
    10. ifneq ($(CONFIG_SPL_TARGET),)  
    11. ALL-$(CONFIG_SPL) += $(obj)$(subst ",,$(CONFIG_SPL_TARGET))  
    12. endif  
    13.   
    14. # enable combined SPL/u-boot/dtb rules for tegra  
    15. ifneq ($(CONFIG_TEGRA),)  
    16. ifeq ($(CONFIG_OF_SEPARATE),y)  
    17. ALL-y += $(obj)u-boot-dtb-tegra.bin  
    18. else  
    19. ALL-y += $(obj)u-boot-nodtb-tegra.bin  
    20. endif  
    21. endif  
    因为本节是讨论SPL, 所以我们只关注其中的一句ALL-$(CONFIG_SPL) += $(obj)spl/u-boot-spl.bin
    这句话表明
    • 必须定义CONFIG_SPL才能编译出spl的bin: 一般在"include/configs/${CONFIG_NAME}.h"中定义
    • SPL的bin依赖于u-boot-spl.bin
    接着往下看
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. $(obj)spl/u-boot-spl.bin:   $(SUBDIR_TOOLS) depend  
    2.         $(MAKE) -C spl all  
    这里可以发现, u-boot-spl.bin依赖于 $(SUBDIR_TOOLS) depend
    • $(SUBDIR_TOOLS) : 暂不分析
    • depend: 参考附录中的depend
    • 进入spl目录, 执行make all
    接下来进入spl目录, 看看它的Makefile : 这里只分析与SPL相关的部分
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. CONFIG_SPL_BUILD := y  
    2. export CONFIG_SPL_BUILD  
    • export CONFIG_SPL_BUILD: 在接下来的编译中, 这个变量为y. 从后面的分析中可以看到, uboot的stage1, stage2阶段的代码用的是同一个Start.S, 只不过在Start.S中用#ifdef CONFIG_SPL_BUILD这种条件编译来区分. 类似的还有其他一些文件.
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. HAVE_VENDOR_COMMON_LIB = $(if $(wildcard $(SRCTREE)/board/$(VENDOR)/common/Makefile),y,n)  
      1. 如果board/$(VENDOR)/common目录中有Makefile文件,则HAVE_VENDOR_COMMON_LIB为y否则为n  
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. ifdef   CONFIG_SPL_START_S_PATH  
    2. START_PATH := $(subst ",,$(CONFIG_SPL_START_S_PATH))  
    3. else  
    4. START_PATH := $(CPUDIR)  
    5. endif  
    • 我们这里没有定义CONFIG_SPL_START_S_PATH, 所以START_PATH := $(CPUDIR)
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. START := $(START_PATH)/start.o  
    • 依赖start.o, 综合来看, 就是要把CPUDIR下的start.S编译进来.
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. LIBS-y += arch/$(ARCH)/lib/lib$(ARCH).o  
    • 依赖lib$(ARCH).o, 具体来看, 就是依赖arch/arm/lib/libarm.o
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. LIBS-y += $(CPUDIR)/lib$(CPU).o  
    • 依赖lib$(CPU).o, 具体来看, 就是依赖arch/arm/cpu/armv7/libarmv7.o
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. ifdef SOC  
    2. LIBS-y += $(CPUDIR)/$(SOC)/lib$(SOC).o  
    3. endif  
    • 如果定义了SOC, 则依赖lib$(SOC).o, 具体来看, 就是依赖arch/arm/cpu/s5pc1xx/libs5pc1xx.o
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. LIBS-y += board/$(BOARDDIR)/lib$(BOARD).o  
    • 依赖lib$(BOARD).o, 具体来看, 就是依赖board/samsung/tiny210/libtiny210.o
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. LIBS-$(HAVE_VENDOR_COMMON_LIB) += board/$(VENDOR)/common/lib$(VENDOR).o  
    • 如果HAVE_VENDOR_COMMON_LIB为y, 则依赖lib$(VENDOR).o, 具体来看, 就是依赖board/samsung/common/libsamsung.o
    [plain] view plaincopy
    1. LIBS-$(CONFIG_SPL_FRAMEWORK) += common/spl/libspl.o  
    2. LIBS-$(CONFIG_SPL_LIBCOMMON_SUPPORT) += common/libcommon.o  
    3. LIBS-$(CONFIG_SPL_LIBDISK_SUPPORT) += disk/libdisk.o  
    4. LIBS-$(CONFIG_SPL_I2C_SUPPORT) += drivers/i2c/libi2c.o  
    5. LIBS-$(CONFIG_SPL_GPIO_SUPPORT) += drivers/gpio/libgpio.o  
    6. LIBS-$(CONFIG_SPL_MMC_SUPPORT) += drivers/mmc/libmmc.o  
    7. LIBS-$(CONFIG_SPL_SERIAL_SUPPORT) += drivers/serial/libserial.o  
    8. LIBS-$(CONFIG_SPL_SPI_FLASH_SUPPORT) += drivers/mtd/spi/libspi_flash.o  
    9. LIBS-$(CONFIG_SPL_SPI_SUPPORT) += drivers/spi/libspi.o  
    10. LIBS-$(CONFIG_SPL_FAT_SUPPORT) += fs/fat/libfat.o  
    11. LIBS-$(CONFIG_SPL_LIBGENERIC_SUPPORT) += lib/libgeneric.o  
    12. LIBS-$(CONFIG_SPL_POWER_SUPPORT) += drivers/power/libpower.o \  
    13.     drivers/power/pmic/libpmic.o  
    14. LIBS-$(CONFIG_SPL_NAND_SUPPORT) += drivers/mtd/nand/libnand.o  
    15. LIBS-$(CONFIG_SPL_ONENAND_SUPPORT) += drivers/mtd/onenand/libonenand.o  
    16. LIBS-$(CONFIG_SPL_DMA_SUPPORT) += drivers/dma/libdma.o  
    17. LIBS-$(CONFIG_SPL_POST_MEM_SUPPORT) += post/drivers/memory.o  
    18. LIBS-$(CONFIG_SPL_NET_SUPPORT) += net/libnet.o  
    19. LIBS-$(CONFIG_SPL_ETH_SUPPORT) += drivers/net/libnet.o  
    20. LIBS-$(CONFIG_SPL_ETH_SUPPORT) += drivers/net/phy/libphy.o  
    21. LIBS-$(CONFIG_SPL_USBETH_SUPPORT) += drivers/net/phy/libphy.o  
    22. LIBS-$(CONFIG_SPL_MUSB_NEW_SUPPORT) += drivers/usb/musb-new/libusb_musb-new.o  
    23. LIBS-$(CONFIG_SPL_USBETH_SUPPORT) += drivers/usb/gadget/libusb_gadget.o  
    24. LIBS-$(CONFIG_SPL_WATCHDOG_SUPPORT) += drivers/watchdog/libwatchdog.o  
    • 根据具体配置, 选择相应的依赖关系
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. ifeq ($(SOC),exynos)  
    2. LIBS-y += $(CPUDIR)/s5p-common/libs5p-common.o  
    3. endif  
    • 如果SOC为exynos, 则依赖libs5p-common.o, 我们这里的SOC为s5pc1xx, 所以不依赖
    [plain] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. START := $(addprefix $(SPLTREE)/,$(START))  
    2. LIBS := $(addprefix $(SPLTREE)/,$(sort $(LIBS-y)))  
    • 给START和LIBS加上前缀, $(SPLTREE), 具体来看, 就是编译过程中生成的.o文件都会放到spl/目录下面
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. # Linker Script  
    2. ifdef CONFIG_SPL_LDSCRIPT  
    3. # need to strip off double quotes  
    4. LDSCRIPT := $(addprefix $(SRCTREE)/,$(subst ",,$(CONFIG_SPL_LDSCRIPT)))  
    5. endif  
    6.   
    7. ifeq ($(wildcard $(LDSCRIPT)),)  
    8.     LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot-spl.lds  
    9. endif  
    10. ifeq ($(wildcard $(LDSCRIPT)),)  
    11.     LDSCRIPT := $(TOPDIR)/$(CPUDIR)/u-boot-spl.lds  
    12. endif  
    13. ifeq ($(wildcard $(LDSCRIPT)),)  
    14.     LDSCRIPT := $(TOPDIR)/arch/$(ARCH)/cpu/u-boot-spl.lds  
    15. endif  
    16. ifeq ($(wildcard $(LDSCRIPT)),)  
    17. $(error could not find linker script)  
    18. endif  
    • 找到spl的链接配置文件, 具体来看, 用的是arch/arm/cpu下的u-boot-spl.lds
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. ALL-y   += $(obj)$(SPL_BIN).bin  
    2.   
    3. ifdef CONFIG_SAMSUNG  
    4. ALL-y   += $(obj)$(BOARD)-spl.bin  
    5. endif  
    6.   
    7. all:    $(ALL-y)  
    8.   
    9. ifdef CONFIG_SAMSUNG  
    10. $(obj)$(BOARD)-spl.bin: $(obj)u-boot-spl.bin  
    11.     $(OBJTREE)/tools/mk$(BOARD)spl \  
    12.         $(obj)u-boot-spl.bin $(obj)$(BOARD)-spl.bin  
    13. endif  
    14.   
    15. $(obj)$(SPL_BIN).bin:   $(obj)$(SPL_BIN)  
    16.     $(OBJCOPY) $(OBJCFLAGS) -O binary $< $@  
    17.   
    18. GEN_UBOOT = \  
    19.     cd $(obj) && $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)) $(__START) \  
    20.         --start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \  
    21.         -Map $(SPL_BIN).map -o $(SPL_BIN)  
    22.   
    23. $(obj)$(SPL_BIN):   depend $(START) $(LIBS) $(obj)u-boot-spl.lds  
    24.     $(GEN_UBOOT)  
    25.   
    26. $(START):   depend  
    27.     $(MAKE) -C $(SRCTREE)/$(START_PATH) $@  
    28.   
    29. $(LIBS):    depend  
    30.     $(MAKE) -C $(SRCTREE)$(dir $(subst $(SPLTREE),,$@))  
    31.   
    32. $(obj)u-boot-spl.lds: $(LDSCRIPT) depend  
    33.     $(CPP) $(CPPFLAGS) $(LDPPFLAGS) -I$(obj). -ansi -D__ASSEMBLY__ -P - < $< > $@  
    34.   
    35. depend: $(obj).depend  
    36. .PHONY: depend  
    • all: $(ALL-y), 还记得本篇上面说的, 进入到spl目录下之后干啥事吗? 没错, 执行make all, 其实执行的就是这里的all目标. 它依赖$(ALL-y). 具体的依赖关系就不赘述了, 顺藤摸瓜即可
    • ifdef CONFIG_SAMSUNG: 这个是针对Samsung平台的特殊之处. 
      • 利用tools/mk$(BOARD)spl这个工具, 将u-boot-spl.bin转为$(BOARD)-spl.bin
        • 转换的本质, 就是在u-boot-spl.bin前面加入head info.关于head info是什么, 可以参考文档S5PV210_iROM_ApplicationNote_Preliminary_20091126.pdf. 顺便可以理解一下samsung芯片的启动流程
      • tools/mk$(BOARD)spl这个工具是在tools/Makefile里面生成的.
    OK, 分析结束, 接下来, 就基于我们上面的分析开始分析代码了.

    SPL代码分析

    u-boot-spl.lds: 它的位置在上文中我们分析了
    • 根据u-boot-spl.lds中的规则, 我们知道CPUDIR/start.o被放在了最前面. 它所对应的文件就是arch/arm/cpu/armv7/start.S

    start.S

    下面我们看看start.S
    [plain] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. .globl _start  
    2. _start: b   reset  
    3.     ldr pc, _undefined_instruction  
    4.     ldr pc, _software_interrupt  
    5.     ldr pc, _prefetch_abort  
    6.     ldr pc, _data_abort  
    7.     ldr pc, _not_used  
    8.     ldr pc, _irq  
    9.     ldr pc, _fiq  
    • _start是我们在lds里面指定的ENTRY(_start)
    • 首先会跳转到reset处
    • ldr  pc, _xxx定义的是中断向量表
    [plain] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. #ifdef CONFIG_SPL_BUILD  
    2. _undefined_instruction: .word _undefined_instruction  
    3. _software_interrupt:    .word _software_interrupt  
    4. _prefetch_abort:    .word _prefetch_abort  
    5. _data_abort:        .word _data_abort  
    6. _not_used:      .word _not_used  
    7. _irq:           .word _irq  
    8. _fiq:           .word _fiq  
    9. _pad:           .word 0x12345678 /* now 16*4=64 */  
    10. #else  
    11. _undefined_instruction: .word undefined_instruction  
    12. _software_interrupt:    .word software_interrupt  
    13. _prefetch_abort:    .word prefetch_abort  
    14. _data_abort:        .word data_abort  
    15. _not_used:      .word not_used  
    16. _irq:           .word irq  
    17. _fiq:           .word fiq  
    18. _pad:           .word 0x12345678 /* now 16*4=64 */  
    19. #endif  /* CONFIG_SPL_BUILD */  
    • 当CONFIG了SPL_BUILD之后, 一旦发生异常中断, 就会进入死循环. 所以我们的SPL里面不允许出发异常中断
    • 不过正常的uboot(即stage2阶段)还是可以处理异常中断的.

    reset

    [plain] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. /*  
    2.  * the actual reset code  
    3.  */  
    4.   
    5. reset:  
    6.     bl  save_boot_params  
    7.     /*  
    8.      * disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode,  
    9.      * except if in HYP mode already  
    10.      */  
    11.     mrs r0, cpsr  
    12.     and r1, r0, #0x1f       @ mask mode bits  
    13.     teq r1, #0x1a       @ test for HYP mode  
    14.     bicne   r0, r0, #0x1f       @ clear all mode bits  
    15.     orrne   r0, r0, #0x13       @ set SVC mode  
    16.     orr r0, r0, #0xc0       @ disable FIQ and IRQ  
    17.     msr cpsr,r0  
    18.   
    19.         /* ........ */  
    20.     /* the mask ROM code should have PLL and others stable */  
    21. #ifndef CONFIG_SKIP_LOWLEVEL_INIT  
    22.     bl  cpu_init_cp15  
    23.     bl  cpu_init_crit  
    24. #endif  
    25.   
    26.     bl  _main  
    当初次上电或者复位时, Uboot最新运行的就是这里的代码
    • bl save_boot_params: 如果没有重新定义save_boot_params,则使用<arch/arm/cpu/armv7/start.S>中的save_boot_params。其不做任何事情,直接返回
    • 禁止FIQ, IRQ; 设置CPU工作在SVC32模式
    • bl cpu_init_cp15: (I/D-Cache, MMU, TLBs),具体见下面代码中注释
    • bl    cpu_init_crit    :  主要是设置CPU的PLL, GPIO管脚复用, memory等. 具体见下面
    • bl    _main              :  跳转到<arch/arm/lib/crt0.S>中的_main. 具体见下面

    cpu_init_cp15

    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. /*************************************************************************  
    2.  *  
    3.  * cpu_init_cp15  
    4.  *  
    5.  * Setup CP15 registers (cache, MMU, TLBs). The I-cache is turned on unless  
    6.  * CONFIG_SYS_ICACHE_OFF is defined.  
    7.  *  
    8.  *************************************************************************/  
    9. ENTRY(cpu_init_cp15)  
    10.     /*  
    11.      * Invalidate L1 I/D  
    12.      */  
    13.     mov r0, #0          @ set up for MCR  
    14.     mcr p15, 0, r0, c8, c7, 0   @ invalidate TLBs  
    15.     mcr p15, 0, r0, c7, c5, 0   @ invalidate icache  
    16.     mcr p15, 0, r0, c7, c5, 6   @ invalidate BP array  
    17.     mcr     p15, 0, r0, c7, c10, 4  @ DSB  
    18.     mcr     p15, 0, r0, c7, c5, 4   @ ISB  
    19.   
    20.     /*  
    21.      * disable MMU stuff and caches  
    22.      */  
    23.     mrc p15, 0, r0, c1, c0, 0  
    24.     bic r0, r0, #0x00002000 @ clear bits 13 (--V-)  
    25.     bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM)  
    26.     orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align  
    27.     orr r0, r0, #0x00000800 @ set bit 11 (Z---) BTB  
    28. #ifdef CONFIG_SYS_ICACHE_OFF  
    29.     bic r0, r0, #0x00001000 @ clear bit 12 (I) I-cache  
    30. #else  
    31.     orr r0, r0, #0x00001000 @ set bit 12 (I) I-cache  
    32. #endif  
    33.     mcr p15, 0, r0, c1, c0, 0  
    34.   
    35. #ifdef CONFIG_ARM_ERRATA_716044  
    36.     mrc p15, 0, r0, c1, c0, 0   @ read system control register  
    37.     orr r0, r0, #1 << 11  @ set bit #11  
    38.     mcr p15, 0, r0, c1, c0, 0   @ write system control register  
    39. #endif  
    40.   
    41. #ifdef CONFIG_ARM_ERRATA_742230  
    42.     mrc p15, 0, r0, c15, c0, 1  @ read diagnostic register  
    43.     orr r0, r0, #1 << 4       @ set bit #4  
    44.     mcr p15, 0, r0, c15, c0, 1  @ write diagnostic register  
    45. #endif  
    46.   
    47. #ifdef CONFIG_ARM_ERRATA_743622  
    48.     mrc p15, 0, r0, c15, c0, 1  @ read diagnostic register  
    49.     orr r0, r0, #1 << 6       @ set bit #6  
    50.     mcr p15, 0, r0, c15, c0, 1  @ write diagnostic register  
    51. #endif  
    52.   
    53. #ifdef CONFIG_ARM_ERRATA_751472  
    54.     mrc p15, 0, r0, c15, c0, 1  @ read diagnostic register  
    55.     orr r0, r0, #1 << 11  @ set bit #11  
    56.     mcr p15, 0, r0, c15, c0, 1  @ write diagnostic register  
    57. #endif  
    58.   
    59.     mov pc, lr          @ back to my caller  
    60. ENDPROC(cpu_init_cp15)  

    cpu_init_crit

    [plain] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. #ifndef CONFIG_SKIP_LOWLEVEL_INIT  
    2. /*************************************************************************  
    3.  *  
    4.  * CPU_init_critical registers  
    5.  *  
    6.  * setup important registers  
    7.  * setup memory timing  
    8.  *  
    9.  *************************************************************************/  
    10. ENTRY(cpu_init_crit)  
    11.     /*  
    12.      * Jump to board specific initialization...  
    13.      * The Mask ROM will have already initialized  
    14.      * basic memory. Go here to bump up clock rate and handle  
    15.      * wake up conditions.  
    16.      */  
    17.     b   lowlevel_init       @ go setup pll,mux,memory  
    18. ENDPROC(cpu_init_crit)  
    19. #endif  
    • b lowlevel_init : 跳转到<arch/arm/cpu/armv7/lowlevel_init.S>中的lowlevel_init

    lowlevel_init.S

    lowlevel_init

    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. #include <asm-offsets.h>  
    2. #include <config.h>  
    3. #include <linux/linkage.h>  
    4.   
    5. ENTRY(lowlevel_init)  
    6.     /*  
    7.      * Setup a temporary stack  
    8.      */  
    9.     ldr sp, =CONFIG_SYS_INIT_SP_ADDR  
    10.     bic sp, sp, #7 /* 8-byte alignment for ABI compliance */  
    11. #ifdef CONFIG_SPL_BUILD  
    12.     ldr r9, =gdata  
    13. #else  
    14.     sub sp, #GD_SIZE  
    15.     bic sp, sp, #7  
    16.     mov r9, sp  
    17. #endif  
    18.     /*  
    19.      * Save the old lr(passed in ip) and the current lr to stack  
    20.      */  
    21.     push    {ip, lr}  
    22.   
    23.     /*  
    24.      * go setup pll, mux, memory  
    25.      */  
    26.     bl  s_init  
    27.     pop {ip, pc}  
    以前老版本的uboot, lowlevel_init一般都是在board/xxx下面的板级文件夹下面实现的. 现在直接放到CPUDIR下面了, 那它做了什么事情呢
    • 对stack pointer赋值成CONFIG_SYS_INIT_SP_ADDR
    • 确保sp是8字节对齐
    • 将gdata的地址存入到r9寄存器中
    • 跳转到 s_init: 这个s_init就需要芯片厂商或者我们自己在板级文件里面实现了. 它主要做的事情
      • setup pll, mux, memory
    我个人感觉, 新版本的uboot在CPUDIR下实现了一个lowlevel_init.S文件, 主要目标是初始化sp, 这样s_init就可以用C语言实现了. 而以前的老版本里面, s_init里面要做的事情都是用汇编做的.

    crt0.S

    _main

    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. ENTRY(_main)  
    2.   
    3. /*  
    4.  * Set up initial C runtime environment and call board_init_f(0).  
    5.  */  
    6.   
    7. #if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)  
    8.     ldr sp, =(CONFIG_SPL_STACK)  
    9. #else  
    10.     ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)  
    11. #endif  
    12.     bic sp, sp, #7  /* 8-byte alignment for ABI compliance */  
    13.     sub sp, #GD_SIZE    /* allocate one GD above SP */  
    14.     bic sp, sp, #7  /* 8-byte alignment for ABI compliance */  
    15.     mov r9, sp      /* GD is above SP */  
    16.     mov r0, #0  
    17.     bl  board_init_f  
    • 重新对SP赋值, 确认sp是8字对齐
    • 在栈顶保留一个global_data的大小, 这个global_data是uboot里面的一个全局数据, 很多地方都会用到. 俗称 gd_t
    • 确认更新后的sp是8字对齐
    • r9指向global_data, 后面别的地方想用global_data时候, 可以直接从r9里面获取地址.
    • r0赋值0
    • bl board_init_f: 跳转到board_init_f. 在编译SPL时, 分析Makefile可以看出, 该函数的实现是在<arch/arm/lib/spl.c>. 

    arch/arm/lib/spl.c

    board_init_f

    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. /*  
    2.  * In the context of SPL, board_init_f must ensure that any clocks/etc for  
    3.  * DDR are enabled, ensure that the stack pointer is valid, clear the BSS  
    4.  * and call board_init_f.  We provide this version by default but mark it  
    5.  * as __weak to allow for platforms to do this in their own way if needed.  
    6.  */  
    7. void __weak board_init_f(ulong dummy)  
    8. {  
    9.     /* Clear the BSS. */  
    10.     memset(__bss_start, 0, __bss_end - __bss_start);  
    11.   
    12.     /* Set global data pointer. */  
    13.     gd = &gdata;  
    14.   
    15.     board_init_r(NULL, 0);  
    16. }  
    • __weak: 表明该函数可以被重新定义
    • 对BSS段进行清零操作
    • gd = &gdata;
      • gd的定义在DECLARE_GLOBAL_DATA_PTR <arch/arm/include/asm/global_data.h>
        • #define DECLARE_GLOBAL_DATA_PTR     register volatile gd_t *gd asm ("r9")
          • 还记得r9这个寄存器吗, 在上面初始化过了
      • gdata的定义在本文件中: gd_t gdata __attribute__ ((section(".data")));  
        • 它是一个 gd_t 也就是global_data类型的变量
        • __attribute__表示这个变量会被放到".data"这个输入段中. 连接器会把输入段按照链接脚本(u-boot-spl.lds)里面指定的规则存放到输出段.
      • 为什么会有这个赋值操作, 不太明白...
    • board_init_r : 在编译SPL时, 分析Makefile可以看出, 该函数的实现是在<common/spl/spl.c>

    common/spl/spl.c

    board_init_r

    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. #ifdef CONFIG_SYS_SPL_MALLOC_START  
    2.     mem_malloc_init(CONFIG_SYS_SPL_MALLOC_START,  
    3.             CONFIG_SYS_SPL_MALLOC_SIZE);  
    4. #endif  
    • 如果定义了:CONFIG_SYS_SPL_MALLOC_START, 则进行memory的malloc池初始化. 以后调用malloc就在这个池子里面分配内存
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. #ifndef CONFIG_PPC  
    2.     /*  
    3.      * timer_init() does not exist on PPC systems. The timer is initialized  
    4.      * and enabled (decrementer) in interrupt_init() here.  
    5.      */  
    6.     timer_init();  
    7. #endif  
    • 如果没有定义:CONFIG_PPC, 则进行timer的初始化. <arch/arm/cpu/armv7/s5p-common/timer.c>里面定义
    [plain] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. #ifdef CONFIG_SPL_BOARD_INIT  
    2.     spl_board_init();  
    3. #endif  
    • SPL阶段, 如果还需要做什么初始化动作, 可以放在这里. 具体的实现可以在BOARDDIR下面.
    [plain] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. boot_device = spl_boot_device();  
    2.     debug("boot device - %d\n", boot_device);  
    • 必须实现spl_boot_device, 返回是从哪个外部设备启动的(NAND/SDCARD/NOR...). 可以厂商或者自己在BOARDDIR下面实现
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1.     switch (boot_device) {  
    2. #ifdef CONFIG_SPL_RAM_DEVICE  
    3.     case BOOT_DEVICE_RAM:  
    4.         spl_ram_load_image();  
    5.         break;  
    6. #endif  
    7. #ifdef CONFIG_SPL_MMC_SUPPORT  
    8.     case BOOT_DEVICE_MMC1:  
    9.     case BOOT_DEVICE_MMC2:  
    10.     case BOOT_DEVICE_MMC2_2:  
    11.         spl_mmc_load_image();  
    12.         break;  
    13. #endif  
    14. #ifdef CONFIG_SPL_NAND_SUPPORT  
    15.     case BOOT_DEVICE_NAND:  
    16.         spl_nand_load_image();  
    17.         break;  
    18. #endif  
    19. #ifdef CONFIG_SPL_ONENAND_SUPPORT  
    20.     case BOOT_DEVICE_ONENAND:  
    21.         spl_onenand_load_image();  
    22.         break;  
    23. #endif  
    24. #ifdef CONFIG_SPL_NOR_SUPPORT  
    25.     case BOOT_DEVICE_NOR:  
    26.         spl_nor_load_image();  
    27.         break;  
    28. #endif  
    29. #ifdef CONFIG_SPL_YMODEM_SUPPORT  
    30.     case BOOT_DEVICE_UART:  
    31.         spl_ymodem_load_image();  
    32.         break;  
    33. #endif  
    34. #ifdef CONFIG_SPL_SPI_SUPPORT  
    35.     case BOOT_DEVICE_SPI:  
    36.         spl_spi_load_image();  
    37.         break;  
    38. #endif  
    39. #ifdef CONFIG_SPL_ETH_SUPPORT  
    40.     case BOOT_DEVICE_CPGMAC:  
    41. #ifdef CONFIG_SPL_ETH_DEVICE  
    42.         spl_net_load_image(CONFIG_SPL_ETH_DEVICE);  
    43. #else  
    44.         spl_net_load_image(NULL);  
    45. #endif  
    46.         break;  
    47. #endif  
    48. #ifdef CONFIG_SPL_USBETH_SUPPORT  
    49.     case BOOT_DEVICE_USBETH:  
    50.         spl_net_load_image("usb_ether");  
    51.         break;  
    52. #endif  
    53.     default:  
    54.         debug("SPL: Un-supported Boot Device\n");  
    55.         hang();  
    56.     }  
    • 将image从具体的外部设备中load到ram中. 这里暂时先不分析具体的load过程.
    [plain] view plain copy
     在CODE上查看代码片派生到我的代码片
    1.     switch (spl_image.os) {  
    2.     case IH_OS_U_BOOT:  
    3.         debug("Jumping to U-Boot\n");  
    4.         break;  
    5. #ifdef CONFIG_SPL_OS_BOOT  
    6.     case IH_OS_LINUX:  
    7.         debug("Jumping to Linux\n");  
    8.         spl_board_prepare_for_linux();  
    9.         jump_to_image_linux((void *)CONFIG_SYS_SPL_ARGS_ADDR);  
    10. #endif  
    11.     default:  
    12.         debug("Unsupported OS image.. Jumping nevertheless..\n");  
    13.     }  
    14.     jump_to_image_no_args(&spl_image);  
    • 判断image的类型
      • 如果是u-boot,则直接break, 去运行u-boot
      • 如果是Linux,则启动Linux
    至此,SPL结束它的生命,控制权交于u-boot或Linux

    在接下来的一篇中, 我们会分析当控制权交给u-boot之后, uboot的运行流程

    总结

    SPL移植注意点

    • s_init: C语言实现此函数, 必须的. 如果是厂商提供的, 一般在arch/arm/cpu/xxx下面. 如果厂商没有提供, 我们可以在BOARDDIR下面实现. 主要完成以下功能
      • 设置CPU的PLL, GPIO管脚复用, memory等
    • spl_board_init: C语言实现, 可选的.  如果是厂商提供的, 一般在arch/arm/cpu/xxx下面. 如果厂商没有提供, 我们可以在BOARDDIR下面实现. 主要完成的功能自己决定
    • spl_boot_device: C语言实现, 必须的. 如果是厂商提供的, 一般在arch/arm/cpu/xxx下面. 如果厂商没有提供, 我们可以在BOARDDIR下面实现. 主要完成的功能,返回是从什么设备启动的(NAND/SDCARD/Nor ...). 像Atmel, Samsung的芯片, 都是有办法做这个事情的.
    展开全文
  • SPL Spectrum Analyzer 介绍SPL Spectrum AnalyzerApp measures and analyses sound pressure level and sound frequency spectrum in real time (RTA) using FFT. It is very easy to use and offers a lot of ...

    SPL Spectrum Analyzer 介绍

    SPL Spectrum Analyzer

    App measures and analyses sound pressure level and sound frequency spectrum in real time (RTA) using FFT. It is very easy to use and offers a lot of useful features: high RTA refreshing rate and frequency resolution, adjustable sound pressure level scale (up to 150 dB), RTA peak hold function, flat reference line, local peaks... RTA measurement can be recorded on 3 separate channels. User can later compare SPL and frequency response charts between the channels.It also includes a signal (tone) generator, which helps us measuring the frequency response of a sound system. Input/output can be adjusted to Internal, AUX or Bluetooth. However, all I/O options and combinations do not work on all devices. Microphone can be accurately calibrated for each frequency band separately.It is very easy to use and offers a lot of useful features: high RTA refreshing rate and frequency resolution, adjustable sound pressure level scale (up to 150 dB), RTA peak hold function, flat reference line, local peaks...RTA measurement can be recorded on 3 separate channels. User can later compare SPL and frequency response charts between the channels.It also includes a signal (tone) generator, which helps us measuring the frequency response of a sound system.Input/output can be adjusted to Internal, AUX or Bluetooth. However, all I/O options and combinations do not work on all devices.Microphone can be accurately calibrated for each frequency band separately.

    来自应用汇: SPL Spectrum Analyzer http://www.appchina.com/app/com.pcmehanik.splspectrumanalyzer?from=spi-desc

    SPL Spectrum Analyzer 历史版本

    8f82527d5eb839ccc3f0ef12451dead2.png

    SPL Spectrum Analyzer

    版本: 7.6

    大小: 3.76 M

    Some bugs fixed.

    下载

    7a66749e6dc12b7c9d324e51b791b802.png

    SPL Spectrum Analyzer

    版本: 7.5

    大小: 3.08 M

    Some bugs fixed.

    下载

    0df7ec18fb501da462d30f2420ae9328.png

    SPL Spectrum Analyzer

    版本: 7.4

    大小: 2.69 M

    Some bugs fixed.

    下载

    f8c3e0b422dd70fdfec91c05fbe75293.png

    SPL Spectrum Analyzer

    版本: 7.3

    大小: 2.44 M

    Some bugs fixed.

    下载

    9a8d935c6b45fd9c36ee0c27e00ca6e6.png

    SPL Spectrum Analyzer

    版本: 7.2

    大小: 2.60 M

    Some bugs fixed.

    下载

    44b71f6f69d7fe1fa10ae4f7adca9ca8.png

    SPL Spectrum Analyzer

    版本: 7.0

    大小: 1.85 M

    Some bugs fixed.

    下载

    502f6181feafe288baac4900f7f03d50.png

    SPL Spectrum Analyzer

    版本: 6.9

    大小: 2.92 M

    Some bugs fixed.

    下载

    11fefbfa4835e957be712d27166bd084.png

    SPL Spectrum Analyzer

    版本: 6.8

    大小: 2.92 M

    Some bugs fixed.

    下载

    4e4cd009b2f1efe717a92c5f584d0443.png

    SPL Spectrum Analyzer

    版本: 6.7

    大小: 2.89 M

    Some bugs fixed.

    下载

    69ddb3bb7e9c02e92ab66ddad5427464.png

    SPL Spectrum Analyzer

    版本: 6.6

    大小: 2.92 M

    Some bugs fixed.

    下载

    SPL Spectrum Analyzer 版本更新

    Some bugs fixed.

    SPL Spectrum Analyzer 类似软件

    包含 SPL Spectrum Analyzer 的应用集

    3f8a95037deb291503056006199af0ff.png

    02f3d89b526136be167e654d397c4ea2.png

    b7cbd890ff65c7bcf01189379f1be3e3.png

    开拓者应用

    缘来幸福

    75ee6f5f5629a12115e6b5958df898ea.png4439

    79b3d8483a835fc456cdfa7bcb7aef04.png7

    2018-12-23

    f64e55ac6ce82a9beb3c0aa985805db6.png

    7cd1bd0c8da8d586e9f153e2eb85cf43.png

    55c4040f1c6bb3806b3781bf13e5b2e5.png

    煲机 调音 声场 音箱 耳机

    缘来幸福

    75ee6f5f5629a12115e6b5958df898ea.png2372

    79b3d8483a835fc456cdfa7bcb7aef04.png5

    2018-01-31

    4a89b50c187d70eb06d0b53ecb7b5960.png

    5a90a9613267048eb401326bf79468b5.png

    19a3a7cf629d38528e80488bdd01481b.png

    音谱 调音 煲机 声场 耳机

    缘来幸福

    75ee6f5f5629a12115e6b5958df898ea.png1037

    79b3d8483a835fc456cdfa7bcb7aef04.png0

    2019-02-11

    用户对 SPL Spectrum Analyzer 的评论

    当前还没有用户评论 ㄟ( ▔, ▔ )ㄏ

    亲,想发表评论请下载[应用汇手机客户端]哦~

    展开全文
  • PHP SPL

    2020-03-15 22:25:45
    SPL是用于解决典型问题(standard problems)的一组接口与类的集合。 数据结构 SplDoublyLinkedList SplStack SplQueue SplHeap SplMaxHeap SplMinHeap SplPriorityQueue SplFixedArray SplObjectStorage ...

    简介

    SPL是用于解决典型问题(standard problems)的一组接口与类的集合。

    数据结构

    SPL 提供了一套标准的数据结构。它们按底层实现进行分组, 通常定义了它们的一般应用领域。

    双向链表

    双链表 (DLL) 是一个链接到两个方向的节点列表。当底层结构是 DLL 时, 迭代器的操作、对两端的访问、节点的添加或删除都具有 O (1) 的开销。因此, 它为栈和队列提供了一个合适的实现。

    堆是遵循堆属性的树状结构: 每个节点都大于或等于其子级, 使用对堆全局的已实现的比较方法进行比较。

    数组

    数组是以连续方式存储数据的结构, 可通过索引进行访问。不要将它们与 php 数组混淆: php 数组实际上是按照有序的列表实现的。

    映射

    映射是一个数据拥有键值对。PHP 数组可以被看作是从整数/字符串到值的映射。SPL 提供了从对象到数据的映射。此映射也可用作对象集。

    展开全文
  • PHP SPL-标准PHP库 在的讨论中,我们发现由于对SPL自身存在的了解不足,因此对SPL的接受度较低。 PHP SPL系列的目的-标准PHP库旨在尝试解决此问题,向每个SPL参与者展示其含义,用途以及使用方法。
  • PHP SPL相关

    2020-12-15 17:43:40
    什么是SPL 什么是Iterator SPL数据结构 SPL迭代器 SPL函数 SPL文件处理 各种类接口 1.1什么是SPL SPL是解决典型(standard porblems)问题的一组接口和类的集合。 1.2 什么是Iterator 它是SPL的核心理念,...

    目录

    1. 简介

    1. 什么是SPL
    2. 什么是Iterator
    3. SPL数据结构
    4. SPL迭代器
    5. SPL函数
    6. SPL文件处理
    7. 各种类接口

     1.1 什么是SPL

    SPL是解决典型(standard porblems)问题的一组接口和类的集合。

    1.2 什么是Iterator 

    它是SPL的核心理念,直译过来就是迭代器。迭代器是常见的设计模式之一,有很多使用场景(遍历文件,数据库)。通俗的说,Iterator能够使很多不同的数据结构(文件,数据库搜索的结果集),都能有统一的操作界面(比如:遍历,foreach)。

    1.3 SPL的数据结构

    1. SplDoublyLinkList   双向链表
    2. SplStack 通过双向链表提供栈的主要功能(就是栈)
    3. SplQueue 通过双向链表提供队列的主要功能
    4. SplHeap  通过双向链表提供堆的主要功能(抽象类 )
    5. SplMaxHeap,SplMinHeap 最大堆和最小堆(继承SplHeap)
    6. SplPriorityQueue 优先级队列 (底层的数据结构是堆)
    7. SplFixedArray 定长数组
    8. SplObjectStorage 对象管理器

    1.4 SPL 迭代器

    1. AppendIterator 迭代器的迭代器
    2. ArrayIterator 数组迭代器
    3. CachingIterator (此对象支持在另一个迭代器上缓存迭代。)
    4. DirectoryIterator (文件和系统目录的迭代)
    5. EmpryIterator 空迭代器
    6. FilesystemIterator 文件迭代器
    7. FilterLteraTor (抽象类)迭代遍历的时候过滤不需要的值
    8. GlobIterator (遍历一个文件系统 类似于golb)  
    9. InfiniteIterator 无限迭代器
    10. IteratorIterator 迭代器包装器
    11. LimitIterator 遍历一个iterator限定子集元素
    12. MultipleIterator 可以把多个迭代器组合为一个整体访问
    13. NoRewindIterator 忽略rewind 可以在多个部分foreach
    14. PraentIterator 对filterItreator扩展 允许recursive操作 只显示有子元素的元素
    15. RecursiveArrayIterator  功能类似arrayIterator  可以递归当前迭代器的条目
    16. RecursiveCachingIterator 
    17. RecursiveCallbackFilterIterator 
    18. RecursiveDirectoryLierator 
    19. RecursiveIteratorIterator 
    20. RecursiveRegexIterator 正则表达式过滤
    21. RecursiveTreeIterator 迭代生成ASCII树
    22. RegexIterator 正则迭代器

     1.5 SPL函数

    1. class_implements  --- 返回指定类实现的所有接口
    2. class_parents --- 返回指定类的父类
    3. class_uses --- 返回指定类的trait
    4. iterator_apply --- 为迭代器每一个元素调用一个用户自定义函数
    5. iterator_count --- 计算迭代器中元素个数
    6. iterator_to_array --- 将迭代器中的元素拷贝到数组
    7. spl_aotoload_call --- 尝试调用所有已经注册的__autoload()函数来装载请求类
    8. spl_autoload_extendsions --- 注册并返回spl_autoload 函数使用的默认文件扩展名
    9. spl_autoload_functions --- 返回所有已注册的__autolaod()函数
    10. spl_autoload_register --- 注册指定函数作为__autoload 的实现
    11. spl_autoload_unregister --- 注销已经注册的__autoload 函数
    12. spl_autoload --- __autoload() 函数的默认实现
    13. spl_classes --- 返回所有可用的SPL类
    14. spl_object_hash --- 返回指定对象的hash id
    15. spl_object_id --- 返回给定对象的handle

    1.6  文件处理

    1. SplFileInfo  为单个文件的信息提供了一个高级的面向对象的接口(接口)
    2. SplFileObject 为文件提供了一个面向对象接口(类)
    3. SplTempFileObejct 继承了上面的

    1.7  各种类接口

    1. ArrayObject 可以将对象作为数组一样工作
    2. SplObserver SplObjserver与SplSubject一起使用 实现观察者模式
    3. SplSubject 
    4. Countable 实现接口可以被用于count()函数
    5. OuterIterator  实现的接口可以迭代迭代器
    6. RecursiveIterator  实现接口的类可以用于递归迭代迭代器
    7. SeekableIterator  搜索迭代器

     

    展开全文
  • 主要介绍了PHP SPL应用,结合实例形式分析了SPL非常重要却又不为人所熟知的功能与相关操作技巧,需要的朋友可以参考下
  • spl基本命令

    2011-11-01 10:54:50
    spl基本命令spl基本命令spl基本命令spl基本命令spl基本命令spl基本命令spl基本命令
  • SPL使用说明

    2013-05-18 11:42:56
    SPL最大的特点是实用. 我感觉tintown设计SPL的时候,完全是从实用角度出发,所以SPL的易用性极高,只需要很少的配置文件(2个XML),而且在功能上,完全围绕如何尽可能简单的做到CRUD,而... 这点在我过的项目中已经得到验证.
  • SPL是用于解决典型问题的一组接口与类的集合。在PHP5.3.0以后成为了PHP内核组件的一部份。一、SPL数据结构(结构数据里可放任意类型数据)1、双向链表接口SplDoublyLinkedList $dbLink = new SplDoublyLinkedList();$...
  • php SPL

    2017-03-05 08:33:11
    SPL是用于解决典型问题(standard problems)的一组接口与类的集合。 数据结构 SPL提供了一组标准数据结构。 双向链表 双向链表 (DLL) is a list of nodes linked in both directions to each others. ...
  • SPL3-源码

    2021-03-31 00:17:38
    SPL3
  • 6800 SPL2.47

    2012-03-16 21:41:26
    电信手机6800 SPL2.47
  • SPL添加驱动

    2019-06-25 19:02:35
    如何在spl添加i2c驱动 1.查看drivers/Makefile文件,有定义: drivers/Makefile: obj-$(CONFIG_$(SPL_TPL_)I2C_SUPPORT) += i2c/ 然后在configs/xx_defconfig中添加: CONFIG_SPL_I2C_SUPPORT=y 2....
  • 这个东西应该属于PHP中的高级内容,看上去很复杂,但是非常有用,所以我了长篇笔记。不然记不住,以后要用的时候,还是要从头学起。由于这是供自己参考的笔记,不是教程,所以写得比较简单,没有多解释。但是我想...
  • SPL函数

    2018-08-21 15:09:39
    //设置autoload寻找php... spl_autoload_extensions('.class.php, .php'); //设置autoload寻找PHP、定义的类文件的目录,多个目录用PATH_SEPARATOR进行分隔 set_include_path(get_include_path().PATH_SEPARATO...
  • SPL基础知识

    2015-06-28 20:01:17
    前些日子一直在学习php,没有笔记,现在趁着一身的热,赶紧补上,作为以后的备用?在学习之前,首页要知道我们的学习目标,紧紧是为了学会"spl"?会用就行了?no.no.no,其实就是以下的目标: 什么是splspl...
  • SPL

    2017-02-14 10:49:00
    SPL类 用途:对类,方法,属性,参数的提取生成文档;自动加载插件 实列化类同于new:$ref = new ReflectionClass($classname);$class = $ref->newInstance(); //相当于new $classname; 区别:...
  • spl android

    2010-07-25 10:13:15
    android 一个webservice例子
  • uboot spl

    2015-04-16 11:52:20
    uboot spl Introduction: ===== The idea is to build a mini u-boot(same as UBL in Davinci?) out of the u-boot tree that fits into SoC's internal SRAM ( Such a mini u-boot is typical
  • <p>what is the <strong>difference,*<em>usage* scenerio between normal ARray, SPL array and SPL datastorage? It would be great if anyone can give some practical example of usage of SPLarray and SPL ...
  • spl06使用代码.zip

    2021-03-30 11:03:56
    spl06使用
  • m trying to use spl_hostid kernel parameter, but it seems to be recognized only by zfs, while spl sets its own hostid, which is clear from the boot message. <p>There was some comment a year ago about ...
  • SPL 教案——程序

    2019-10-18 11:10:31
    SPL教程.pdf
  • spl_classes

    2019-03-27 22:08:40
    spl_classes—返回所有可用的SPL类 Example #1spl_classes()example <?php print_r(spl_classes()); ?> 以上例程的输出类似于: Array ( [ArrayObject] => ArrayObject [ArrayIterator] => ...
  • 本文实例讲述了PHP标准库 (SPL)——Countable用法。分享给大家供大家参考,具体如下:类实现 Countable 可被用于 count() 函数.接口摘要Countable {/* 方法 */abstract public count ( void ) : int}当一个类实现了...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 27,488
精华内容 10,995
关键字:

做spl