記錄將 Linux 內核(2.6.x 時代)移植到 S3C2440(SMDK2440 開發板)的關鍵步驟與核心代碼路徑,涵蓋配置、啟動參數解析、內存映射、控制台初始化、MTD 分區、平台驅動模型。
1. 內核配置
make menuconfig
→ System Type → S3C2440 Machines → SMDK2440
生成 .config,關鍵宏:CONFIG_ARCH_S3C2440、CONFIG_MACH_SMDK2440。
2. 機器類型識別:__lookup_machine_type
U-Boot 傳遞 machine_id(r1 寄存器),內核遍歷 __arch_info_begin~__arch_info_end 段查找匹配的 machine_desc 結構:
// arch/arm/mach-s3c2440/mach-smdk2440.c
MACHINE_START(SMDK2440, "SMDK2440")
.phys_io = S3C2410_PA_UART,
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
.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
3. setup_arch:解析 ATAGs
- 調用
__lookup_machine_type 獲取 mdesc。
parse_tags(tag_ptr) 遍歷 ATAG 列表:
| ATAG 類型 | 處理函數 | 作用 |
ATAG_MEM | parse_tag_mem32 | 填充 meminfo 結構,記錄物理內存區域 |
ATAG_CMDLINE | parse_tag_cmdline | 拷貝啟動參數到 default_command_line |
早期參數解析:__early_param("mem=", early_mem)、__early_param("initrd=", early_initrd)。
paging_init(&meminfo, mdesc) 建立頁表映射。
調用 mdesc->map_io() → smdk2440_map_io():
static void __init smdk2440_map_io(void) {
s3c24xx_init_io(smdk2440_iodesc, ARRAY_SIZE(smdk2440_iodesc)); // 靜態 IO 映射表
s3c24xx_init_clocks(16934400); // 外部晶振 16.9344 MHz
s3c24xx_init_uarts(smdk2440_uartcfgs, ARRAY_SIZE(smdk2440_uartcfgs));
}
4. parse_args:後續命令行參數處理
處理 setup_arch 未覆蓋的參數(如 ttySAC0=...),並進一步規範化已解析參數。
5. 控制台初始化:console_init
遍歷 __con_initcall_start~__con_initcall_end 區間的函數指針:
console_initcall(s3c24xx_serial_initconsole); // 宏註冊
// drivers/serial/s3c2410.c
void __init s3c24xx_serial_initconsole(void) {
register_console(&s3c24xx_serial_console); // 向內核註冊控制台設備
}
6. MTD 分區修改
預設分區定義於 arch/arm/plat-s3c24xx/common-smdk.c 的 smdk_default_nand_part 結構體,按項目需求調整起始地址、大小、名稱(Bootloader/Kernel/Rootfs/Env 等)。
7. 平台驅動模型:設備與驅動匹配
// 設備結構
struct platform_device {
const char* name;
u32 id;
struct device dev;
u32 num_resources;
struct resource* resource; // IOMEM, IRQ, DMA 等
};
// 驅動結構
struct platform_driver {
int (*probe)(struct platform_device*);
int (*remove)(struct platform_device*);
// ... pm callbacks
struct device_driver driver; // .name = "xxx" 用於匹配
};
內核掃描註冊的 platform_device,與 platform_driver 的 name 字符串匹配,成功則調用 probe。設備資源(resource)通常來自板級文件(如 mach-smdk2440.c)靜態定義或 Device Tree(新內核)。
關鍵文件路徑速查
arch/arm/mach-s3c2440/mach-smdk2440.c:機器描述、IO 映射、時鐘、串口
arch/arm/plat-s3c24xx/common-smdk.c:預設 NAND 分區
drivers/serial/s3c2410.c:串口驅動、控制台註冊
arch/arm/kernel/setup.c:setup_arch、parse_tags、paging_init
註:現代內核(4.x+)已全面轉向 Device Tree,ATAGs/板級文件機制逐漸淘汰,但理解舊流程有助於閱讀歷史代碼與舊項目維護。
- 上一篇文章: Cocos2d-x 開發工具分享:AnimatePacker 動畫打包工具原始碼(Qt 4.8 版)
- 下一篇文章: C++ 線程池完整實現:基於信號量與臨界區的任務隊列設計與使用範例
Copyright ©
程式碼之家 All Rights Reserved