新書推薦:
《
艾尔米塔什国家博物馆 少年游学 人一生一定要看的博物馆
》
售價:HK$
38.1
《
世界四大博物馆4册套装 卢浮宫大英大都会艾尔米塔什博物馆 青少年游学艺术参观科普书
》
售價:HK$
152.3
《
艺术家之路 塑造插画风格
》
售價:HK$
166.8
《
古乐钩沉(中国音乐学院60周年校庆中青年学者文集)
》
售價:HK$
132.2
《
我和抑郁症的3000天
》
售價:HK$
66.1
《
与骸骨交谈:我希望每一个真相都被发现
》
售價:HK$
76.2
《
人体使用手册3:自愈力的逻辑(全面解读身体面对疾病时的反应逻辑,学习更多有效的系列家庭按摩)
》
售價:HK$
61.6
《
素描简史:从文艺复兴到现代艺术
》
售價:HK$
436.8
|
編輯推薦: |
多年来,Linux一直是嵌入式计算的中流砥柱。然而,涵盖该领域所有主题的书籍非常少,本书旨在填补这一空白。“嵌入式Linux”一词的定义并不明确,它可以应用于从恒温器到Wi-Fi路由器,再到工业控制单元的各种设备内的操作系统。但是,它们都建立在相同的基本开源软件之上。这些正是我们在本书中要描述的技术,本书的写作基于我们作为工程师的经验和为培训课程开发的资料。
|
內容簡介: |
《精通嵌入式Linux编程》详细阐述了与嵌入式Linux开发相关的基本解决方案,主要包括初识嵌入式Linux开发、关于工具链、引导加载程序详解、配置和构建内核、构建根文件系统、选择构建系统、使用Yocto进行开发、Yocto技术内幕、创建存储策略、现场更新软件、连接设备驱动程序、使用分线板进行原型设计、init程序、使用BusyBox runit启动、管理电源、打包Python程序、了解进程和线程、管理内存、使用GDB进行调试、性能分析和跟踪、实时编程等内容。此外,本书还提供了相应的示例、代码,以帮助读者进一步理解相关方案的实现过程。 本书适合作为高等院校计算机及相关专业的教材和教学参考书,也可作为相关开发人员的自学用书和参考手册。
|
關於作者: |
弗兰克·瓦斯奎兹是一位专注于消费电子产品的独立软件顾问。他在设计和构建嵌入式Linux系统方面拥有十多年的经验。在此期间,他完成了许多设备的开发,包括机架式DSP音频服务器、潜水员手持式声纳摄像机和消费者物联网热点。在成为嵌入式Linux开发工程师之前,Frank曾经是IBM的数据库内核开发人员,他在该公司主要从事DB2方面的工作。他目前住在硅谷。
|
目錄:
|
第1篇 嵌入式Linux的要素
第1章 初识嵌入式Linux开发 3
1.1 选择Linux的原因 4
1.2 不选择Linux的原因 5
1.3 找到合适的玩家 5
1.4 穿越项目生命周期 7
1.4.1 篇章内容概述 7
1.4.2 嵌入式Linux的4个基本要素 7
1.5 开源的意义 8
1.5.1 开源和免费有区别 8
1.5.2 开源许可机制 8
1.6 为嵌入式Linux开发选择硬件 10
1.7 获取本书所需硬件 11
1.7.1 Raspberry Pi 4 11
1.7.2 BeagleBone Black 12
1.7.3 QEMU 13
1.8 配置开发环境 15
1.9 小结 15
第2章 关于工具链 17
2.1 技术要求 17
2.2 工具链简介 18
2.2.1 工具链的类型 20
2.2.2 CPU架构 21
2.2.3 选择C库 22
2.3 寻找工具链 24
2.4 使用crosstool-NG构建工具链 26
2.4.1 安装crosstool-NG 26
2.4.2 为BeagleBone Black构建工具链 27
2.4.3 为QEMU构建工具链 28
2.5 工具链剖析 29
2.5.1 了解你的交叉编译器 30
2.5.2 sysroot、库和头文件 31
2.5.3 工具链中的其他工具 32
2.5.4 查看C库的组件 33
2.6 与库链接—静态和动态链接 34
2.6.1 静态库 34
2.6.2 共享库 35
2.6.3 了解共享库版本号 36
2.7 交叉编译的技巧 37
2.7.1 相对简单的makefile 38
2.7.2 Autotools 38
2.7.3 编译示例—SQLite 40
2.7.4 包配置 42
2.7.5 交叉编译带来的问题 43
2.7.6 CMake 44
2.8 小结 46
2.9 延伸阅读 46
第3章 引导加载程序详解 47
3.1 技术要求 47
3.2 引导加载程序的作用 48
3.3 引导顺序 48
3.3.1 阶段1—ROM代码 49
3.3.2 阶段2—SPL 51
3.3.3 阶段3—TPL 52
3.4 从引导加载程序转移到内核中 53
3.5 设备树简介 54
3.5.1 有关设备树的基础知识 54
3.5.2 reg属性 55
3.5.3 标签和中断 56
3.5.4 设备树包含文件 57
3.5.5 编译设备树 59
3.6 U-Boot 60
3.6.1 构建U-Boot 60
3.6.2 安装U-Boot 62
3.6.3 使用U-Boot 64
3.6.4 环境变量 65
3.6.5 引导镜像格式 65
3.6.6 加载镜像 67
3.6.7 引导Linux 69
3.6.8 使用U-Boot脚本自动化引导过程 69
3.6.9 将U-Boot移植到新板上 69
3.6.10 与特定开发板相关的文件 71
3.6.11 配置头文件 73
3.6.12 构建和测试 74
3.6.13 Falcon模式 75
3.7 小结 76
第4章 配置和构建内核 77
4.1 技术要求 77
4.2 内核的作用 78
4.3 选择内核 80
4.3.1 内核开发周期 80
4.3.2 稳定和长期支持版本 81
4.3.3 供应商支持 82
4.3.4 许可机制 82
4.4 构建内核 83
4.4.1 获取源 83
4.4.2 了解内核配置—Kconfig 84
4.4.3 使用LOCALVERSION识别内核 88
4.4.4 使用内核模块的时机 89
4.5 编译—Kbuild 90
4.5.1 找出要构建的内核目标 90
4.5.2 构建工件 91
4.5.3 编译设备树 93
4.5.4 编译模块 93
4.5.5 清理内核源 94
4.5.6 为Raspberry Pi 4构建64位内核 94
4.5.7 为BeagleBone Black构建内核 96
4.5.8 为QEMU构建内核 97
4.6 引导内核 97
4.6.1 引导Raspberry Pi 4 97
4.6.2 引导BeagleBone Black 98
4.6.3 引导QEMU 99
4.6.4 内核恐慌 100
4.6.5 早期用户空间 100
4.6.6 内核消息 101
4.6.7 内核命令行 101
4.7 将Linux移植到新板上 102
4.7.1 新的设备树 103
4.7.2 设置开发板的兼容属性 104
4.8 小结 106
4.9 延伸阅读 107
第5章 构建根文件系统 109
5.1 技术要求 110
5.2 根文件系统中应该包含的东西 110
5.3 目录布局 111
5.3.1 暂存目录 112
5.3.2 POSIX文件访问权限 113
5.3.3 暂存目录中的文件所有权权限 115
5.4 根文件系统的程序 115
5.4.1 init程序 115
5.4.2 shell 115
5.4.3 实用程序 116
5.4.4 关于BusyBox 116
5.4.5 构建BusyBox 117
5.4.6 ToyBox—BusyBox的替代品 118
5.5 根文件系统的库 119
5.5.1 选择需要的库 119
5.5.2 通过剥离减小尺寸 120
5.6 设备节点 121
5.7 proc和sysfs文件系统 122
5.7.1 proc和sysfs文件系统的功能 123
5.7.2 挂载文件系统 123
5.7.3 内核模块 124
5.8 将根文件系统传输到目标 124
5.9 创建引导initramfs 125
5.9.1 独立的initramfs 126
5.9.2 引导initramfs 126
5.9.3 使用QEMU引导 126
5.9.4 引导BeagleBone Black 127
5.9.5 挂载proc 127
5.9.6 将initramfs构建到内核镜像中 128
5.9.7 使用设备表构建initramfs 129
5.9.8 旧的initrd格式 130
5.10 init程序 130
5.10.1 BusyBox的init程序 131
5.10.2 启动守护进程 132
5.11 配置用户账户 132
5.11.1 配置账户 132
5.11.2 将用户账户添加到根文件系统中 134
5.12 管理设备节点的更好方法 134
5.12.1 使用devtmpfs的示例 135
5.12.2 使用mdev的示例 135
5.12.3 静态设备节点的优劣 136
5.13 配置网络 136
5.13.1 BusyBox中的网络配置 136
5.13.2 glibc的网络组件 137
5.14 使用设备表创建文件系统镜像 138
5.14.1 安装和使用genext2fs工具 138
5.14.2 引导BeagleBone Black 139
5.15 使用NFS挂载根文件系统 140
5.15.1 使用QEMU进行测试 141
5.15.2 使用BeagleBone Black进行测试 142
5.15.3 文件权限问题 142
5.16 使用TFTP加载内核 143
5.17 小结 144
5.18 延伸阅读 144
第6章 选择构建系统 145
6.1 技术要求 145
6.2 比较构建系统 146
6.3 分发二进制文件 148
6.4 Buildroot简介 148
6.4.1 Buildroot的背景知识 149
6.4.2 稳定版本和长期支持版本 149
6.4.3 安装Buildroot 149
6.4.4 配置Buildroot 150
6.4.5 运行 151
6.4.6 以真实硬件为目标 153
6.4.7 创建自定义BSP 154
6.4.8 U-Boot配置 154
6.4.9 Linux配置 155
6.4.10 构建系统镜像 157
6.4.11 添加自己的代码 159
6.4.12 覆盖层 160
6.4.13 添加包 160
6.4.14 许可合规性 162
6.5 Yocto Project简介 162
6.5.1 Yocto Project的背景知识 163
6.5.2 稳定版本和支持 164
6.5.3 安装Yocto Project 165
6.5.4 配置 165
6.5.5 构建 166
6.5.6 运行QEMU目标 167
6.5.7 元层 167
6.5.8 BitBake和配方 170
6.5.9 通过local.conf自定义镜像 172
6.5.10 编写镜像配方 173
6.5.11 创建SDK 174
6.5.12 许可证审核 176
6.6 小结 176
6.7 延伸阅读 177
第7章 使用Yocto进行开发 179
7.1 技术要求 179
7.2 在现有BSP之上构建镜像 180
7.2.1 构建现有的BSP 180
7.2.2 控制Wi-Fi 186
7.2.3 控制蓝牙 189
7.2.4 添加自定义层 192
7.3 使用devtool捕获更改 195
7.3.1 开发工作流程 195
7.3.2 创建新配方 197
7.3.3 修改由配方构建的源 198
7.3.4 将配方升级到较新版本 200
7.4 构建自己的发行版 203
7.4.1 推出发行版的合适时机 203
7.4.2 创建一个新的发行层 203
7.4.3 配置发行版 204
7.4.4 向发行版添加更多配方 205
7.4.5 运行时包管理 205
7.5 配置远程包服务器 207
7.5.1 配置包服务器 207
7.5.2 配置目标客户端 208
7.6 小结 209
7.7 延伸阅读 209
第8章 Yocto技术内幕 211
8.1 技术要求 211
8.2 Yocto架构和工作流程分解 212
8.2.1 元数据 214
8.2.2 构建任务 215
8.2.3 镜像生成 217
8.3 将元数据分层 218
8.4 构建失败故障排除 220
8.4.1 隔离错误 220
8.4.2 检查和转储环境值 221
8.4.3 读取任务日志 222
8.4.4 添加更多日志记录 222
8.4.5 从devshell中运行命令 223
8.4.6 查看包的依赖关系 224
8.5 了解BitBake语法和语义 225
8.5.1 任务 225
8.5.2 依赖项 226
8.5.3 任务间依赖项 226
8.5.4 构建时依赖项 226
8.5.5 运行时依赖项 227
8.5.6 变量 228
8.5.7 赋值和扩展 228
8.5.8 附加和前置 229
8.5.9 覆盖 229
8.5.10 内联Python 230
8.5.11 函数 231
8.5.12 shell 231
8.5.13 Python 231
8.5.14 纯Python函数 232
8.5.15 BitBake风格的Python函数 232
8.5.16 匿名Python函数 233
8.5.17 RDEPENDS 234
8.6 小结 235
8.7 延伸阅读 235
第2篇 系统架构和设计决策
第9章 创建存储策略 239
9.1 技术要求 239
9.2 存储选项 240
9.2.1 NOR闪存 241
9.2.2 NAND闪存 241
9.2.3 托管闪存 243
9.2.4 多媒体卡和安全数字卡 244
9.2.5 eMMC 245
9.2.6 其他类型的托管闪存 245
9.3 从引导加载程序中访问闪存 245
9.3.1 U-Boot和NOR闪存 246
9.3.2 U-Boot和NAND闪存 246
9.3.3 U-Boot和MMC、SD和eMMC 246
9.4 从Linux中访问闪存 247
9.4.1 内存技术设备子系统 247
9.4.2 MTD分区 248
9.4.3 MTD设备驱动程序 251
9.4.4 MTD字符设备 251
9.4.5 MTD块设备mtdblock 252
9.4.6 将内核错误记录到MTD上 253
9.4.7 模拟NAND存储器 253
9.4.8 MMC块驱动程序 253
9.5 闪存文件系统 254
9.5.1 闪存转换层的特点 254
9.5.2 闪存转换层的部署方式 255
9.6 NOR和NAND闪存的文件系统 255
9.6.1 JFFS2 256
9.6.2 摘要节点 257
9.6.3 干净标记 257
9.6.4 创建JFFS2文件系统 257
9.6.5 YAFFS2 258
9.6.6 创建YAFFS2文件系统 259
9.6.7 UBI和UBIFS 260
9.6.8 UBI 260
9.6.9 UBIFS 263
9.7 托管闪存的文件系统 264
9.7.1 Flashbench 265
9.7.2 丢弃和修剪 266
9.7.3 Ext4 267
9.7.4 F2FS 268
9.7.5 FAT16/32 268
9.8 只读压缩文件系统 269
9.8.1 SquashFS 269
9.8.2 在NAND闪存上使用SquashFS 269
9.9 临时文件系统 270
9.10 将根文件系统设为只读 271
9.11 文件系统选择 272
9.12 小结 273
9.13 延伸阅读 273
第10章 现场更新软件 275
10.1 技术要求 275
10.2 启动更新的方法 276
10.3 更新的内容 276
10.3.1 引导加载程序 277
10.3.2 内核 277
10.3.3 根文件系统 278
10.3.4 系统应用程序 278
10.3.5 与特定设备相关的数据 278
10.3.6 需要更新的组件 279
10.4 有关软件更新的基础知识 279
10.4.1 使更新稳定可靠 279
10.4.2 使更新不受故障影响 280
10.4.3 确保更新安全 282
10.5 更新机制的类型 283
10.5.1 对称镜像更新 283
10.5.2 非对称镜像更新 285
10.5.3 原子文件更新 286
10.6 OTA更新 288
10.7 使用Mender进行本地更新 288
10.7.1 构建Mender客户端 289
10.7.2 安装更新 291
10.8 使用Mender进行OTA更新 294
10.8.1 设置更新服务器 294
10.8.2 上传工件 297
10.8.3 部署更新 299
10.9 使用balena进行本地更新 301
10.9.1 创建一个账户 302
10.9.2 创建应用程序 303
10.9.3 添加设备 304
10.9.4 启用本地模式 306
10.9.5 安装CLI 307
10.9.6 推送一个项目 309
10.9.7 修改和更新项目 310
10.10 小结 311
第11章 连接设备驱动程序 313
11.1 技术要求 313
11.2 设备驱动程序的作用 314
11.3 字符设备 315
11.4 块设备 317
11.5 网络设备 318
11.6 在运行时查找驱动程序 320
11.6.1 从sysfs中获取信息 322
11.6.2 设备 322
11.6.3 驱动程序 323
11.6.4 块驱动程序 324
11.7 寻找合适的设备驱动程序 325
11.8 用户空间中的设备驱动程序 325
11.8.1 通用输入/输出接口 326
11.8.2 处理来自GPIO的中断 327
11.8.3 LED 329
11.8.4 I2C 330
11.8.5 SPI 332
11.9 编写内核设备驱动程序 333
11.9.1 设计字符设备驱动程序接口 333
11.9.2 对于设备驱动程序的剖析 335
11.9.3 编译内核模块 338
11.9.4 加载内核模块 339
11.10 发现硬件配置 339
11.10.1 设备树 340
11.10.2 平台数据 340
11.10.3 将硬件与设备驱动程序链接在一起 341
11.11 小结 343
11.12 延伸阅读 344
第12章 使用分线板进行原型设计 345
12.1 技术要求 345
12.2 将原理图映射到设备树的源中 346
12.2.1 阅读原理图和数据表 347
12.2.2 在BeagleBone Black上安装Debian 352
12.2.3 启用spidev 353
12.2.4 自定义设备树 359
12.3 使用分线板进行原型设计 367
12.3.1 闭合SPI跳线 368
12.3.2 安装GNSS天线 370
12.3.3 附加SPI接头 370
12.3.4 连接SPI跳线 371
12.4 使用逻辑分析仪探测SPI信号 375
12.4.1 连接逻辑分析仪 376
12.4.2 配置Logic 8 377
12.5 通过SPI接收NMEA消息 383
12.6 小结 387
12.7 延伸阅读 387
第13章 init程序 389
13.1 技术要求 389
13.2 内核引导后的操作 390
13.3 init程序简介 391
13.4 BusyBox init 392
13.4.1 BusyBox init解析 392
13.4.2 Buildroot init脚本 393
13.5 System V init 393
13.5.1 inittab 395
13.5.2 init.d脚本 397
13.5.3 添加新的守护进程 398
13.5.4 启动和停止服务 399
13.6 systemd 400
13.6.1 使用Yocto Project和Buildroot构建systemd 400
13.6.2 关于目标、服务和单元 401
13.6.3 单元 401
13.6.4 服务 402
13.6.5 目标 402
13.6.6 systemd引导系统的方式 403
13.6.7 添加自己的服务 404
13.6.8 添加看门狗 405
13.6.9 对嵌入式Linux的影响 406
13.7 小结 406
13.8 延伸阅读 407
第14章 使用BusyBox runit启动 409
14.1 技术要求 409
14.2 获取BusyBox runit 410
14.3 创建服务目录和文件 416
14.3.1 服务目录布局 417
14.3.2 服务配置 418
14.4 服务监督 425
14.4.1 runsv脚本运行的服务 425
14.4.2 控制服务 427
14.5 服务依赖 429
14.5.1 启动依赖项 429
14.5.2 自定义启动依赖项 431
14.5.3 简单总结 431
14.6 专用服务日志记录 432
14.6.1 专用日志记录器的工作方式 432
14.6.2 向服务中添加专用日志记录 433
14.6.3 日志轮转 434
14.7 发出服务信号 435
14.8 小结 436
14.9 延伸阅读 437
第15章 管理电源 439
15.1 技术要求 439
15.2 测量用电量 440
15.3 调整时钟频率 443
15.3.1 CPUFreq驱动程序 444
15.3.2 使用CPUFreq 446
15.4 选择最佳空闲状态 448
15.4.1 CPUIdle驱动程序 449
15.4.2 无滴答操作 452
15.5 关闭外围设备 452
15.6 使系统进入休眠状态 454
15.6.1 电源状态 454
15.6.2 唤醒事件 455
15.6.3 从实时时钟定时唤醒 456
15.7 小结 458
15.8 延伸阅读 458
第3篇 编写嵌入式应用程序
第16章 打包Python程序 461
16.1 技术要求 461
16.1.1 安装venv 462
16.1.2 安装Docker 462
16.2 追溯Python打包的起源 463
16.2.1 distutils 463
16.2.2 setuptools 463
16.2.3 setup.py 464
16.3 使用pip安装Python包 466
16.3.1 pip和pip3 466
16.3.2 requirements.txt 469
16.4 使用venv管理Python虚拟环境 471
16.4.1 venv 472
16.4.2 创建虚拟环境 473
16.4.3 激活和验证虚拟环境 473
16.4.4 在虚拟环境中安装测试库 474
16.5 使用conda安装预编译的二进制文件 475
16.5.1 环境管理 475
16.5.2 验证根环境 476
16.5.3 创建conda环境 477
16.5.4 包管理 478
16.5.5 导出虚拟环境 479
16.6 使用Docker部署Python应用程序 480
16.6.1 Dockerfile解析 481
16.6.2 构建Docker镜像 483
16.6.3 运行Docker镜像 484
16.6.4 提取Docker镜像 485
16.6.5 发布Docker镜像 485
16.6.6 删除Docker容器 486
16.6.7 删除Docker镜像 487
16.6.8 Docker应用总结 487
16.7 小结 488
16.8 延伸阅读 488
第17章 了解进程和线程 489
17.1 技术要求 489
17.2 进程和线程的抉择 490
17.3 进程 492
17.3.1 创建新进程 492
17.3.2 终止进程 493
17.3.3 运行不同的程序 494
17.3.4 守护进程 497
17.3.5 进程间通信 497
17.3.6 基于消息的IPC 498
17.3.7 UNIX套接字 498
17.3.8 FIFO和命名管道 499
17.3.9 POSIX消息队列 499
17.3.10 基于消息的IPC总结 499
17.3.11 基于共享内存的IPC 500
17.3.12 POSIX共享内存 500
17.4 线程 503
17.4.1 创建一个新线程 503
17.4.2 终止线程 505
17.4.3 用线程编译程序 505
17.4.4 线程间通信 505
17.4.5 互斥锁 506
17.4.6 不断变化的条件 506
17.4.7 进程和线程应用规则 508
17.5 ZeroMQ 509
17.5.1 获取pyzmq 510
17.5.2 进程之间的消息传递 510
17.5.3 进程内的消息传递 512
17.6 调度 514
17.6.1 公平与确定性 514
17.6.2 分时策略 515
17.6.3 nice值 516
17.6.4 实时策略 516
17.6.5 选择策略 517
17.6.6 选择实时优先级 518
17.7 小结 518
17.8 延伸阅读 518
第18章 管理内存 521
18.1 技术要求 521
18.2 虚拟内存基础知识 522
18.3 内核空间内存布局 523
18.3.1 内核日志消息分析 523
18.3.2 内核的内存使用情况 524
18.4 用户空间内存布局 526
18.5 进程内存映射 528
18.6 交换 529
18.6.1 交换的利弊 529
18.6.2 交换到压缩内存 530
18.7 使用mmap映射内存 530
18.7.1 使用mmap分配私有内存 531
18.7.2 使用mmap共享内存 531
18.7.3 使用mmap访问设备内存 532
18.8 应用程序的内存使用情况 532
18.9 每个进程的内存使用情况 533
18.9.1 使用top和ps 534
18.9.2 使用smem 534
18.9.3 其他工具 536
18.10 识别内存泄漏 537
18.10.1 mtrace 537
18.10.2 Valgrind 538
18.11 内存不足 540
18.12 小结 541
18.13 延伸阅读 542
第4篇 调试和优化性能
第19章 使用GDB进行调试 545
19.1 技术要求 545
19.2 GNU调试器 546
19.3 准备调试 547
19.4 调试应用程序 547
19.4.1 使用gdbserver进行远程调试 548
19.4.2 设置Yocto Project以进行远程调试 549
19.4.3 为远程调试设置Buildroot 550
19.5 启动调试 550
19.5.1 连接GDB和gdbserver 550
19.5.2 设置sysroot 551
19.5.3 GDB命令文件 553
19.5.4 GDB命令概述 554
19.5.5 运行到断点 555
19.5.6 用Python扩展GDB 556
19.5.7 构建包含Python支持的GDB 556
19.5.8 使用GDB远程调试bsdiff 559
19.6 本机调试 560
19.6.1 Yocto Project 560
19.6.2 Buildroot 561
19.7 即时调试 561
19.8 调试分叉和线程 562
19.9 核心文件 562
19.9.1 观察核心文件 563
19.9.2 使用GDB查看核心文件 564
19.10 GDB用户界面 565
19.10.1 终端用户界面 565
19.10.2 数据显示调试器 566
19.11 Visual Studio Code 567
19.11.1 安装Visual Studio Code 567
19.11.2 安装工具链 567
19.11.3 安装CMake 569
19.11.4 创建一个Visual Studio Code项目 569
19.11.5 安装Visual Studio Code扩展 569
19.11.6 配置CMake 570
19.11.7 配置项目设置 571
19.11.8 配置远程调试的启动设置 573
19.12 调试内核代码 574
19.12.1 使用kgdb调试内核代码 575
19.12.2 调试会话示例 576
19.12.3 调试早期代码 577
19.12.4 调试模块 578
19.12.5 使用kdb调试内核代码 579
19.12.6 查看内核Oops消息 580
19.12.7 保存Oops消息 583
19.13 小结 584
19.14 延伸阅读 585
第20章 性能分析和跟踪 587
20.1 技术要求 588
20.2 观察者效应 588
20.2.1 关于观察者效应 588
20.2.2 符号表和编译标志 589
20.3 开始性能分析 589
20.4 使用top进行性能分析 590
20.5 穷人的性能分析器 591
20.6 perf简介 592
20.6.1 为perf配置内核 593
20.6.2 使用Yocto Project构建perf 593
20.6.3 使用Buildroot构建perf 594
20.6.4 使用perf进行性能分析 594
20.6.5 调用图 596
20.6.6 perf annotate 597
20.7 跟踪事件 598
20.8 Ftrace简介 599
20.8.1 准备使用Ftrace 599
20.8.2 使用Ftrace 600
20.8.3 动态Ftrace和跟踪过滤器 602
20.8.4 跟踪事件 603
20.9 使用LTTng 604
20.9.1 LTTng和Yocto Project 605
20.9.2 LTTng和Buildroot 605
20.9.3 使用LTTng进行内核跟踪 606
20.10 使用BPF 608
20.10.1 为BPF配置内核 608
20.10.2 使用Buildroot构建BCC工具包 611
20.10.3 使用BPF跟踪工具 612
20.11 使用Valgrind 615
20.11.1 Callgrind 615
20.11.2 Helgrind 616
20.12 使用strace 616
20.13 小结 619
20.14 延伸阅读 619
第21章 实时编程 621
21.1 技术要求 621
21.2 关于实时 622
21.3 识别非确定性的来源 624
21.4 了解调度延迟 625
21.5 内核抢占 626
21.5.1 实时Linux内核(PREEMPT_RT) 627
21.5.2 线程化中断处理程序 628
21.6 可抢占内核锁 630
21.6.1 获取PREEMPT_RT补丁 631
21.6.2 Yocto Project和PREEMPT_RT 632
21.7 高分辨率定时器 632
21.8 避免页面错误 633
21.9 中断屏蔽 634
21.10 测量调度延迟 634
21.10.1 cyclictest 635
21.10.2 使用Ftrace 638
21.10.3 结合cyclictest和Ftrace 639
21.11 小结 640
21.12 延伸阅读 641
|
內容試閱:
|
多年来,Linux一直是嵌入式计算的中流砥柱。然而,涵盖该领域所有主题的书籍非常少,本书旨在填补这一空白。“嵌入式Linux”一词的定义并不明确,它可以应用于从恒温器到Wi-Fi路由器,再到工业控制单元的各种设备内的操作系统。但是,它们都建立在相同的基本开源软件之上。这些正是我们在本书中要描述的技术,本书的写作基于我们作为工程师的经验和为培训课程开发的资料。技术不会停滞不前。基于嵌入式计算的行业与主流计算一样容易受到摩尔定律的影响。这种指数级的增长意味着自本书第一版出版以来发生了惊人的大量变化。你现在正在阅读的第三版经过全面修订,使用最新版本的主要开源组件,包括Linux 5.4、Yocto Project 3.1 Dunfell和Buildroot 2020.02 LTS。除了Autotools,本书还包含CMake,这是一种新构建系统,近年来得到了越来越多的采用。本书大致按照你在实际项目中遇到的顺序来涵盖这些主题。第1篇包括第1~8章,涉及项目的早期阶段。本篇涵盖选择工具链、引导加载程序和内核等基础知识。我们以Buildroot和Yocto项目为例介绍嵌入式构建系统的概念。本篇以对Yocto Project的新深入研究结束。第2篇包括第9~15章,着眼于在进行开发之前需要做出的各种设计决策。本篇涵盖文件系统、软件更新、设备驱动程序、init程序和电源管理等主题。第12章演示使用分线板进行快速原型设计的各种技术,包括如何使用逻辑分析仪读取原理图、焊接接头和排除信号故障等。第14章深入探讨Buildroot,你将学习如何使用BusyBox runit将系统软件划分为单独的服务。第3篇包括第16~18章,将为你的项目实施阶段提供帮助。我们从Python打包和依赖管理开始,随着机器学习应用程序风靡全球,这个话题变得越来越重要。然后,我们讨论各种形式的进程间通信和多线程编程。本篇最后还仔细探讨Linux如何管理内存,并演示如何使用各种可用工具来测量内存使用情况和检测内存泄漏。第4篇包括第19~21章,向你展示如何有效地利用Linux提供的许多调试和分析工具来检测问题和识别性能瓶颈。第19章介绍如何配置Visual Studio Code以使用GDB进行远程调试。第20章介绍BPF,这是一种在Linux内核中实现高级编程跟踪的新技术。最后一章则阐释如何在实时应用程序中使用Linux。本书的每一章都介绍嵌入式Linux的一个主要领域。它描述知识背景,以便你可以了解一般原则,它还包括详细的有效示例来说明这些领域中的操作。你可以把它当作一本理论书籍,也可以将它作为一本实战操作指南。如果你能二者兼得,那么效果当然最好:你可以先熟悉理论,然后在现实生活中尝试。本书读者本书是为对嵌入式计算和Linux感兴趣的开发人员编写的。在编写本书时,我们假设你对Linux命令行有基本的了解;在编程示例中,我们假设你对C和Python语言的知识有一定的了解。其中还有几章侧重于嵌入式目标板的硬件,因此对于本书读者来说,熟悉硬件和硬件接口将是一个明显的优势。内容介绍本书分为4篇共21章,具体介绍如下。第1篇:嵌入式Linux的要素,包括第1~8章。第1章“初识嵌入式Linux开发”,详细阐释嵌入式Linux生态系统,介绍硬件选择和开发环境配置等准备工作。第2章“关于工具链”,描述工具链的组件,演示如何为目标开发板的交叉编译代码创建工具链。本章还详细介绍从何处获取工具链,并提供有关如何从源代码中构建工具链的详细信息。第3章“引导加载程序详解”,阐释引导加载程序在将Linux内核加载到内存这一过程中的作用,并以U-Boot为例演示其操作。本章还介绍设备树,它是一种对几乎所有嵌入式Linux系统中的硬件细节进行编码的机制。第4章“配置和构建内核”,介绍如何为嵌入式系统选择Linux内核并为设备内的硬件配置它。本章还介绍如何将Linux移植到新的硬件上。第5章“构建根文件系统”,通过有关如何配置根文件系统的分步指南,详细介绍嵌入式Linux实现的用户空间部分背后的思想。第6章“选择构建系统”,涵盖两个常用的嵌入式Linux构建系统Buildroot和Yocto Project,它们可以自动执行此前4章中描述的步骤。第7章“使用Yocto进行开发”,演示如何在现有板级支持包(BSP)层之上构建系统镜像,如何使用Yocto的可扩展SDK开发板载软件包,如何推出你自己的嵌入式Linux发行版,以及如何进行运行时包管理和配置远程包服务器等。第8章“Yocto技术内幕”,介绍Yocto的构建工作流程和架构,包括对Yocto独特的多层方法的解释。本章还通过实际配方文件中的示例详细介绍BitBake语法和语义方面的基础知识。第2篇:系统架构和设计决策,包括第9~15章。第9章“创建存储策略”,讨论管理闪存带来的挑战,包括原始闪存芯片和嵌入式MMC(eMMC)封装。本章还描述适用于各种技术的文件系统。第10章“现场更新软件”,介绍在设备部署后更新软件的各种方法,包括完全托管的无线(OTA)更新。本章讨论的关键主题是可靠性和安全性。第11章“连接设备驱动程序”,描述内核设备驱动程序如何通过实现一个简单的驱动程序与硬件进行交互。本章还阐释从用户空间调用设备驱动程序的各种方法。第12章“使用分线板进行原型设计”,演示如何使用BeagleBone Black开发板的预构建Debian镜像和外围分线板快速构建硬件和软件原型。你将了解如何阅读数据表、连接电路板、多路复用设备树绑定以及分析SPI信号。第13章“init程序”,解释第一个用户空间程序init,讨论如何通过它启动系统的其余部分。本章描述init程序的3个版本(每个版本都适用于不同的嵌入式系统组):从简单的BusyBox init到System V init,再到当前最先进的方法systemd。第14章“使用BusyBox runit启动”,演示如何使用Buildroot将系统划分为单独的BusyBox runit 服务,每个服务都有自己的专用进程监督和日志记录,就像 systemd 提供的那样。与System V init不同,BusyBox runit服务是同时启动而不是顺序启动,这可以显著加快启动速度。第15章“管理电源”,考虑可以调整Linux以降低功耗的各种方法,包括动态频率和电压调整、选择更深的空闲状态和系统挂起等。其目的是使设备在电池充电时运行时间更长,并且运行温度更低。第3篇:编写嵌入式应用程序,包括第16~18章。第16章“打包Python程序”,解释哪些选项可用于将Python模块捆绑在一起进行部署,以及何时使用一种方法而不是另一种方法。本章涵盖pip、venv、conda和Docker。第17章“了解进程和线程”,从应用程序开发人员的角度描述嵌入式系统。本章着眼于进程和线程、进程间通信和调度策略。第18章“管理内存”,介绍虚拟内存背后的思想以及地址空间如何被划分为内存映射。本章还描述如何准确测量内存使用情况,以及如何检测内存泄漏。第4篇:调试和优化性能,包括第19~21章。第19章“使用GDB进行调试”,演示使用GNU调试器GDB和调试代理gdbserver来调试在目标设备上远程运行的应用程序。本章还介绍如何扩展这个模型来调试内核代码,即利用kgdb调试内核代码。第20章“性能分析和跟踪”,涵盖可用于测量系统性能的技术。本章从整个系统的性能分析开始,介绍多种性能分析工具。本章还描述如何使用Valgrind检查应用程序在线程同步和内存分配方面的正确性。第21章“实时编程”,提供Linux实时编程的详细指南,包括内核配置和 PREEMPT_RT实时内核补丁。内核跟踪工具Ftrace可用于测量内核调度延迟并显示各种内核配置的效果。充分利用本书本书中使用的软件是完全开源的。在几乎所有示例中,我们都使用了撰写本文时可用的最新稳定版本。虽然我们试图以不特定于版本的方式来描述主要功能,但不可避免的是一些示例需要适应以后的软件。本书涵盖的软硬件如表P-1所示。表P-1 本书涵盖的软硬件本书涵盖的软硬件 操作系统需求BeagleBone Black 不适用Raspberry Pi 4 不适用QEMU(32位ARM) Linux(任意版本)Yocto Project 3.1(Dunfell) 兼容Linux发行版*Buildroot 2020.02 LTS Linux(任意版本)crosstool-NG 1.24.0 Linux(任意版本)U-Boot v2021.01 Linux(任意版本)Linux Kernel 5.4 Linux(任意版本)* 有关更多详细信息,你可以参阅Yocto Project Quick Build(《Yocto Project快速构建》)指南的“Compatible Linux Distribution”(《兼容Linux发行版》)部分。其网址如下: https://www.yoctoproject.org/docs/current/brief-yoctoprojectqs/brief-yoctoprojectqs.html嵌入式开发涉及主机和目标两个系统:主机用于开发程序,目标用于运行程序。对于主机系统,我们使用的是Ubuntu 20.04 LTS,但大多数Linux发行版只需稍作修改即可工作。你可能决定在虚拟机中以访客身份运行Linux,但你应该知道,某些任务(如使用Yocto Project构建发行版)要求很高,最好在Linux的本机安装上运行。本书选择了3个示例目标:QEMU模拟器、BeagleBone Black和Raspberry Pi 4。使用QEMU意味着你可以尝试大多数示例,而无须投资任何额外的硬件。另外,如果你有真正的硬件,有些事情会更好,为此,我们选择了BeagleBone Black,因为它较为便宜,广泛可用,并且有很好的社区支持。Raspberry Pi 4是在本书第3版中添加的,因为它内置了Wi-Fi和蓝牙。当然,你不仅限于这3个目标。本书背后的想法是为你提供问题的通用解决方案,以便你可以将它们应用到广泛的目标板上。下载示例代码文件本书随附的代码可以在GitHub上找到,其网址如下: https://github.com/PacktPublishing/Mastering-Embedded-Linux-Programming-Third-Edition 如果代码有更新,那么它将在GitHub存储库中被更新。下载彩色图像我们还提供了一个PDF文件,其中包含本书中使用的屏幕截图/图表的彩色图像。你可以通过以下地址进行下载: https://static.packt-cdn.com/downloads/9781789530384_ColorImages.pdf本书约定本书中使用了许多文本约定。(1)有关代码块的设置如下: #include #include int main (int argc, char *argv[]){ printf (”Hello, world!\”); return 0;} (2)为了突出代码块,相关内容需要以粗体的形式进行显示: #!/bin/shmount -t proc proc /procmount -t sysfs sysfs /sysmount -t devtmpfs devtmpfs /devecho /sbin/mdev > /proc/sys/kernel/hotplugmdev -s (3)任何命令行的输入或输出都采用如下所示的粗体代码形式: $ sudo tunctl -u $(whoami) -t tap0 (4)术语或重要单词采用中英文对照的形式给出,在括号内保留其英文原文。示例如下: 在嵌入式设备中最常见的架构是ARM、MIPS、PowerPC和x86,每一种都有32位和64位变体,它们都具有内存管理单元(memory management unit,MMU)。 (5)对于界面词汇或专有名词将保留其英文原文,在括号内添加其中文译文。示例如下: 最后,将BR2_ROOTFS_OVERLAY设置为指向覆盖层的路径。可以在menuconfig中使用System configuration(系统配置)| Root filesystem overlay directories(根文件系统覆盖层目录)选项进行配置。 (6)本书还使用了以下两个图标: 表示警告或重要的注意事项。 表示提示信息或操作技巧。
|
|