OK6410开发板bootloader架构设计分析---嵌入式回归第五篇
来源:互联网 发布:应聘java简历自我评价 编辑:程序博客网 时间:2024/05/22 02:27
在介绍bootloader嵌,先简要介绍一下汇编的相关知识!为后边的学习做铺垫!大学里面学习过汇编,之前汇编部分的视频也是一点一点的跟着国嵌的视频把代码撸出来一步一步的调试!相对学习起来还是比较容易的!比数据结构和算法简单的多了。
汇编语言介绍这一部分暂时就不写笔记了!写bootloader后边会用到比较多,这里只简单的挑一些重要的介绍一下。
ARM汇编分类:
1. ARM标准汇编:使用ARM公司的汇编器,适合在windows平台下使用,
2. GNU汇编:适合于GNU交叉编译工具链中的汇编器,适合Linux开发平台
bootloader在最开始的时候,并没有构建运行C语言的环境,所以一开始都是用汇编代码写的,到后边等构建好了C代码环境,就可以使用C来写了,这里汇编先只简要介绍一下!
汇编程序框架:(后边的bootloader也是按照这个格式写的)
.section .data
<初始化的数据>
.section .bss
<未初始化的数据>
.section .text
.global _start
_start:
<汇编代码>
1. ARM汇编指令分类学习(指令比较多):
2. ARM伪指令
伪指令本身并没有所对应的机器码,本身只是在编译的时候起作用,或者转化为其他的实际指令来运行
3. 协处理器访问指令:(这个比较重要,在bootloader中这个一般在关键点的地方用的很多)
下边来开始慢慢一步一步来记录bootloader从0到有,从有到精通!不想当将军的士兵不是好厨师!
bootloader设计蓝图大纲
1. bootloader 的作用 (类似于windows的bios程序,主要做一些硬件的初始化工作)
2. bootloader 设计方法 (模仿)
3. bootloader代码工程建立 (通过sourceInsight )
ARM处理器启动流程:(这个还是datasheet说了算)
1. 启动方式:
2. 地址布局:
3. 启动流程:
这里BL0里面芯片厂商已经给我们把程序固化好了!这里我们需要完成BL1和BL2的部分!
这是uboot源码里面顶层Makefile里面的一个关于6410的配置选项:这里有一个smdk6410 选项
<span style="font-size:24px;">smdk6410_config:unconfig@$(MKCONFIG) $(@:_config=) arm s3c64xx smdk6410 samsung s3c6410 </span>同理我们可以在/board/samsung/目录下找到这个目录文件smdk6410 ,这里面存放的就是支持开发板的一些相关文件
打开里面的链接器脚本u-boot.lds文件可以看到一些非常有用的信息:
/* * (C) Copyright 2002 * Gary Jennejohn, DENX Software Engineering, <gj@denx.de> * * See file CREDITS for list of people who contributed to this * project. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/OUTPUT_ARCH(arm)ENTRY(_start)SECTIONS{. = 0x00000000;. = ALIGN(4);.text :{ cpu/s3c64xx/start.o(.text) cpu/s3c64xx/s3c6410/cpu_init.o(.text) cpu/s3c64xx/onenand_cp.o(.text) cpu/s3c64xx/nand_cp.o(.text) cpu/s3c64xx/movi.o (.text) *(.text) lib_arm/div0.o}. = ALIGN(4);.rodata : { *(.rodata) }. = ALIGN(4);.data : { *(.data) }. = ALIGN(4);.got : { *(.got) }__u_boot_cmd_start = .;.u_boot_cmd : { *(.u_boot_cmd) }__u_boot_cmd_end = .;. = ALIGN(4);.mmudata : { *(.mmudata) }. = ALIGN(4);__bss_start = .;.bss : { *(.bss) }_end = .;}
可以看到位于代码段最前端的是cpu/s3c64xx/start.o文件,这里start.o对应的是start.S文件!可以在相应的目录下看到!
从上面的链接器脚本中可以看到 :ENTRY(_start) 所以整个程序的入口就是_start标号处,下面可以来看看start.S文件的内容:
/* * armboot - Startup Code for S3C6400/ARM1176 CPU-core * * Copyright (c) 2007Samsung Electronics * * * See file CREDITS for list of people who contributed to this * project. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * 2007-09-21 - Restructured codes by jsgood (jsgood.yang@samsung.com) * 2007-09-21 - Added moviNAND and OneNAND boot codes by jsgood (jsgood.yang@samsung.com) * Base codes by scsuh (sc.suh) */#include <config.h>#include <version.h>#ifdef CONFIG_ENABLE_MMU#include <asm/proc/domain.h>#endif#include <regs.h>#ifndef CONFIG_ENABLE_MMU#ifndef CFG_PHY_UBOOT_BASE#define CFG_PHY_UBOOT_BASECFG_UBOOT_BASE#endif#endif/* ************************************************************************* * * Jump vector table as in table 3.1 in [1] * ************************************************************************* */.globl _start_start: bresetldrpc, _undefined_instructionldrpc, _software_interruptldrpc, _prefetch_abortldrpc, _data_abortldrpc, _not_usedldrpc, _irqldrpc, _fiq_undefined_instruction:.word undefined_instruction_software_interrupt:.word software_interrupt_prefetch_abort:.word prefetch_abort_data_abort:.word data_abort_not_used:.word not_used_irq:.word irq_fiq:.word fiq_pad:.word 0x12345678 /* now 16*4=64 */.global _end_vect_end_vect:.balignl 16,0xdeadbeef/* ************************************************************************* * * Startup Code (reset vector) * * do important init only if we don't start from memory! * setup Memory and board specific bits prior to relocation. * relocate armboot to ram * setup stack * ************************************************************************* */_TEXT_BASE:.wordTEXT_BASE/* * Below variable is very important because we use MMU in U-Boot. * Without it, we cannot run code correctly before MMU is ON. * by scsuh. */_TEXT_PHY_BASE:.wordCFG_PHY_UBOOT_BASE.globl _armboot_start_armboot_start:.word _start/* * These are defined in the board-specific linker script. */.globl _bss_start_bss_start:.word __bss_start.globl _bss_end_bss_end:.word _end#ifdef CONFIG_USE_IRQ/* IRQ stack memory (calculated at run-time) */.globl IRQ_STACK_STARTIRQ_STACK_START:.word0x0badc0de/* IRQ stack memory (calculated at run-time) */.globl FIQ_STACK_STARTFIQ_STACK_START:.word 0x0badc0de#endif/* * the actual reset code */reset:/* * set the cpu to SVC32 mode */mrsr0,cpsrbicr0,r0,#0x1forrr0,r0,#0xd3msrcpsr,r0/* ************************************************************************* * * CPU_init_critical registers * * setup important registers * setup memory timing * ************************************************************************* */ /* * we do sys-critical inits only at reboot, * not when booting from ram! */cpu_init_crit:/* * flush v4 I/D caches */movr0, #0mcrp15, 0, r0, c7, c7, 0/* flush v3/v4 cache */mcrp15, 0, r0, c8, c7, 0/* flush v4 TLB *//* * disable MMU stuff and caches */mrcp15, 0, r0, c1, c0, 0bicr0, r0, #0x00002300@ clear bits 13, 9:8 (--V- --RS)bicr0, r0, #0x00000087@ clear bits 7, 2:0 (B--- -CAM)orrr0, r0, #0x00000002@ set bit 2 (A) Alignorrr0, r0, #0x00001000@ set bit 12 (I) I-Cachemcrp15, 0, r0, c1, c0, 0/* Peri port setup */ldrr0, =0x70000000orrr0, r0, #0x13 mcrp15,0,r0,c15,c2,4 @ 256M(0x70000000-0x7fffffff)#ifdef CONFIG_BOOT_ONENANDldrr0, =0x70000000@ onenand controller setuporrr0, r0, #0x100000ldrr1, =0x4000orrr1, r1, #0xe0strr1, [r0]#if defined(CONFIG_S3C6410) || defined(CONFIG_S3C6430)orrr0, r0, #300@ disable watchdogmovr1, #1strr1, [r0]movr1, #0x23000000@ start buffer registerorrr1, r1, #0x30000orrr1, r1, #0xc800#elsemovr1, =0x20000000@ start buffer registerorrr1, r1, #0xc30000orrr1, r1, #0xc800#endifsubr0, r1, #0x0400@ start address1 registerldrr2, [r1, #0x84]@ ecc bypassorrr2, r2, #0x100strr2, [r1, #0x84]movr3, #0x0@ DFS, FBAstrr3, [r0, #0x00]strr3, [r0, #0x04]@ select dataram for DDP as 0movr4, #0x104@ interrupt registermovr5, #0x0002@ FPA, FSAmovr6, #0x0800@ BSAonenand_bl1_load:strr5, [r0, #0x1c]@ save FPA, FSAorrr6, r6, #0x02@ BSCstrr6, [r1, #0x00]@ save BSA, BSCstrr3, [r1, r4]@ clear interruptstrr3, [r1, #0x80]@ write load commandmovr7, #0x100@ need small delayonenand_wait_loop1:subsr7, r7, #0x1bneonenand_wait_loop1addr5, r5, #0x2@ next FPA, FSAsubr6, r6, #0x2addr6, r6, #0x200@ next BSAcmpr5, #0x8bneonenand_bl1_load#endif/* * Go setup Memory and board specific bits prior to relocation. */bllowlevel_init/* go setup pll,mux,memory *//* when we already run in ram, we don't need to relocate U-Boot. * and actually, memory controller must be configured before U-Boot * is running in ram. */ ldrr0, =0xff000fffbicr1, pc, r0/* r0 <- current base addr of code */ldrr2, _TEXT_BASE/* r1 <- original base addr in ram */bicr2, r2, r0/* r0 <- current base addr of code */cmp r1, r2 /* compare r0, r1 */beq after_copy/* r0 == r1 then skip flash copy */#ifdef CONFIG_BOOT_NOR/* relocate U-Boot to RAM */adrr0, _start/* r0 <- current position of code */ldrr1, _TEXT_PHY_BASE/* r1 <- destination */ldrr2, _armboot_startldrr3, _bss_startsubr2, r3, r2/* r2 <- size of armboot */addr2, r0, r2/* r2 <- source end address */nor_copy_loop:ldmiar0!, {r3-r10}/* copy from source address [r0] */stmiar1!, {r3-r10}/* copy to target address [r1] */cmpr0, r2/* until source end addreee [r2] */blenor_copy_loopbafter_copy#endif#ifdef CONFIG_BOOT_NANDmovr0, #0x1000blcopy_from_nand#endif#ifdef CONFIG_BOOT_MOVINANDldrsp, _TEXT_PHY_BASEblmovi_bl2_copybafter_copy#endif#ifdef CONFIG_BOOT_ONENANDldrsp, =0x50000000@ temporary stack#ifdef CONFIG_S3C6400movr1, =0x20000000@ start buffer registerorrr1, r1, #0xc30000orrr1, r1, #0xc800#elsemovr1, #0x23000000@ start buffer registerorrr1, r1, #0x30000orrr1, r1, #0xc800#endifldrr2, [r1, #0x84]@ ecc bypassorrr2, r2, #0x100strr2, [r1, #0x84]subr0, r1, #0x0400@ start address1 registerstrr3, [r0, #0x00]strr3, [r0, #0x04]@ select dataram for DDP as 0movr4, #0x104@ interrupt registermovr6, #0x0c00@ fixed dataram1 sector numberstrr6, [r1, #0x00]movr3, #0x0@ DFS, FBAmovr5, #0x0000@ FPA, FSAldrr9, =CFG_PHY_UBOOT_BASE@ destinationonenand_bl2_load:strr3, [r0, #0x00]@ save DFS, FBAstrr5, [r0, #0x1c]@ save FPA, FSAmovr7, #0x0@ clear interruptstrr7, [r1, r4]strr7, [r1, #0x80]@ write load commandmovr8, #0x1000onenand_wait_loop2:subsr8, r8, #0x1bneonenand_wait_loop2onenand_wait_int:@ wait INT and RIldrr7, [r1, r4]movr8, #0x8000orrr8, r8, #0x80tstr7, r8beqonenand_wait_intmovr7, #0x0@ clear interruptstrr7, [r1, r4]movr8, #0xc00@ source address (dataram1)movr10, #0x40@ copy loop count (64 = 2048 / 32)stmiasp, {r0-r7}@ backuponenand_copy_to_ram:ldmiar8!, {r0-r7}stmiar9!, {r0-r7}subsr10, r10, #0x1bneonenand_copy_to_ramldmiasp, {r0-r7}@ restoreaddr5, r5, #0x4@ next FPAcmpr5, #0x100@ last FPA?bneonenand_bl2_load/* next block */movr5, #0x0@ reset FPAaddr3, r3, #0x1@ next FBAcmpr3, #0x2@ last FBA?bneonenand_bl2_loadbafter_copy#endif#ifdef CONFIG_BOOT_ONENAND_IROMldrsp, _TEXT_PHY_BASEblonenand_bl2_copybafter_copy#endifafter_copy:#ifdef CONFIG_ENABLE_MMUenable_mmu:/* enable domain access */ldrr5, =0x0000ffffmcrp15, 0, r5, c3, c0, 0@ load domain access register/* Set the TTB register */ldrr0, _mmu_table_baseldrr1, =CFG_PHY_UBOOT_BASEldrr2, =0xfff00000bicr0, r0, r2orrr1, r0, r1mcrp15, 0, r1, c2, c0, 0/* Enable the MMU */mmu_on:mrcp15, 0, r0, c1, c0, 0orrr0, r0, #1/* Set CR_M to enable MMU */mcrp15, 0, r0, c1, c0, 0nopnopnopnop#endifskip_hw_init:/* Set up the stack */stack_setup:#ifdef CONFIG_MEMORY_UPPER_CODEldrsp, =(CFG_UBOOT_BASE + CFG_UBOOT_SIZE - 0xc)#elseldrr0, _TEXT_BASE/* upper 128 KiB: relocated uboot */subr0, r0, #CFG_MALLOC_LEN/* malloc area */subr0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */#ifdef CONFIG_USE_IRQsubr0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)#endifsubsp, r0, #12/* leave 3 words for abort-stack */#endifclear_bss:ldrr0, _bss_start/* find start of bss segment */ldrr1, _bss_end/* stop here */mov r2, #0x00000000/* clear */clbss_l:strr2, [r0]/* clear loop... */addr0, r0, #4cmpr0, r1bleclbss_lldrpc, _start_armboot_start_armboot:.word start_armboot#ifdef CONFIG_ENABLE_MMU_mmu_table_base:.word mmu_table#endif/* * copy U-Boot to SDRAM and jump to ram (from NAND or OneNAND) * r0: size to be compared * Load 1'st 2blocks to RAM because U-boot's size is larger than 1block(128k) size */.globl copy_from_nandcopy_from_nand:movr10, lr/* save return address */movr9, r0/* get ready to call C functions */ldrsp, _TEXT_PHY_BASE/* setup temp stack pointer */subsp, sp, #12movfp, #0/* no previous frame, so fp=0 */movr9, #0x1000blcopy_uboot_to_ram3:tst r0, #0x0bnecopy_failedldrr0, =0x0c000000ldrr1, _TEXT_PHY_BASE1:ldrr3, [r0], #4ldrr4, [r1], #4teqr3, r4bnecompare_failed/* not matched */subsr9, r9, #4bne1b4:movlr, r10/* all is OK */movpc, lrcopy_failed:nop/* copy from nand failed */bcopy_failedcompare_failed:nop/* compare failed */bcompare_failed/* * we assume that cache operation is done before. (eg. cleanup_before_linux()) * actually, we don't need to do anything about cache if not use d-cache in U-Boot * So, in this function we clean only MMU. by scsuh * * voidtheLastJump(void *kernel, int arch_num, uint boot_params); */#ifdef CONFIG_ENABLE_MMU.globl theLastJumptheLastJump:movr9, r0ldrr3, =0xfff00000ldrr4, _TEXT_PHY_BASEadrr5, phy_last_jumpbicr5, r5, r3orrr5, r5, r4movpc, r5phy_last_jump:/* * disable MMU stuff */mrcp15, 0, r0, c1, c0, 0bicr0, r0, #0x00002300/* clear bits 13, 9:8 (--V- --RS) */bicr0, r0, #0x00000087/* clear bits 7, 2:0 (B--- -CAM) */orrr0, r0, #0x00000002/* set bit 2 (A) Align */orrr0, r0, #0x00001000/* set bit 12 (I) I-Cache */mcrp15, 0, r0, c1, c0, 0mcrp15, 0, r0, c8, c7, 0/* flush v4 TLB */movr0, #0movpc, r9#endif/* ************************************************************************* * * Interrupt handling * ************************************************************************* */@@ IRQ stack frame.@#define S_FRAME_SIZE72#define S_OLD_R068#define S_PSR64#define S_PC60#define S_LR56#define S_SP52#define S_IP48#define S_FP44#define S_R1040#define S_R936#define S_R832#define S_R728#define S_R624#define S_R520#define S_R416#define S_R312#define S_R28#define S_R14#define S_R00#define MODE_SVC 0x13#define I_BIT 0x80/* * use bad_save_user_regs for abort/prefetch/undef/swi ... * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling */.macrobad_save_user_regssubsp, sp, #S_FRAME_SIZE@ carve out a frame on current user stackstmiasp, {r0 - r12}@ Save user registers (now in svc mode) r0-r12ldrr2, _armboot_startsubr2, r2, #(CFG_MALLOC_LEN)subr2, r2, #(CFG_GBL_DATA_SIZE+8)@ set base 2 words into abort stackldmiar2, {r2 - r3}@ get values for "aborted" pc and cpsr (into parm regs)addr0, sp, #S_FRAME_SIZE@ grab pointer to old stackaddr5, sp, #S_SPmovr1, lrstmiar5, {r0 - r3}@ save sp_SVC, lr_SVC, pc, cpsrmovr0, sp@ save current stack into r0 (param register).endm.macroirq_save_user_regssubsp, sp, #S_FRAME_SIZEstmiasp, {r0 - r12}@ Calling r0-r12addr8, sp, #S_PC@ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good.stmdbr8, {sp, lr}^@ Calling SP, LRstrlr, [r8, #0]@ Save calling PCmrsr6, spsrstrr6, [r8, #4]@ Save CPSRstrr0, [r8, #8]@ Save OLD_R0movr0, sp.endm.macroirq_restore_user_regsldmiasp, {r0 - lr}^@ Calling r0 - lrmovr0, r0ldrlr, [sp, #S_PC]@ Get PCaddsp, sp, #S_FRAME_SIZEsubspc, lr, #4@ return & move spsr_svc into cpsr.endm.macro get_bad_stackldrr13, _armboot_start@ setup our mode stack (enter in banked mode)subr13, r13, #(CFG_MALLOC_LEN)@ move past malloc poolsubr13, r13, #(CFG_GBL_DATA_SIZE+8) @ move to reserved a couple spots for abort stackstrlr, [r13]@ save caller lr in position 0 of saved stackmrslr, spsr@ get the spsrstrlr, [r13, #4]@ save spsr in position 1 of saved stackmovr13, #MODE_SVC@ prepare SVC-Mode@ msrspsr_c, r13msrspsr, r13@ switch modes, make sure moves will executemovlr, pc@ capture return pcmovspc, lr@ jump to next instruction & switch modes..endm.macro get_bad_stack_swisubr13, r13, #4@ space on current stack for scratch reg.strr0, [r13]@ save R0's value.ldrr0, _armboot_start@ get data regions startsubr0, r0, #(CFG_MALLOC_LEN)@ move past malloc poolsubr0, r0, #(CFG_GBL_DATA_SIZE+8)@ move past gbl and a couple spots for abort stackstrlr, [r0]@ save caller lr in position 0 of saved stackmrsr0, spsr@ get the spsrstrlr, [r0, #4]@ save spsr in position 1 of saved stackldrr0, [r13]@ restore r0addr13, r13, #4@ pop stack entry.endm.macro get_irq_stack@ setup IRQ stackldrsp, IRQ_STACK_START.endm.macro get_fiq_stack@ setup FIQ stackldrsp, FIQ_STACK_START.endm/* * exception handlers */.align5undefined_instruction:get_bad_stackbad_save_user_regsbldo_undefined_instruction.align5software_interrupt:get_bad_stack_swibad_save_user_regsbldo_software_interrupt.align5prefetch_abort:get_bad_stackbad_save_user_regsbldo_prefetch_abort.align5data_abort:get_bad_stackbad_save_user_regsbldo_data_abort.align5not_used:get_bad_stackbad_save_user_regsbldo_not_used#ifdef CONFIG_USE_IRQ.align5irq:get_irq_stackirq_save_user_regsbldo_irqirq_restore_user_regs.align5fiq:get_fiq_stack/* someone ought to write a more effiction fiq_save_user_regs */irq_save_user_regsbldo_fiqirq_restore_user_regs#else.align5irq:get_bad_stackbad_save_user_regsbldo_irq.align5fiq:get_bad_stackbad_save_user_regsbldo_fiq#endif.align 5.global arm1136_cache_flusharm1136_cache_flush:mcrp15, 0, r1, c7, c5, 0@ invalidate I cachemovpc, lr@ back to caller#if defined(CONFIG_INTEGRATOR) && defined(CONFIG_ARCH_CINTEGRATOR)/* Use the IntegratorCP function from board/integratorcp/platform.S */#elif defined(CONFIG_S3C64XX)/* For future usage of S3C64XX*/#else.align5.globl reset_cpureset_cpu:ldrr1, rstctl/* get addr for global reset reg */movr3, #0x2/* full reset pll+mpu */strr3, [r1]/* force reset */movr0, r0_loop_forever:b_loop_foreverrstctl:.wordPM_RSTCTRL_WKUP#endif全部都是汇编代码,而且还有点长!其实整个学下来相比数据结构和算法感觉还是简单多了!从上面的代码中可以找到_start标号处,那就是程序开始执行的入口处!下面就可以用sourceInsight来分析源码了!
下面的基本上是对照着uboot源码里面的ok6410 start.S源码分析整个start过程的工作流程图!对比着上面的代码和注释结合起来看可以看到也不是那么复杂!在把里面的各个知识点逐个击破!
- OK6410开发板bootloader架构设计分析---嵌入式回归第五篇
- OK6410开发板系统安装---嵌入式回归第二篇
- OK6410开发板资源介绍---嵌入式回归第一篇
- 一灯大师之点亮OK6410开发板上4个LED裸机程序---嵌入式回归第十篇
- PXA270 BootLoader 架构设计分析
- OK6410之bootloader设计指南
- 【嵌入式开发】 Bootloader 详解 ( 代码环境 | ARM 启动流程 | uboot 工作流程 | 架构设计)
- 【嵌入式开发】 Bootloader 详解 ( 代码环境 | ARM 启动流程 | uboot 工作流程 | 架构设计)
- 嵌入式BootLoader设计实现
- OK6410(s3c6410)的bootloader设计蓝图
- ARM7嵌入式系统中Bootloader分析与设计
- Bootloader架构设计
- Bootloader架构设计
- ok6410 搭建嵌入式开发环境
- (二)U-boot在开发板上移植过程详解--bootloader架构分析
- U-boot在开发板上移植过程详解(1)---bootloader架构分析
- U-boot在开发板上移植过程详解--bootloader架构分析
- (二)U-boot在开发板上移植过程详解--bootloader架构分析
- Codeforces Round #347 (Div. 2) B Rebus (贪心构造)
- Eclipse依赖打包问题
- 第4章--Toast提醒控件的使用
- android-support-multidex解决65535问题
- android的进程间通信----aidl
- OK6410开发板bootloader架构设计分析---嵌入式回归第五篇
- 三步翻转法------有意思的方法
- Lab3:自行车码表
- Algorithm.Find(查找)
- 类的权限修饰符
- 用例图——详解
- WebService学习总结(一)——WebService的相关概念
- 彻底解决 Android Studio 乱码问题
- LeetCode *** 284. Peeking Iterator