以下是ARM版本Linux啟動過程的超詳細樹狀圖,涵蓋硬件上電到應用程序交互的全流程,并包含關鍵函數調用鏈及源碼位置,適用于系統開發與調試場景:
ARM Linux啟動全流程(含函數調用鏈)
ARM Linux啟動流程(函數級調用鏈)
│
├─── **1. 硬件上電與Boot ROM階段**
│ │
│ ├─── 硬件復位與初始化
│ │ ├─── CPU進入Reset異常向量(ARM異常向量表基址0x0或0xffff0000)
│ │ │ └─── 匯編代碼:arch/arm/kernel/entry-armv.S:reset_handler
│ │ │
│ │ ├─── 關閉Cache和MMU
│ │ │ ├─── 匯編指令:MCR p15,0,r0,c7,c5,0 ( invalidate icache)
│ │ │ └─── 匯編指令:MRC p15,0,r0,c1,c0,0; BIC r0,r0,#1 ( disable MMU)
│ │ │
│ │ └─── 初始化棧空間(SP指針)
│ │ └─── 匯編代碼:設置SVC模式棧,arch/arm/kernel/entry-armv.S
│ │
│ └─── Boot ROM固件(廠商固化,如ARM Trusted Firmware)
│ ├─── 加載Boot Loader到RAM
│ │ ├─── 從啟動設備(eMMC/SD卡)讀取U-Boot鏡像
│ │ └─── 復制鏡像到指定內存地址(如0x80000000)
│ │
│ └─── 跳轉執行Boot Loader
│ └─── 匯編指令:BX BootLoader入口地址
│
├─── **2. 引導加載程序階段(以U-Boot為例)**
│ │
│ ├─── Stage 1:匯編初始化(arch/arm/cpu/armv7/start.S)
│ │ ├─── 異常向量表初始化
│ │ │ └─── 定義Reset、Undefined、IRQ等異常處理入口
│ │ │
│ │ ├─── 內存控制器初始化
│ │ │ ├─── 配置DDR時序:arch/arm/cpu/armv7/mx6/sdram.c:mx6_sdram_initialize
│ │ │ └─── 初始化MMU頁表(臨時)
│ │ │
│ │ ├─── 串口初始化
│ │ │ ├─── 配置UART控制器:drivers/serial/serial.c:serial_initialize
│ │ │ └─── 設置波特率、數據位等參數
│ │ │
│ │ └─── 加載Stage 2到RAM
│ │ ├─── 從Flash/SD卡讀取U-Boot第二階段鏡像
│ │ └─── 跳轉執行:ldr pc, =stage2_entry
│ │
│ ├─── Stage 2:C代碼初始化(lib_arm/board.c:start_armboot)
│ │ ├─── 硬件設備初始化
│ │ │ ├─── 初始化NAND/SD卡:drivers/mtd/nand/nand_base.c:nand_init
│ │ │ ├─── 初始化USB:drivers/usb/usb_main.c:usb_init
│ │ │ └─── 初始化網絡:drivers/net/eth.c:eth_initialize
│ │ │
│ │ ├─── 設備樹解析
│ │ │ ├─── 讀取.dtb文件:drivers/of/fdt.c:fdt_init
│ │ │ └─── 驗證設備樹:drivers/of/fdt.c:fdt_validate
│ │ │
│ │ ├─── 加載Linux內核
│ │ │ ├─── 從存儲設備讀取內核鏡像:common/cmd_load.c:do_load
│ │ │ └─── 解壓縮內核(如zImage):lib/decompress.c:decompress
│ │ │
│ │ ├─── 傳遞啟動參數
│ │ │ ├─── 構建cmdline:board/arm/yourboard/yourboard.c:setup_args
│ │ │ └─── 設置啟動參數地址:arch/arm/lib/bootm.c:do_bootm_linux
│ │ │
│ │ └─── 跳轉啟動內核
│ │ └─── 匯編調用:arm/linux/bootm.c:bootm_linux
│ │
│ └─── 關鍵函數調用鏈
│ ├─── start_armboot()
│ │ ├─── board_init()
│ │ ├─── device_tree_init()
│ │ ├─── load_kernel_image()
│ │ └─── bootm_linux()
│
├─── **3. 內核初始化階段(kernel_init)**
│ │
│ ├─── 內核解壓縮與架構初始化(arch/arm/kernel/head.S)
│ │ ├─── 解壓縮內核鏡像(如zImage)
│ │ │ └─── 匯編解壓縮代碼:arch/arm/boot/compressed/head.S
│ │ │
│ │ ├─── ARM架構初始化
│ │ │ ├─── 配置頁表:arch/arm/mm/proc-v7.S:create_page_tables
│ │ │ ├─── 啟用MMU:arch/arm/mm/proc-v7.S:enable_mmu
│ │ │ ├─── 初始化GIC中斷控制器:drivers/interrupts/gic.c:gic_init
│ │ │ └─── 多核啟動:arch/arm/kernel/smp.c:smp_init
│ │ │
│ │ └─── 跳轉到C語言入口:start_kernel()
│ │ └─── 定義于init/main.c:start_kernel
│ │
│ ├─── 內核C語言初始化(init/main.c:start_kernel)
│ │ ├─── 調度器初始化:sched_init()
│ │ │ └─── kernel/sched/core.c:sched_init
│ │ │
│ │ ├─── 內存管理初始化:mm_init()
│ │ │ ├─── 伙伴系統初始化:mm/page_alloc.c:page_alloc_init
│ │ │ ├─── slab分配器初始化:mm/slab.c:kmem_cache_init
│ │ │ └─── 高端內存映射:mm/highmem.c:highmem_init
│ │ │
│ │ ├─── 設備模型初始化:device_tree_init()
│ │ │ ├─── 解析設備樹:drivers/of/fdt.c:of_platform_default_populate
│ │ │ ├─── 注冊平臺總線:drivers/base/platform.c:platform_bus_init
│ │ │ └─── 匹配設備與驅動:drivers/base/dd.c:driver_probe_device
│ │ │
│ │ ├─── 驅動子系統初始化:drivers_init()
│ │ │ ├─── 初始化PCI/USB總線:drivers/pci/pci.c:pci_subsystem_init
│ │ │ ├─── 注冊字符設備驅動:drivers/char/char_dev.c:register_chrdev
│ │ │ └─── 初始化塊設備:drivers/block/genhd.c:block_device_init
│ │ │
│ │ ├─── 文件系統初始化:filesystem_init()
│ │ │ ├─── 注冊ext4文件系統:fs/ext4/ext4_init
│ │ │ ├─── 掛載rootfs:fs/namespace.c:mount_root
│ │ │ │ ├─── 解析root=參數:fs/cmdline.c:parse_cmdline
│ │ │ │ └─── 調用具體文件系統mount函數
│ │ │ └─── 初始化tmpfs:fs/tmpfs/inode.c:tmpfs_init
│ │ │
│ │ ├─── 網絡子系統初始化:net_init()
│ │ │ ├─── 初始化TCP/IP協議棧:net/ipv4/af_inet.c:inet_init
│ │ │ ├─── 注冊網絡設備:drivers/net/ethernet/ethernet.c:register_netdevice
│ │ │ └─── 配置DHCP:net/ipv4/dhcpcd.c:dhcpcd_init
│ │ │
│ │ └─── 啟動init進程:kernel_thread(init_post, NULL, CLONE_FS)
│ │ └─── init_post()定義于init/main.c
│ │
│ └─── 設備驅動加載流程(以GPIO驅動為例)
│ ├─── 設備樹匹配:of_device_match_table
│ │ └─── drivers/gpio/gpiolib-of.c:of_gpiochip_add
│ │
│ ├─── 驅動注冊:platform_driver_register()
│ │ └─── drivers/base/platform.c:platform_driver_register
│ │
│ ├─── 設備探測:driver_probe_device()
│ │ └─── drivers/base/dd.c:driver_probe_device
│ │
│ └─── 硬件操作函數:gpio_request(), gpio_set_value()
│ ├─── drivers/gpio/gpiolib.c:gpio_request
│ └─── drivers/gpio/gpiolib.c:gpio_set_value
│
├─── **4. 用戶空間啟動階段(systemd流程)**
│ │
│ ├─── init進程啟動(PID=1,init/main.c:init_post)
│ │ ├─── 解析啟動參數,確定init程序(如/systemd)
│ │ ├─── 掛載系統文件系統:
│ │ │ ├─── mount -t proc proc /proc
│ │ │ ├─── mount -t sysfs sysfs /sys
│ │ │ └─── mount -t devtmpfs devtmpfs /dev
│ │ │
│ │ └─── 執行init程序:do_execve()
│ │ └─── 系統調用:kernel/sys.c:sys_execve
│ │
│ ├─── systemd主流程(src/core/main.c:main)
│ │ ├─── 解析命令行參數:parse_arguments()
│ │ ├─── 初始化日志系統:log_init()
│ │ ├─── 加載單元配置:load_unit_files()
│ │ │ ├─── 解析.target文件:src/core/unit.c:unit_load
│ │ │ └─── 構建依賴圖:src/core/dependency.c:resolve_dependencies
│ │ │
│ │ ├─── 啟動基本系統服務:
│ │ │ ├─── systemd-udevd.service:src/udev/udevd.c:main
│ │ │ ├─── systemd-journald.service:src/journal/journald.c:main
│ │ │ └─── systemd-networkd.service:src/network/networkd.c:main
│ │ │
│ │ ├─── 激活默認目標(如multi-user.target)
│ │ │ ├─── 解析.target依賴:src/core/unit.c:unit_activate
│ │ │ ├─── 并行啟動服務:src/core/job.c:job_execute
│ │ │ └─── 等待服務就緒:src/core/manager.c:manager_wait_for_dependencies
│ │ │
│ │ └─── 啟動登錄服務:
│ │ ├─── getty@.service:src/login/getty.c:main
│ │ └─── lightdm.service(圖形界面):src/lightdm/lightdm.c:main
│ │
│ └─── 函數調用鏈示例(啟動網絡服務)
│ ├─── systemd_main()
│ │ ├─── manager_load_unit()
│ │ ├─── unit_activate()
│ │ ├─── job_queue()
│ │ └─── exec_service() → 調用networkctl啟動網絡
│
└─── **5. 應用程序與系統交互(函數級)**│├─── 終端交互(Shell命令執行)│ ├─── 用戶輸入命令(如ls)│ │ └─── shell解析:bash/src/eval.c:eval_command│ ││ ├─── 執行程序:fork() + execve()│ │ ├─── fork系統調用:kernel/fork.c:do_fork│ │ └─── execve系統調用:kernel/exec.c:do_execve│ ││ └─── 程序運行:libc函數 → 系統調用│ ├─── printf() → write() → sys_write│ └─── open() → sys_open(定義于arch/arm/kernel/sys_arm.c)│├─── 設備訪問流程(以串口為例)│ ├─── 打開設備:fd = open("/dev/ttyAMA0", O_RDWR)│ │ └─── 系統調用:fs/open.c:do_sys_open│ ││ ├─── 配置參數:ioctl(fd, TCSETS, &termios)│ │ └─── 驅動處理:drivers/tty/serial/8250/8250.c:serial8250_ioctl│ ││ └─── 讀寫數據:read(fd, buf, len) / write(fd, buf, len)│ ├─── 系統調用:fs/read_write.c:vfs_read/vfs_write│ └─── 驅動處理:drivers/tty/serial/8250/8250.c:serial8250_read/serial8250_write│├─── 網絡應用交互(Socket編程)│ ├─── 創建Socket:sock = socket(AF_INET, SOCK_STREAM, 0)│ │ └─── 系統調用:net/socket.c:sys_socket│ ││ ├─── 綁定地址:bind(sock, &addr, len)│ │ └─── 系統調用:net/ipv4/af_inet.c:inet_bind│ ││ ├─── 監聽連接:listen(sock, backlog)│ │ └─── 系統調用:net/core/sock.c:sys_listen│ ││ └─── 數據收發:send(sock, data, len, 0) / recv(...)│ ├─── 系統調用:net/core/sock.c:sys_sendto/sys_recvfrom│ └─── 協議處理:net/ipv4/tcp.c:tcp_sendmsg/tcp_recvmsg│└─── 系統調用在內核中的處理(以ARM為例)├─── 用戶態陷入內核:SWI指令或SVC指令(ARMv8)│ └─── 異常向量:arch/arm/kernel/entry-armv.S:svc_entry│├─── 系統調用分發:│ ├─── 解析SWI號:arch/arm/kernel/call-sysv.S:sys_call│ └─── 查找系統調用表:arch/arm/kernel/sys_arm.c:sys_call_table│└─── 具體系統調用處理:├─── 如sys_open:fs/open.c:do_sys_open└─── 如sys_write:fs/read_write.c:sys_write
關鍵技術點與源碼映射
1. ARM啟動階段的函數調用核心
- 異常向量處理:ARMv7的Reset異常處理在
arch/arm/kernel/entry-armv.S
中,通過reset_handler
函數完成底層初始化。 - U-Boot Stage1:匯編代碼位于
arch/arm/cpu/armv7/start.S
,核心函數start_armboot
是Stage2的入口。 - 內核架構初始化:
arch/arm/kernel/head.S
中的__create_page_tables
和__enable_mmu
是MMU啟用的關鍵函數。
2. 設備驅動加載的函數鏈
- 設備樹解析:
drivers/of/fdt.c
中的of_platform_default_populate
會遍歷設備樹節點,為每個節點匹配驅動。 - 驅動注冊與探測:
platform_driver_register
注冊驅動時,會調用driver_probe_device
,該函數會觸發驅動的probe
函數(如gpiochip_probe
)。
3. systemd啟動的關鍵函數
- 單元加載:
src/core/unit.c
中的unit_load
負責解析.service
和.target
文件,構建依賴關系。 - 并行啟動:
src/core/job.c
中的job_execute
實現服務的并行啟動,通過fork()
和exec()
執行具體服務程序。
4. 系統調用在ARM上的實現
- 異常機制:ARM通過SWI(ARMv7)或SVC(ARMv8)指令從用戶態陷入內核,異常處理入口在
arch/arm/kernel/entry-armv.S
。 - 調用表映射:系統調用號通過
arch/arm/kernel/sys_arm.c
中的sys_call_table
映射到具體處理函數,如sys_open
對應do_sys_open
。
典型ARM平臺啟動差異(函數級)
平臺 | 關鍵函數差異 |
---|---|
樹莓派(RPi) | 額外固件層函數:bootcode.bin 調用start.elf 中的initialize_platform() ,再加載U-Boot。 |
ARM64(AArch64) | 啟動流程使用arch/arm64/kernel/head.S ,MMU配置函數為__enable_mmu ,支持4級頁表。 |
嵌入式設備 | 可能自定義啟動函數,如直接從NOR Flash加載內核,使用load_elf_image() 替代U-Boot的do_bootm 。 |
通過以上樹狀圖,可清晰看到從硬件上電到應用程序的每一層函數調用關系,尤其適合系統開發人員調試啟動問題、優化啟動時間或開發定制化啟動流程。如需進一步分析某模塊的函數調用細節(如GIC中斷初始化、USB驅動探測流程),可提供具體方向進行深入展開。