第三章 内核源码获取与结构:从三星官方获取内核源码、内核源码目录结构解析、Git版本管理技巧

3.1 从三星官方获取内核源码

做Exynos开发,第一步就是拿到正确的内核源码。这事儿看着简单,但坑不少。我刚开始做4412项目时,就因为在第三方网站下了个"优化版"内核,结果折腾了两周才发现是被人改过的——有些驱动被删了,有些配置被改了。从那以后,我只认官方渠道。

三星官方内核源码,主要有三个获取途径:

  • 三星开源发布中心(opensource.samsung.com):这是最权威的渠道。所有Exynos芯片的内核源码,都会在这里发布。你输入芯片型号,比如Exynos4412、Exynos5422,就能找到对应的源码包。
  • 三星GitHub仓库:三星在GitHub上有官方账号,会维护一些主流芯片的内核分支。不过说实话,更新速度不如开源发布中心快。
  • 开发板厂商提供的BSP包:比如友善之臂、迅为这些厂商,他们会从三星拿到源码,然后加上自己的板级支持包。如果你用的是开发板,这个渠道其实更方便。
我的建议:优先用三星开源发布中心的源码。因为那是"原汁原味"的,没有被二次修改过。你裁剪时心里有底,知道哪些是三星官方的,哪些是厂商加的。

下载时要注意版本号。Exynos4412对应的内核版本通常是Linux 3.0.x或3.5.x,Exynos5422对应的是3.10.x或4.4.x。别下错了版本,否则后面驱动适配会出大问题。

3.2 内核源码目录结构解析

拿到源码后,第一件事就是解压看看目录结构。很多新手一上来就急着改代码,结果连arch目录和drivers目录都分不清。嗯,这里我带你走一遍。

Linux内核源码的顶层目录,大概有这些:

目录名 作用 裁剪时重点关注
arch/ 体系结构相关代码 arch/arm/ 下的 mach-exynos/ 和 plat-samsung/
drivers/ 设备驱动 这是裁剪的主战场,占内核代码的70%以上
fs/ 文件系统 不需要的文件系统类型可以砍掉
net/ 网络协议栈 根据产品需求决定保留哪些协议
kernel/ 内核核心功能 调度器、信号、定时器等,一般不动
mm/ 内存管理 除非你特别懂,否则别碰
include/ 头文件 定义了很多宏和数据结构
sound/ 音频子系统 如果产品不需要音频,可以整个目录去掉
crypto/ 加密API 嵌入式设备通常用硬件加密,这个可以精简

对于Exynos平台,最关键的目录是 arch/arm/mach-exynos/。这里面包含了芯片的板级初始化代码、时钟管理、电源管理、中断控制器等。我当年裁剪4412内核时,在这个目录里泡了整整一周。

避坑指南:我曾经犯过一个错误——为了追求极致的小内核,把arch/arm/mach-exynos/下的某些文件直接删了。结果编译出来的内核,连串口都打不开。后来才明白,这个目录里的代码是芯片的"骨架",只能裁剪配置项,不能删文件。

再看 drivers/ 目录,这里面的子目录是按设备类型分的:

  • drivers/gpio/ — GPIO驱动
  • drivers/i2c/ — I2C总线驱动
  • drivers/spi/ — SPI总线驱动
  • drivers/mmc/ — SD/MMC卡驱动
  • drivers/video/ — 显示驱动
  • drivers/usb/ — USB驱动
  • drivers/input/ — 输入设备驱动(触摸屏、按键等)
  • drivers/net/ — 网络设备驱动

裁剪时,你只需要保留产品实际用到的驱动。比如你的产品没有WiFi,那 drivers/net/wireless/ 整个目录都可以不编译。

3.3 Git版本管理技巧

做内核裁剪,没有Git寸步难行。你想想看,改了几百个配置项,结果编译不过,想回退都不知道从哪下手。所以,我强烈建议从一开始就用Git管理你的内核源码。

我的工作流是这样的:

  1. 从三星官方拉取源码后,先打一个taggit tag v3.0.15-exynos4412-origin。这样你随时可以回到最原始的版本。
  2. 创建一个裁剪分支git checkout -b custom/cutdown-v1。所有修改都在这个分支上进行。
  3. 每次修改配置后,提交一次:比如"disable WiFi driver"、"remove unused filesystem"、"enable DMA engine"。提交信息要写清楚,方便以后回溯。
  4. 编译通过后,再打一个taggit tag v3.0.15-exynos4412-cutdown-v1。这样每个可用版本都有记录。
一个小技巧:我习惯在提交信息里加上编译状态。比如"[BUILD OK] disable WiFi driver",或者"[BUILD FAIL] remove DMA engine - need to check dependency"。这样看日志就知道哪些提交是能编译通过的。

还有一个很实用的命令——git bisect。当你裁剪后发现某个功能不正常,但又不知道是哪个配置引起的,可以用它来二分查找。我曾在一次项目中,用bisect在30分钟内找到了导致USB无法识别的罪魁祸首——一个看起来人畜无害的电源管理配置项。

另外,建议用git stash来临时保存未提交的修改。比如你正在改配置,突然需要切到另一个分支看代码,直接git stash,切回来再git stash pop,非常方便。

注意:不要用git add .一股脑把所有文件都加进去。内核源码编译时会生成很多中间文件(.o、.cmd、.tmp等),这些不应该被Git跟踪。一定要写好.gitignore文件,把*.o*.cmd*.tmpvmlinuxSystem.mapmodules.order这些都忽略掉。

最后,分享一个我自己的习惯:每次裁剪前,先用git diff生成一个patch文件,保存到项目文档里。这样即使以后换了电脑、换了同事,也能知道当初做了哪些修改。说白了,做嵌入式开发,文档和代码一样重要。