UBOOT原始碼分析(詳細)
@可知start.S的流程為:異常向量——上電覆位後進入復位異常向量——跳到啟動程式碼處——設定處理器進入管理模式——關閉看門狗——關閉中斷——設定時鐘分頻——關閉MMU和CACHE——進入lowlever_init.S——檢查當前程式碼所處的位置,如果在FLASH中就將程式碼搬移到RAM中
大多數bootloader都分為stage1和stage2兩部分,u-boot也不例外。依賴於CPU體系結構的程式碼(如裝置初始化程式碼等)通常都放在stage1且可以用匯編語言來實現,而stage2則通常用C語言來實現,這樣可以實現複雜的功能,而且有更好的可讀性和移植性。
1、Stage1start.S
u-boot的stage1程式碼通常放在start.S檔案中,他用匯編語言寫成,其主要程式碼部分如下:(1)定義入口。由於一個可執行的Image必須有一個入口點,並且只能有一個全域性入口,通常這個入口放在ROM(Flash)的0x0地址,因此,必須通知編譯器以使其知道這個入口,該工作可通過修改聯結器指令碼來完成。(2)設定異常向量(Exception Vector)。(3)設定CPU的速度、時鐘頻率及終端控制暫存器。(4)初始化記憶體控制器。(5)將ROM中的程式複製到RAM中。(6)初始化堆疊。(7)轉到RAM中執行,該工作可使用指令ldr pc來完成。
2、Stage2 C語言程式碼部分
lib_arm/board.c中的start armboot是C語言開始的函式也是整個啟動程式碼中C語言的主函式,同時還是整個u-boot(armboot)的主函式,該函式只要完成如下操作:(1)呼叫一系列的初始化函式。(2)初始化Flash裝置。(3)初始化系統記憶體分配函式。(4)如果目標系統擁有NAND裝置,則初始化NAND裝置。(5)如果目標系統有顯示裝置,則初始化該類裝置。(6)初始化相關網路裝置,填寫IP、MAC地址等。(7)進去命令迴圈(即整個boot的工作迴圈),接受使用者從串列埠輸入的命令,然後進行相應的工作。
3、U-Boot的啟動順序(示例,其他u-boot版本類似)
cpu/arm920t/start.S
@檔案包含處理
#include <config.h>
@由頂層的mkconfig生成,其中只包含了一個檔案:configs/<頂層makefile中6個引數的第1個引數>.h
#include <version.h>
#include <status_led.h>
/*
*************************************************************************
*
* Jump vector table as in table 3.1 in [1]
*
*************************************************************************
*/
注:ARM微處理器支援位元組(8位)、半字(16位)、字(32位)3種資料型別
@向量跳轉表,每條佔四個位元組(一個字),地址範圍為0x0000 0000~@0x0000 0020
@ARM體系結構規定在上電覆位後的起始位置,必須有8條連續的跳
@轉指令,通過硬體實現。他們就是異常向量表。ARM在上電覆位後,@是從0x00000000開始啟動的,其實如果bootloader存在,在執行
@下面第一條指令後,就無條件跳轉到start_code,下面一部分並沒@執行。設定異常向量表的作用是識別bootloader。以後系統每當有@異常出現,則CPU會根據異常號,從記憶體的0x00000000處開始查表@做相應的處理
/******************************************************
;當一個異常出現以後,ARM會自動執行以下幾個步驟:
;1.把下一條指令的地址放到連線暫存器LR(通常是R14).---儲存位置
;2.將相應的CPSR(當前程式狀態暫存器)複製到SPSR(備份的程式狀態暫存器)中---儲存CPSR
;3.根據異常型別,強制設定CPSR的執行模式位
;4.強制PC(程式計數器)從相關異常向量地址取出下一條指令執行,從而跳轉到相應的異常處理程式中
*********************************************************/
.globl _start /*系統復位位置,整個程式入口*/
@_start是GNU彙編器的預設入口標籤,.globl將_start宣告為外部程式可訪問的標籤,.globl是GNU彙編的保留關鍵字,前面加點是GNU彙編的語法
_start: b start_code @0x00
@ARM上電後執行的第一條指令,也即復位向量,跳轉到start_code
@reset用b,就是因為reset在MMU建立前後都有可能發生
@其他的異常只有在MMU建立之後才會發生
ldr pc, _undefined_instruction /*未定義指令異常,0x04*/
ldr pc, _software_interrupt /*軟中斷異常,0x08*/
ldr pc, _prefetch_abort /*記憶體操作異常,0x0c*/
ldr pc, _data_abort /*資料異常,0x10*/
ldr pc, _not_used /*未適用,0x14*/
ldr pc, _irq /*慢速中斷異常,0x18*/
ldr pc, _fiq /*快速中斷異常,0x1c*/
@對於ARM資料從記憶體到CPU之間的移動只能通過L/S指令,如:ldr r0,0x12345678為把0x12345678記憶體中的資料寫到r0中,還有一個就是ldr偽指令,如:ldr r0,=0x12345678為把0x12345678地址寫到r0中,mov只能完成暫存器間資料的移動,而且立即數長度限制在8位
_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
@.word為GNU ARM彙編特有的偽操作,為分配一段字記憶體單元(分配的單元為字對齊的),可以使用.word把標誌符作為常量使用。如_fiq:.word
fiq即把fiq存入記憶體變數_fiq中,也即是把fiq放到地址_fiq中。
.balignl 16,0xdeadbeef
@.balignl是.balign的變體
@ .align偽操作用於表示對齊方式:通過新增填充位元組使當前位置
@滿足一定的對齊方式。.balign的作用同.align。
@ .align {alignment} {,fill} {,max}
@ 其中:alignment用於指定對齊方式,可能的取值為2的次
@冪,預設為4。fill是填充內容,預設用0填充。max是填充位元組@數最大值,如果填充位元組數超過max,
就不進行對齊,例如:
@ .align 4 /* 指定對齊方式為字對齊 */
/*
*************************************************************************
*
* Startup Code (called from the ARM reset exception vector)
*
* do important init only if we don't start from memory!
* relocate armboot to ram
* setup stack
* jump to second stage
*
*************************************************************************
@儲存變數的資料區,儲存一些全域性變數,用於BOOT程式從FLASH拷貝@到RAM,或者其它的使用。
@還有一些變數的長度是通過連線腳本里得到,實際上由編譯器算出
@來的
_TEXT_BASE:
@因為linux開始地址是0x30000000,我這裡是64M
SDRAM,所以@TEXT_BASE = 0x33F80000
???
.word TEXT_BASE /*uboot映像在SDRAM中的重定位地址*/
@TEXT_BASE在開發板相關的目錄中的config.mk文件中定義,
他定
@義了程式碼在執行時所在的地址, 那麼_TEXT_BASE中儲存了這個地
@址(這個TEXT_BASE怎麼來的還不清楚)
.globl _armboot_start
_armboot_start:
.word _start
@用_start來初始化_armboot_start。(為什麼要這麼定義一下還不明白)
/*
* These are defined in the board-specific linker script.
*/
@下面這些是定義在開發板目錄連結指令碼中的
.globl _bss_start
_bss_start:
.word __bss_start
@__bss_start定義在和開發板相關的u-boot.lds中,_bss_start儲存的是__bss_start標號所在的地址。
.globl _bss_end
_bss_end:
.word _end
@同上,這樣賦值是因為程式碼所在地址非編譯時的地址,直接取得該標號對應地址。
@中斷的堆疊設定
#ifdef CONFIG_USE_IRQ
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START
IRQ_STACK_START:
.word 0x0badc0de
/* IRQ stack memory (calculated at run-time) */
.globl FIQ_STACK_START
FIQ_STACK_START:
.word 0x0badc0de
#endif
/*
* the actual start code
*/
@復位後執行程式
@真正的初始化從這裡開始了。其實在CPU一上電以後就是跳到這裡執行的
reset:
/*
* set the cpu to SVC32 mode
*/
@更改處理器模式為管理模式
@對狀態暫存器的修改要按照:讀出-修改-寫回的順序來執行
@
31 30 29 28 --- 7 6 - 4 3 2 1 0
N Z C V I F M4 M3 M2 M1 M0
0 0 0 0 0 User26 模式
0 0 0 0 1 FIQ26 模式
0 0 0 1 0 IRQ26 模式
0 0 0 1 1 SVC26 模式
1 0 0 0 0 User 模式
1 0 0 0 1 FIQ 模式
1 0 0 1 0 IRQ 模式
1 0 0 1 1 SVC 模式
1 0 1 1 1 ABT 模式
1 1 0 1 1 UND 模式
1 1 1 1 1 SYS 模式
mrs r0,cpsr
@將cpsr的值讀到r0中
bic r0,r0,#0x1f
@清除M0~M4
orr r0,r0,#0xd3
@禁止IRQ,FIQ中斷,並將處理器置於管理模式
msr cpsr,r0
@以下是點燈了,這裡應該會牽涉到硬體設定,移植的時候應該可以不要
bl coloured_LED_init
bl red_LED_on
@針對AT91RM9200進行特殊處理
#if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK)
/*
* relocate exception table
*/
ldr r0, =_start
ldr r1, =0x0
mov r2, #16
copyex:
subs r2, r2, #1
@sub帶上了s用來更改進位標誌,對於sub來說,若發生借位則C標誌置0,沒有則為1,這跟adds指令相反!要注意。
ldr r3, [r0], #4
str r3, [r1], #4
bne copyex
#endif
@針對S3C2400和S3C2410進行特殊處理
@CONFIG_S3C2400、CONFIG_S3C2410等定義在include/configs/下不同開發板的標頭檔案中
#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)
/* turn off the watchdog */
@關閉看門狗定時器的自動復位功能並遮蔽所有中斷,上電後看門狗為開,中斷為關
# if defined(CONFIG_S3C2400)
# define pWTCON 0x15300000
# define INTMSK 0x14400008 /* Interupt-Controller base addresses */
# define CLKDIVN 0x14800014 /* clock divisor register */
#else @s3c2410的配置
# define pWTCON 0x53000000
@pWTCON定義為看門狗控制暫存器的地址(s3c2410和s3c2440相同)
# define INTMSK 0x4A000008 /* Interupt-Controller base addresses */
@INTMSK定義為主中斷遮蔽暫存器的地址(s3c2410和s3c2440相同)
# define INTSUBMSK 0x4A00001C
@INTSUBMSK定義為副中斷遮蔽暫存器的地址(s3c2410和s3c2440相同)
# define CLKDIVN 0x4C000014 /* clock divisor register */
@CLKDIVN定義為時鐘分頻控制暫存器的地址(s3c2410和s3c2440相同)
# endif
@至此暫存器地址設定完畢
ldr r0, =pWTCON
mov r1, #0x0
str r1, [r0]
@對於S3C2440和S3C2410的WTCON暫存器的[0]控制允許或禁止看門狗定時器的復位輸出功能,設定為“0”禁止復位功能。
/*
* mask all IRQs by setting all bits in the INTMR - default
*/
mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0]
# if defined(CONFIG_S3C2410)
ldr r1, =0x3ff @2410好像應該為7ff才對(不理解uboot為何是這個數字)
ldr r0, =INTSUBMSK
str r1, [r0]
# endif
@對於S3C2410的INTMSK暫存器的32位和INTSUBMSK暫存器的低11位每一位對應一箇中斷,相應位置“1”為不響應相應的中斷。對於S3C2440的INTSUBMSK有15位可用,所以應該為0x7fff了。
/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
@時鐘分頻設定,FCLK為核心提供時鐘,HCLK為AHB(ARM920T,記憶體@控制器,中斷控制器,LCD控制器,DMA和主USB模組)提供時鐘,@PCLK為APB(看門狗、IIS、I2C、PWM、MMC、ADC、UART、GPIO、@RTC、SPI)提供時鐘。分頻數一般選擇1:4:8,所以HDIVN=2,PDIVN=1,@CLKDIVN=5,這裡僅僅是配置了分頻暫存器,關於MPLLCON的配置肯@定寫在lowlevel_init.S中了
@歸納出CLKDIVN的值跟分頻的關係:
@0x0 = 1:1:1 , 0x1 = 1:1:2 , 0x2 = 1:2:2 , 0x3 = 1:2:4, 0x4 = 1:4:4, 0x5 =1:4:8, 0x6 = 1:3:3,
0x7 = 1:3:6
@S3C2440的輸出時鐘計算式為:Mpll=(2*m*Fin)/(p*2^s)
S3C2410的輸出時鐘計算式為:Mpll=(m*Fin)/(p*2^s)
m=M(the value for divider M)+8;p=P(the value for divider P)+2
M,P,S的選擇根據datasheet中PLL VALUE SELECTION TABLE表格進行,我的開發板晶振為16.9344M,所以輸出頻率選為:399.65M的話M=0x6e,P=3,S=1
@s3c2440增加了攝像頭,其FCLK、HCLK、PCLK的分頻數還受到CAMDIVN[9](預設為0),CAMDIVN[8](預設為0)的影響
#endif /* CONFIG_S3C2400 || CONFIG_S3C2410 */
/*
* we do sys-critical inits only at reboot,
* not when booting from ram!
*/
@選擇是否初始化CPU
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
@執行CPU初始化,BL完成跳轉的同時會把後面緊跟的一條指令地址儲存到連線暫存器LR(R14)中。以使子程式執行完後正常返回。
#endif
@除錯階段的程式碼是直接在RAM中執行的,而最後需要把這些程式碼 @固化到Flash中,因此U-Boot需要自己從Flash轉移到
@RAM中執行,這也是重定向的目的所在。
@通過adr指令得到當前程式碼的地址資訊:如果U-boot是從RAM @開始執行,則從adr,r0,_start得到的地址資訊為
@r0=_start=_TEXT_BASE=TEXT_BASE=0x33F80000; @如果U-boot從Flash開始執行,即從處理器對應的地址執行,
@則r0=0x0000,這時將會執行copy_loop標識的那段程式碼了。
@ _TEXT_BASE 定義在board/smdk2410/config.mk中
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate: /* relocate U-Boot to RAM */
adr r0, _start /* r0 <- current position of code */
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
cmp r0, r1 /* don't reloc duringdebug */
beq stack_setup
ldr r2, _armboot_start
@_armboot_start為_start地址
ldr r3, _bss_start
@_bss_start為資料段地址
sub r2, r3, r2 /* r2 <- size ofarmboot */
add r2, r0, r2 /* r2 <- source endaddress */
copy_loop:
ldmia r0!, {r3-r10} /* copy from source address [r0] */
@從源地址[r0]讀取8個位元組到暫存器,每讀一個就更新一次r0地址
@ldmia:r0安位元組增長
stmia r1!, {r3-r10} /* copy to target address [r1] */
@LDM(STM)用於在暫存器所指的一片連續儲存器和暫存器列表的寄存@器間進行資料移動,或是進行壓棧和出棧操作。
@格式為:LDM(STM){條件}{型別}基址暫存器{!},暫存器列表{^}
@對於型別有以下幾種情況: IA
每次傳送後地址加1,用於移動數
@據塊
IB 每次傳送前地址加1,用於移動資料塊
DA 每次傳送後地址減1,用於移動資料塊
DB 每次傳送前地址減1,用於移動資料塊
FD 滿遞減堆疊,用於操作堆疊(即先移動指標再操作資料,相當於DB)
ED 空遞減堆疊,用於操作堆疊(即先操作資料再移動指標,相當於DA)
FA 滿遞增堆疊,用於操作堆疊(即先移動指標再操作資料,相當於IB)
EA 空遞增堆疊,用於操作堆疊(即先操作資料再移動指標,相當於IA)(這裡是不是應該要涉及到NAND或者NOR的讀寫?沒有看出來)
cmp r0, r2 /* until source end addreee[r2] */
ble copy_loop
#endif /* CONFIG_SKIP_RELOCATE_UBOOT */
/* Set up thestack */
@初始化堆疊
stack_setup:
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
@獲取分配區域起始指標,
sub r0, r0, #CONFIG_SYS_MALLOC_LEN /* mallocarea */
@CFG_MALLOC_LEN=128*1024+CFG_ENV_SIZE=128*[email protected]=192K
sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE /*bdinfo */
@CFG_GBL_DATA_SIZE 128---size in bytesreserved for initial data
用來儲存開發板資訊
#ifdef CONFIG_USE_IRQ
@這裡如果需要使用IRQ,
還有給IRQ保留堆疊空間,
一般不使用.
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
sub sp, r0, #12 /* leave 3 words for abort-stack */
@該部分將未初始化資料段_bss_start----_bss_end中的資料 @清零
clear_bss:
ldr r0, _bss_start /* find start of bsssegment */
ldr r1, _bss_end /* stophere */
mov r2, #0x00000000 /*clear */
clbss_l:str r2, [r0] /* clearloop... */
add r0, r0, #4
cmp r0, r1
ble clbss_l
@跳到階段二C語言中去
ldr pc, _start_armboot
_start_armboot: .word start_armboot
@start_armboot在/lib_arm/中,到這裡因該是第一階段已經完成了吧,下面就要去C語言中執行第二階段了吧
/*
*************************************************************************
*
* CPU_init_critical registers
*
* setup important registers
* setup memory timing
*
*************************************************************************
*/
@CPU初始化
@在“relocate: /* relocate U-Boot to RAM */ ”之前被呼叫
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
cpu_init_crit:
/*
* flush v4 I/D caches
*/
@初始化CACHES
mov r0, #0
mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */
mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */
/*
* disable MMU stuff and caches
*/
@關閉MMU和CACHES
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)
bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)
orr r0, r0, #0x00000002 @ set bit 2 (A) Align
orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache
mcr p15, 0, r0, c1, c0, 0
@對協處理器的操作還是看不懂,暫時先不管吧,有時間研究一下ARM技術手冊的協處理器部分。
/*
* before relocating, we have to setup RAM timing
* because memory timing is board-dependend, you will
* find a lowlevel_init.S in your board directory.
*/
@初始化RAM時鐘,因為記憶體是跟開發板密切相關的,所以這部分在/開發板目錄/lowlevel_init.S中實現
mov ip, lr
@儲存LR,以便正常返回,注意前面是通過BL跳到cpu_init_crit來的。
@(ARM9有37個暫存器,ARM7有27個)
37個暫存器=7個未分組暫存器(R0~R7)+
2×(5個分組暫存器R8~R12)+6×2(R13=SP,R14=lr
分組暫存器) + 1(R15=PC) +1(CPSR) + 5(SPSR)
用途和訪問許可權:
R0~R7:USR(使用者模式)、fiq(快速中斷模式)、irq(中斷模式)、svc(超級用法模式)、abt、und
R8~R12:R8_usr~R12_usr(usr,irq,svc,abt,und)
R8_fiq~R12_fiq(fiq)
R11=fp
R12=IP(從反彙編上看,fp和ip一般用於存放SP的值)
R13~R14:R13_usr R14_usr(每種模式都有自己的暫存器)
SP ~lr
:R13_fiq R14_fiq
R13_irq R14_irq
R13_svc R14_svc
R13_abt R14_abt
R13_und R14_und
R15(PC):都可以訪問(即PC的值為當前指令的地址值加8個位元組)
R16 :((Current Program Status Register,當前程式狀態暫存器))
SPSR_fiq,SPSR_irq,SPSR_abt,SPSR_und(USR模式沒有)
#if defined(CONFIG_AT91RM9200EK)
#else
bl lowlevel_init
@在重定向程式碼之前,必須初始化記憶體時序,因為重定向時需要將@flash中的程式碼複製到記憶體中lowlevel_init在@/board/smdk2410/lowlevel_init.S中。
#endif
mov lr, ip
mov pc, lr
@返回到主程式
#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
/*
*************************************************************************
*
* Interrupt handling
*
*************************************************************************
*/
@這段沒有看明白,不過好像跟移植關係不是很大,先放一放。
@
@ IRQ stack frame.
@
#define S_FRAME_SIZE 72
#define S_OLD_R0 68
#define S_PSR 64
#define S_PC 60
#define S_LR 56
#define S_SP 52
#define S_IP 48
#define S_FP 44
#define S_R10 40
#define S_R9 36
#define S_R8 32
#define S_R7 28
#define S_R6 24
#define S_R5 20
#define S_R4 16
#define S_R3 12
#define S_R2 8
#define S_R1 4
#define S_R0 0
#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
*/
.macro bad_save_user_regs
sub sp, sp, #S_FRAME_SIZE
stmia sp, {r0 - r12} @ Calling r0-r12
ldr r2, _armboot_start
sub r2, r2, #(CONFIG_STACKSIZE)
sub r2, r2, #(CONFIG_SYS_MALLOC_LEN)
sub r2, r2, #(CONFIG_SYS_GBL_DATA_SIZE+8) @ set base 2 words into abort stack
ldmia r2, {r2 - r3} @ get pc, cpsr
add r0, sp, #S_FRAME_SIZE @ restore sp_SVC
add r5, sp, #S_SP
mov r1, lr
stmia r5, {r0 - r3} @ save sp_SVC, lr_SVC, pc, cpsr
mov r0, sp
.endm
.macro irq_save_user_regs
sub sp, sp, #S_FRAME_SIZE
stmia sp, {r0 - r12} @ Calling r0-r12
add r7, sp, #S_PC
stmdb r7, {sp,lr}^ @ Calling SP, LR
str lr, [r7,#0] @ Save calling PC
mrs r6, spsr
str r6, [r7,#4] @ Save CPSR
str r0, [r7,#8] @ Save OLD_R0
mov r0, sp
.endm
.macro irq_restore_user_regs
ldmia sp, {r0 - lr}^ @ Calling r0 - lr
mov r0, r0
ldr lr, [sp, #S_PC] @ Get PC
add sp, sp, #S_FRAME_SIZE
subs pc, lr, #4 @ return & move spsr_svc into cpsr
.endm
.macro get_bad_stack
ldr r13, _armboot_start @ setup our mode stack
sub r13, r13, #(CONFIG_STACKSIZE)
sub r13, r13, #(CONFIG_SYS_MALLOC_LEN)
sub r13, r13, #(CONFIG_SYS_GBL_DATA_SIZE+8) @ reserved a couple spots in abortstack
str lr, [r13] @ save caller lr / spsr
mrs lr, spsr
str lr, [r13, #4]
mov r13, #MODE_SVC @ prepare SVC-Mode
@ msr spsr_c, r13
msr spsr, r13
mov lr, pc
movs pc, lr
.endm
.macro get_irq_stack @ setup IRQ stack
ldr sp, IRQ_STACK_START
.endm
.macro get_fiq_stack @ setup FIQ stack
ldr sp, FIQ_STACK_START
.endm
@可知start.S的流程為:異常向量——上電覆位後進入復位異常向量——跳到啟動程式碼處——設定處理器進入管理模式——關閉看門狗——關閉中斷——設定時鐘分頻——關閉MMU和CACHE——進入lowlever_init.S——檢查當前程式碼所處的位置,如果在FLASH中就將程
1.okhttp原始碼分析(一)——基本流程(超詳細) 2.okhttp原始碼分析(二)——RetryAndFollowUpInterceptor過濾器 3.okhttp原始碼分析(三)——CacheInterceptor過濾器 4.okhttp原始碼分析(四)——Conn 舉例 static成員 bsp 根據 執行方法 pip 狀態 font ear 原博地址:
https://blog.csdn.net/Myuhua/article/details/81385609
(一)不含靜態變量的java程序運行時內存變化過程分析
代碼:
1 p
前言
之前分析的兩篇文章
Android Adb 原始碼分析(一)
嵌入式Linux:Android root破解原理(二)
寫完之後,都沒有寫到相關的實現程式碼,這篇文章寫下ADB的通訊流程的一些細節
看這篇文章之前,請先閱讀
Linux的SOCKET
Mybatis對引數的處理是值得推敲的,不然在使用的過程中對發生的一系列錯誤直接懵逼了。
以前遇到引數繫結相關的錯誤我就是直接給加@param註解,也稀裡糊塗地解決了,但是後來遇到了一些問題推翻了我的假設:單個引數不需要使用 @param 。由此產生了一個疑問,Mybatis到底是怎
Mybatis 提供了事物的頂層介面:
public interface Transaction {
/**
* Retrieve inner database connection
* @return DataBase connection
* @throw
一級快取
其實關於 Mybatis 的一級快取是比較抽象的,並沒有什麼特別的配置,都是在程式碼中體現出來的。
當呼叫 Configuration 的 newExecutor 方法來建立 executor:
public Executor newExecutor(Transac
解析封裝
ResultMap 是和結果集相關的東西,最初在解析 XML 的時候,於 parseStatementNode 方法中,針對每一個 select 節點進行解析,轉換為 MappedStatement(類似 Spring 的 bean 配置和 BeanDefinition 的
Java資料庫連線,(Java Database Connectivity,簡稱JDBC)是Java語言中用來規範客戶端程式如何來訪問資料庫的應用程式介面,提供了諸如查詢和更新資料庫中資料的方法。
六步流程:
載入驅動(5.x驅動包不需要這步了)
建立
MyBatis 允許你在已對映語句執行過程中的某一點進行攔截呼叫。
預設情況下,可以使用外掛來攔截的方法呼叫包括:
Executor (update, query, flushStatements, commit, rollback, getTransaction, cl
Mybatis我們一般都是和Spring一起使用的,它們是怎麼融合到一起的,又各自發揮了什麼作用?
就拿這個Mapper來說,我們定義了一個介面,聲明瞭一個方法,然後對應的xml寫了這個sql語句, 它怎麼就執行成功了?這傢伙是怎麼實現的,帶著這個好奇心,我一步步跟蹤,慢慢揭開了它的
不涉及Spring完整的啟動流程,僅僅從Mybatis的視角去分析幾個關鍵的方法,找到Mybatis是如何通過這幾個擴充套件點植入進去的,反過來看Spring是如何設計,埋下這些伏筆,實現其可擴充套件性。
springContext-mybatis.xml的配置:
<!--
感覺CSDN對markdown的支援不夠友好,總是伴隨各種問題,很惱火!
xxMapper.xml的解析主要由XMLMapperBuilder類完成,parse方法來完成解析:
public void parse() {
if (!configuration.isRes
前幾篇介紹了Flume NG Source元件的基本情況,接下來看看Channel相關的元件,Channel相關元件有:
1. Channel
2. ChannelSelector
3. Interceptor / InterceptorChain
4. ChannelProcess
上一篇Flume NG原始碼分析(五)使用ThriftSource通過RPC方式收集日誌 介紹了ThriftSource利用Thrfit服務ThriftSourceProtocol來收集日誌。這篇說說flume-ng-sdk中提供給應用層序使用的RpcClient的設計和實現。繼續使用ThriftR
上一篇說了利用ExecSource從本地日誌檔案非同步的收集日誌,這篇說說採用RPC方式同步收集日誌的方式。筆者對Thrift比較熟悉,所以用ThriftSource來介紹RPC的日誌收集方式。
整體的結構圖如下:
1. ThriftSource包含了一個Thrift Server,以及一個
常見的日誌收集方式有兩種,一種是經由本地日誌檔案做媒介,非同步地傳送到遠端日誌倉庫,一種是基於RPC方式的同步日誌收集,直接傳送到遠端日誌倉庫。這篇講講Flume NG如何從本地日誌檔案中收集日誌。
ExecSource是用來執行本地shell命令,並把本地日誌檔案中的資料封裝成Event
Flume NG有4個主要的元件:
Event表示在Flume各個Agent之間傳遞的資料流
Source表示從外部源接收Event資料流,然後傳遞給Channel
Channel表示對從Source傳遞的Event資料流的臨時儲存
Sink表示從Channel中接收儲存的Event
在上一篇中講了Flume NG配置模組基本的介面的類,PropertiesConfigurationProvider提供了基於properties配置檔案的靜態配置的能力,這篇細說一下PollingPropertiesFileConfigurationProvider提供的執行時動態修改配置並生效的
日誌收集是網際網路公司的一個重要服務,Flume NG是Apache的頂級專案,是分散式日誌收集服務的一個開源實現,具有良好的擴充套件性,與其他很多開源元件可以無縫整合。搜了一圈發現介紹Flume NG的文章有不少,但是深入分析Flume NG原始碼的卻沒有。準備寫一個系列分析一下Flume NG的 相關推薦
UBOOT原始碼分析(詳細)
okhttp原始碼分析(一)——基本流程(超詳細)
(轉)java程序調用內存變化過程分析(詳細)
Android ADB 原始碼分析(三)
Mybatis 原始碼分析(2)—— 引數處理
Mybatis 原始碼分析(9)—— 事物管理
Mybatis 原始碼分析(8)—— 一二級快取
Mybatis原始碼分析(7)—— 結果集處理
Mybatis原始碼分析(6)—— 從JDBC看Mybatis的設計
Mybatis原始碼分析(5)—— 外掛的原理
Mybatis原始碼分析(4)—— Mapper的建立和獲取
Mybatis原始碼分析(3)—— 從Mybatis的視角去看Bean的初始化流程
Mybatis原始碼分析(1)—— Mapper檔案解析
Flume NG原始碼分析(七)ChannelSelector
Flume NG原始碼分析(六)應用程式使用的RpcClient設計
Flume NG原始碼分析(五)使用ThriftSource通過RPC方式收集日誌
Flume NG原始碼分析(四)使用ExecSource從本地日誌檔案中收集日誌
Flume NG原始碼分析(三)使用Event介面表示資料流
Flume NG原始碼分析(二)支援執行時動態修改配置的配置模組
Flume NG原始碼分析(一)基於靜態properties檔案的配置模組