1. linux内核完全注释 linux0.11 怎么编译运行
目录(?)[+] 本系列文章调试Linux-0.11,大部分都是一些新内容,小部分是对代码的一些印证。 另写了一些调试工具,比如readizone,readblock,readinode这些工具对学习linux-0.11操作系统很有帮助。当然还需要stat和hexmp工具的配合。 fdiskforlinux-0.11 开始到-13/3/15的文章导出的pdf文件下载 另写了一些工具源代码分析,比如mkfs.c源代码分析和d
2. mysql卸载后怎么找回原来建的数据库
每个 DBA 是不是都有过删库的经历?删库了没有备份怎么办?备份恢复后无法启动服务什么情况?表定义损坏数据无法读取怎么办?
我曾遇到某初创互联网企业,因维护人员不规范的备份恢复操作,导致系统表空间文件被初始化,上万张表无法读取,花了数小时才抢救回来。
当你发现数据无法读取时,也许并非数据丢失了,可能是 DBMS 找不到描述数据的信息。
背景
先来了解下几张关键的 InnoDB 数据字典表,它们保存了部分表定义信息,在我们恢复表结构时需要用到。
SYS_TABLES 描述 InnoDB 表信息CREATE TABLE `SYS_TABLES` (`NAME` varchar(255) NOT NULL DEFAULT '', 表名`ID` bigint(20) unsigned NOT NULL DEFAULT '0', 表id`N_COLS` int(10) DEFAULT NULL,`TYPE` int(10) unsigned DEFAULT NULL,`MIX_ID` bigint(20) unsigned DEFAULT NULL,`MIX_LEN` int(10) unsigned DEFAULT NULL,`CLUSTER_NAME` varchar(255) DEFAULT NULL,`SPACE` int(10) unsigned DEFAULT NULL, 表空间idPRIMARY KEY (`NAME`)) ENGINE=InnoDB DEFAULT CHARSET=latin1;SYS_INDEXES 描述 InnoDB 索引信息CREATE TABLE `SYS_INDEXES` ( `TABLE_ID` bigint(20) unsigned NOT NULL DEFAULT '0', 与sys_tables的id对应 `ID` bigint(20) unsigned NOT NULL DEFAULT '0', 索引id `NAME` varchar(120) DEFAULT NULL, 索引名称 `N_FIELDS` int(10) unsigned DEFAULT NULL, 索引包含字段的个数 `TYPE` int(10) unsigned DEFAULT NULL, `SPACE` int(10) unsigned DEFAULT NULL, 存储索引的表空间id `PAGE_NO` int(10) unsigned DEFAULT NULL, 索引的root page id PRIMARY KEY (`TABLE_ID`,`ID`)) ENGINE=InnoDB DEFAULT CHARSET=latin1;SYS_COLUMNS 描述 InnoDB 表的字段信息CREATE TABLE `SYS_COLUMNS` ( `TABLE_ID` bigint(20) unsigned NOT NULL, 与sys_tables的id对应 `POS` int(10) unsigned NOT NULL, 字段相对位置 `NAME` varchar(255) DEFAULT NULL, 字段名称 `MTYPE` int(10) unsigned DEFAULT NULL, 字段编码 `PRTYPE` int(10) unsigned DEFAULT NULL, 字段校验类型 `LEN` int(10) unsigned DEFAULT NULL, 字段字节长度 `PREC` int(10) unsigned DEFAULT NULL, 字段精度 PRIMARY KEY (`TABLE_ID`,`POS`)) ENGINE=InnoDB DEFAULT CHARSET=latin1;SYS_FIELDS 描述全部索引的字段列CREATE TABLE `SYS_FIELDS` ( `INDEX_ID` bigint(20) unsigned NOT NULL, `POS` int(10) unsigned NOT NULL, `COL_NAME` varchar(255) DEFAULT NULL, PRIMARY KEY (`INDEX_ID`,`POS`)) ENGINE=InnoDB DEFAULT CHARSET=latin1;./storage/innobase/include/dict0boot.h 文件定义了每个字典表的 index id,对应 id 的 page 中存储着字典表的数据。
3. C++临走前奉献:输出自身的源代码
雨落深山,该住手时就住手。
4. 如何创建自定义的 WPP 扩展格式规格字符串
有关如何使用此宏的详细信息,请参阅复杂类型定义的语法是怎样的?。本主题提供向你介绍如何执行下列操作的示例:通过自定义 WPP 扩展格式规格字符串跟踪固定长度字符串通过自定义 WPP 扩展格式规格字符串跟踪可变长度字符串每个示例都介绍了如何使用自定义 WPP 配置文件来定义 DEFINE_CPLX_TYPE 宏。在这些示例中,配置文件命名为 LocalWpp.ini。有关如何使用自定义 WPP 配置文件的详细信息,请参阅如何定义自定义数据类型?。 通过自定义 WPP 扩展格式规格字符串跟踪固定长度字符串 此示例介绍如何使用自定义 WPP 扩展格式规格字符串跟踪 Internet 协议版本 6 (IPv6) 网络地址。IPv6 网络地址由 in6_addr 结构定义,具有 16 字节的固定长度。在此示例中,定义了一个复杂数据类型,然后可在你的源代码中将其用作 %!IPV6ADDR!格式规格字符串。要创建 IPV6ADDR 复杂数据类型,请将以下语句添加到 LocalWpp.ini 配置文件: DEFINE_CPLX_TYPE(IPV6ADDR, WPP_LOGIPV6, in6_addr *, ItemIPV6Addr, "s", _IPV6_, 0, 1); 此语句使用 DEFINE_CPLX_TYPE 宏定义复杂类型 (IPV6ADDR) 及其属性,例如其参数类型 (in6_addr *) 和大小 (16)。此语句还指定了在 WPP 预处理器在跟踪提供程序的源代码中解析 IPV6ADDR 复杂类型时,该预处理器使用的帮助程序宏的名称 (WPP_LOGIPV6)。 WPP_FLAGS(-DWPP_LOGIPV6(x) WPP_LOGPAIR( (16), (x))); 此语句定义在将 IPV6 参数的长度/地址对传递到 TraceMessage 函数时,用于对该长度/地址对设置格式的帮助程序宏。在Visual Studio 中,打开你的项目的属性页。在“WPP 跟踪”、“文件选项”下,将 LocalWpp.ini 指定为“其他配置文件”。 有关详细信息,请参阅 WPP 预处理器。以下示例源代码介绍你的跟踪提供程序如何可通过使用 %!IPV6ADDR! 格式规格字符串来跟踪 IPv6 网络格式规格字符串: struct in6_addr IPAddressV6 = {0}; DoTraceMessage(Noise, "IN6_ADDR = %!IPV6ADDR!", &IPAddressV6); 注意�0�2�0�2你可以创建复杂类型 (MACADDR) 用于跟踪固定长度的媒体访问控制 (MAC) 地址。此复杂类型可通过按照用于 IPV6ADDDR 复杂类型的过程来指定。 通过自定义 WPP 扩展格式规格字符串跟踪可变长度字符串 此示例介绍如何使用自定义 WPP 扩展格式规格字符串来跟踪数据的可变长度缓冲区。在此示例中,定义了一个复杂数据类型 (HEXDUMP),然后可在你的源代码中将其用作 %!HEXDUMP!格式规格字符串。要创建 HEXDUMP 复杂数据类型,请将以下语句添加到 LocalWpp.ini 配置文件: DEFINE_CPLX_TYPE(HEXDUMP, WPP_LOGHEXDUMP, const xstr_t&, ItemHEXDump,"s", _HEX_, 0, 2); 此语句使用 DEFINE_CPLX_TYPE 宏定义复杂类型 (HEXDUMP) 及其属性,例如其参数类型 (const xstr_t&) 和传递到 TraceMessage 的参数数 (2)。因为此复杂类型将用于可变长度数据,所以将宏的 Size 元素设置为零。此语句还指定了在 WPP 预处理器在跟踪提供程序的源代码中解析 HEXDUMP 复杂类型时,该预处理器使用的帮助程序宏的名称 (WPP_LOGHEXDUMP)。 struct xstr_t { CHAR * _buf; short _len; xstr_t(__in_ecount(len) char *buf, short len):_buf(buf),_len(len) {} }; 此语句定义用于保存可变长度缓冲区的长度和地址的结构。此结构在 LOG_LENSTR 宏中进行初始化,并且对在 FormatString 参数中使用 HEXDUMP 复杂类型的 DoTraceMessage 的每次调用都置于本地。 WPP_FLAGS(-DLOG_LENSTR(len,str)=xstr_t(str,len)); 此语句定义用于为可变长度缓冲区初始化 xstr_t 结构的宏。你必须使用此宏在 DoTraceMessage 的VariableList 参数中传递可变长度缓冲区。 WPP_FLAGS(-DWPP_LOGHEXDUMP(x) WPP_LOGPAIR(2,&(x)._len) WPP_LOGPAIR((x)._len, (x)._buf)); 此语句定义在将可变长度缓冲区参数的长度/地址对传递到 TraceMessage 函数时,用于对该长度/地址对设置格式的帮助程序宏。可变长度参数要求两个长度/地址对。因此,WPP_LOGHEXDUMP 宏以下列方式定义对 WPP_LOGPAIR 的两个调用:对WPP_LOGPAIR 的第一个调用传递可变长度缓冲区的大小。对WPP_LOGPAIR 的第二个调用传递缓冲区自身的地址。注意�0�2�0�2此宏要求,已经通过对 LOG_LENSTR 的调用为可变长度缓冲区初始化 xstr_t 结构。因此,你必须通过 LOG_LENSTR 宏将可变长度缓冲区传递到 DoTraceMessage。在Visual Studio 中,打开你的项目的属性页。在“WPP 跟踪”、“文件选项”下,将 LocalWpp.ini 指定为“其他配置文件”。 有关详细信息,请参阅 WPP 预处理器。以下示例源代码介绍你的跟踪提供程序如何可通过使用 %!HEXDUMP! 格式规格字符串来跟踪数据格式规格字符串: CHAR HexDump[1024] = {0, 1, 2, 3, 4, 5, 6, 7} ; DoTraceMessage(Noise, "HEXDUMP: %!HEXDUMP! ", LOG_LENSTR(sizeof(HexDump),(PCHAR)HexDump)); 注意�0�2�0�2你可以创建复杂类型 (HEXBYTES) 用于跟踪可变长度缓冲区。�0�2�0�2
5. 如何打开二进制文件 ubuntu
查看二进制有以下几种方法:
方法一:hexmp
apt-get install libdata-hexmper-perl
安装好之后就可以直接hexmp your_binary_file
也可以直接使用hd命令来代替hexmp
如果想要慢慢看 : hd your_binary_file | more
方法二:
Vim 可以用来查看和编辑二进制文件
vim -b egenea-base.ko 加上-b参数,以二进制打开
然后输入命令 :%!xxd -g 1 切换到十六进制模式显示
0000000: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 .ELF............
0000010: 01 00 03 00 01 00 00 00 00 00 00 00 00 00 00 00 ................
0000020: 2c a7 03 00 00 00 00 00 34 00 00 00 00 00 28 00 ,.......4.....(.
0000030: 10 00 0d 00 55 89 e5 51 51 8b 45 08 85 c0 74 11 ....U..QQ.E...t.
0000040: 52 52 50 a1 00 00 00 00 50 e8 fc ff ff ff 83 c4 RRP.....P.......
0000050: 10 89 ec 5d c3 8d 76 00 55 89 e5 50 50 b8 01 00 ...]..v.U..PP...
0000060: 00 00 8b 55 08 39 d0 73 09 8d 76 00 01 c0 39 d0 ...U.9.s..v...9.
0000070: 72 fa 8b 55 04 51 52 50 a1 00 00 00 00 50 e8 fc r..U.QRP.....P..
0000080: ff ff ff 89 ec 5d c3 90 55 89 e5 50 50 b8 01 00 .....]..U..PP...
0000090: 00 00 8b 55 08 39 d0 73 09 8d 76 00 01 c0 39 d0 ...U.9.s..v...9.
00000a0: 72 fa 8b 4d 04 8b 55 10 51 52 50 a1 00 00 00 00 r..M..U.QRP.....
00000b0: 50 e8 fc ff ff ff 89 ec 5d c3 89 f6 55 89 e5 57 P.......]...U..W
00000c0: 56 53 81 ec 8c 00 00 00 8b 5d 1c 8b 45 10 85 db VS.......]..E...
00000d0: 75 7e 85 c0 75 71 50 8b 45 04 50 a1 00 00 00 00 u~..uqP.E.P.....
00000e0: 68 8c 00 00 00 50 e8 fc ff ff ff 83 c4 10 89 c2 h....P.........
然后就可以像修改文本文件一样修改16进制的字符,可以用 / 查找指定的偏移等等。修改右边的ascii字符应该无效。修改完成后再执行:%!xxd -r 切换会二进制模式,然后再 :wq 保存退出就可以了。在这vim里面这样编辑还是很方便的,注意一定要:%!xxd -r切换回来之后在保存才行。
方法三. Linux 上面也有十六进制编辑的GUI工具
jeex (http://www.hds619.NET/jeex.PHP)
ghex
bless (Bless is a Hex Editor for Gtk# http://home.gna.org/bless/)
UltraEdit
6. 如何在Ubuntu下使用TF/SD 卡制作Exynos 4412 u-boot启动盘
U-Boot源代码下载地址 http://www.linuxidc.com/Linux/2011-07/38897.htm
硬件:迅为iTop 4412精英版 & TF卡
软件:系统自带终端即可
首先,我们应该清楚TF/SD卡可以看作一张完全空白的“白纸”,之所以有分区、分区格式的区别不过是在在这张“白纸”的某些特定位置写入了一些数据来指示分区、分区格式。
其次,我们还应该清楚,在TF/SD启动模式下,exynos 4412一上电,内部iROM会从TF/SD的第1个Block(第512个字节开始)读取8KB的数据到内部iRAM,然后从内部iRAM的0地址开始运行。
原理搞清楚了,那么首先需要把TF/SD低级格式化-所有Block全部写0x00。
1、连接TF/SD卡,打开终端
使用ls /dev/sd* 命令查看所有连接到电脑上磁盘。
问题:在这里为什么不用df命令?
原因是假设你的TF/SD卡只有一个分区但这个分区已损坏,或者有多个分区但是没有一个可以识别的分区,那么此时df命令无法查看到tf/sd卡,所以说直接列出dev下所有sd开头的设备,是终极方案。
(1)假设你的tf/sd卡只有一个分区,无论这个分区是否损坏,现象应该是类似这样的:
插上tf/sd卡之前:
插上tf/sd卡之后:
很明显多出的/dev/sdb就是本文后续操作的对象。
(2)假设你的tf/sd卡已有多个分区,无论这些分区是否损坏,现象应该是类似这样的:
插上tf/sd卡之前:
插上tf/sd卡之后:
这里多出5个设备,但是我们仍然将/dev/sdb作为本文后续操作的对象。
注意:我这里是/dev/sdb,但是还有可能是/dev/sdc等等其它符号,必须根据你实际出现的设备名称进行以下操作,否则有可能损坏系统分区,非常重要,切记!!!
2、使用16进制模式打开TF卡查看数据(可跳过)
我们使用linux自带命令hexmp查看tf/sd卡中的数据:
命令为:
sudo hexmp -n 1048576 /dev/sdb
其中-n 1048576代表打印出前1M=1024*1024=1048576字节的数据。
执行结果(部分)如下:
*代表内容为0x00,为了节省空间故作省略。
3、清空TF卡上前1MB的数据
由于4412的uboot大小基本在几百kB的量级,所以清空前1MB空间足够用,注意这里的清空不是格式化,而是填充0x00。
我们利用系统/dev下的zero设备,清零tf/sd卡前1MB。
执行结果如下:
这里的count=2000代表清空2000个block,一个block=512B,2000个正好为1MB。
再次hexmp查看tf/sd卡数据,发现:
前1MB空间成功清0x00。
4、烧写uboot启动文件
在这里,我们待烧写的文件为 u-boot-iTOP-4412.bin 这个文件。
终端执行命令:
if代表输入文件地址,以你u-boot-iTOP-4412.bin 这个文件的实际地址为准,of代表输出地址,以你tf/sd卡的实际设备号为准。
到这里,就可以将tf/sd卡插入开发板上电启动了,为了证明我们烧写无误,我们执行后续操作。
5、确认烧写正确(可跳过)
我们需要确定从tf/sd卡的第一个block开始处,确实正确烧写了u-boot-iTOP-4412.bin这个文件,下面我们对比一下,用到的命令同样还是hexmp。
在这里,我们为了显示方便,只打印前5KB数据,发现bin文件被正确的复制到了sd卡的512字节处:
6、将TF卡接到开发板上,拨码开关选择TF启动,上电:
Done。
本文永久更新链接地址:http://www.linuxidc.com/Linux/2015-02/113493.htm
7. Linux内核编程的目录
目录
第1章概述1
1.1UNIX的历史2
1.2标准和通用接口3
1.3自由软件和开放源码3
1.4Linux发布版概览3
1.41Debian4
1.42Red Hat/Fedora 4
1.43Mandriva4
1.44SUSE4
1.45Gentoo4
1.46Yellow Dog5
1.47其他发布版5
1.5内核版本信息5
1.6基于Power的Linux5
1.7什么是操作系统6
1.8内核组织7
1.9Linux内核概述7
1.9.1用户接口7
1.9.2用户标识符8
1.9.3文件和文件系统8
1.9.4进程12
1.9.5系统调用15
1.9.6Linux调度程序15
1.9.7Linux设备驱动程序15
1.10可移植性和体系结构的相关性16
1.11小结16
1.12习题16
第2章内核探索工具集18
2.1内核中常见的数据类型18
2.1.1链表18
2.1.2查找21
2.1.3树22
2.2汇编24
2.2.1PowerPC24
2.2.2x8627
2.3汇编语言示例29
2.3.1x86中的汇编示例30
2.3.2PowerPC中的汇编示例31
2.4内联汇编33
2.4.1输出操作数34
2.4.2输入操作数34
2.4.3已修改过的寄存器(已修改的元素列表) 34
2.4.4参数的编号方式34
2.4.5约束条件34
2.4.6asm35
2.4.7__volatile__35
2.5特殊的C 语言用法38
2.5.1asmlinkage38
2.5.2UL39
2.5.3内联39
2.5.4const和volatile39
2.6内核探索工具一览40
2.6.1objmp/readelf40
2.6.2hexmp41
2.6.3nm41
2.6.4obj42
2.6.5ar42
2.7内核发言:倾听来自内核的消息42
2.7.1printk()42
2.7.2dmesg42
2.7.3/var/log/messages42
2.8其他奥秘43
2.8.1__init43
2.8.2likely()和unlikely()43
2.8.3IS_ERR和PTR_ERR44
2.8.4通告程序链44
2.9小结45
2.9.1项目:Hellomod45
2.9.2第一步:构造Linux模块的框架45
2.9.3第二步:编译模块46
2.9.4第三步:运行代码47
2.10习题48
第3章进程:程序执行的基本模型49
3.1程序51
3.2进程描述符52
3.2.1与进程属性相关的字段54
3.2.2与调度相关的字段55
3.2.3涉及进程间相互关系的字段58
3.2.4与进程信任状相关的字段59
3.2.5与进程权能相关的字段60
3.2.6与进程限制相关的字段61
3.2.7与文件系统及地址空间相关的字段63
3.3进程的创建:系统调用fork()、vfork 和clone()64
3.3.1fork()函数65
3.3.2vfork()函数66
3.3.3clone()函数67
3.3.4do_fork()函数68
3.4进程的生命周期70
3.4.1进程的状态70
3.4.2进程状态的转换71
3.5进程的终止74
3.5.1sys_exit()函数75
3.5.2do_exit()函数75
3.5.3通知父进程和sys_wait4()77
3.6了解进程的动态:调度程序的基本构架80
3.6.1基本结构80
3.6.2从等待中醒来或者激活81
3.7等待队列86
3.7.1添加到等待队列88
3.7.2等待事件89
3.7.3唤醒进程91
3.8异步执行流程93
3.8.1异常93
3.8.2中断95
3.9小结114
3.9.1项目:系统变量current114
3.9.2项目源码115
3.9.3运行代码116
3.10习题116
第4章内存管理117
4.1页119
4.2内存管理区121
4.2.1内存管理区描述符122
4.2.2内存管理区操作辅助函数124
4.3页面124
4.3.1请求页面的函数124
4.3.2释放页面的函数126
4.3.3伙伴系统126
4.4Slab分配器130
4.4.1缓存描述符133
4.4.2通用缓存描述符135
4.4.3Slab描述符136
4.5Slab分配器的生命周期138
4.5.1与Slab分配器有关的全局变量138
4.5.2创建缓存139
4.5.3创建slab与cache_grow()144
4.5.4Slab的销毁:退还内存与kmem_cache_destroy()146
4.6内存请求路径147
4.6.1kmalloc()147
4.6.2kmem_cache_alloc()148
4.7Linux进程的内存结构149
4.7.1mm_struct150
4.7.2vm_area_struct152
4.8进程映像的分布及线性地址空间153
4.9页表155
4.10缺页156
4.10.1x86缺页异常156
4.10.2缺页处理程序157
4.10.3PowerPC缺页异常164
4.11小结164
4.12项目:进程内存映射165
4.13习题166
第5章输入/输出167
5.1总线、桥、端口和接口的硬件实现167
5.2设备171
5.2.1块设备概述172
5.2.2请求队列和I/O 调度173
5.2.3示例:“通用”块设备驱动程序180
5.2.4设备操作182
5.2.5字符设备183
5.2.6网络设备184
5.2.7时钟设备184
5.2.8终端设备184
5.2.9直接存储器存取184
5.3小结185
5.4项目:创建并口驱动程序185
5.4.1并口的硬件185
5.4.2运行在并口上的软件187
5.5习题192
第6章文件系统194
6.1文件系统的基本概念194
6.1.1文件和文件名194
6.1.2文件类型195
6.1.3文件的附加属性195
6.1.4目录和路径名196
6.1.5文件操作197
6.1.6文件描述符197
6.1.7磁盘块、磁盘分区以及实现197
6.1.8性能198
6.2Linux虚拟文件系统198
6.2.1VFS的数据结构200
6.2.2全局链表和局部链表的引用211
6.3与VFS相关的结构212
6.3.1fs_struct结构212
6.3.2files_struct结构213
6.4页缓存216
6.4.1address_space结构217
6.4.2buffer_head结构219
6.5VFS的系统调用和文件系统层221
6.5.1open()221
6.5.2close()227
6.5.3read()229
6.5.4write()244
6.6小结246
6.7习题246
第7章进程调度和内核同步247
7.1Linux的调度程序248
7.1.1选择下一个进程248
7.1.2上下文切换253
7.1.3让出CPU261
7.2内核抢占269
7.2.1显式内核抢占269
7.2.2隐式用户抢占270
7.2.3隐式内核抢占270
7.3自旋锁和信号量272
7.4系统时钟:关于时间和定时器274
7.4.1实时时钟:现在几点了274
7.4.2读取PPC的实时时钟276
7.4.3读取x86的实时时钟278
7.5小结280
7.6习题280
第8章内核引导281
8.1BIOS和Open Firmware282
8.2引导加载程序282
8.2.1GRUB283
8.2.2LILO286
8.2.3PowerPC和Yaboot286
8.3与体系结构相关的内存初始化287
8.3.1PowerPC的硬件内存管理287
8.3.2基于Intel x86体系结构的硬件内存管理296
8.3.3PowerPC和x86的代码汇集305
8.4原始的RAM盘305
8.5开始:start_kernel()306
8.5.1调用lock_kernel()307
8.5.2调用page_address_init()309
8.5.3调用printk(linux_banner)311
8.5.4调用setup_arch311
8.5.5调用setup_per_cpu_areas()315
8.5.6调用smp_prepare_boot_cpu()316
8.5.7调用sched_init()317
8.5.8调用build_all_zonelists()319
8.5.9调用page_alloc_init319
8.5.10调用parse_args()320
8.5.11调用trap_init()322
8.5.12调用rcu_init()323
8.5.13调用init_IRQ()323
8.5.14调用softirq_init()324
8.5.15调用time_init()325
8.5.16调用console_init()326
8.5.17调用profile_init()326
8.5.18调用local_irq_enable()327
8.5.19配置initrd327
8.5.20调用mem_init()327
8.5.21调用late_time_init()333
8.5.22调用calibrate_delay()333
8.5.23调用pgtable_cache_init()334
8.5.24调用buffer_init()335
8.5.25调用security_scaffolding_startup()336
8.5.26调用vfs_caches_init()336
8.5.27调用radix_tree_init()343
8.5.28调用signal_init()344
8.5.29调用page_writeback_init()344
8.5.30调用proc_root_init()346
8.5.31调用init_idle()347
8.5.32调用rest_init()348
8.6init线程(或进程1)349
8.7小结353
8.8习题353
第9章构建Linux内核354
9.1工具链354
9.1.1编译程序355
9.1.2交叉编译355
9.1.3链接程序356
9.1.4ELF二进制目标文件356
9.2内核源代码的构建360
9.2.1解释源代码360
9.2.2构建内核映像364
9.3小结369
9.4习题369
第10章向内核添加代码371
10.1浏览源代码371
10.11熟悉文件系统371
10.12filp和fops372
10.13用户空间和内核空间374
10.14等待队列375
10.15工作队列及中断378
10.16系统调用380
10.17其他类型的驱动程序380
10.18设备模型和sysfs文件系统383
10.2编写代码386
10.2.1设备基础386
10.2.2符号输出388
10.2.3IOCTL388
10.2.4轮询与中断391
10.2.5工作队列和tasklet395
10.2.6增加系统调用的代码396
10.3构建和调试398
10.4小结399
10.5习题400
8. 如何在Ubuntu下使用TF/SD 卡制作Exynos 4412 u-boot启动盘
/**
******************************************************************************
* @author Maoxiao Hu
* @version V1.0.1
* @date Feb-2015
******************************************************************************
* < COPYRIGHT 2015 ISE of SHANDONG UNIVERSITY >
******************************************************************************
**/
如果你的系统是Mac OS X,请移步这里《如何在Mac下使用TF/SD 卡制作Exynos 4412 u-boot启动盘》 http://www.linuxidc.com/Linux/2015-02/113494.htm。
U-Boot源代码下载地址 http://www.linuxidc.com/Linux/2011-07/38897.htm
硬件:迅为iTop 4412精英版 & TF卡
软件:系统自带终端即可
首先,我们应该清楚TF/SD卡可以看作一张完全空白的“白纸”,之所以有分区、分区格式的区别不过是在在这张“白纸”的某些特定位置写入了一些数据来指示分区、分区格式。
其次,我们还应该清楚,在TF/SD启动模式下,exynos 4412一上电,内部iROM会从TF/SD的第1个Block(第512个字节开始)读取8KB的数据到内部iRAM,然后从内部iRAM的0地址开始运行。
原理搞清楚了,那么首先需要把TF/SD低级格式化-所有Block全部写0x00。
1、连接TF/SD卡,打开终端
使用ls /dev/sd* 命令查看所有连接到电脑上磁盘。
问题:在这里为什么不用df命令?
原因是假设你的TF/SD卡只有一个分区但这个分区已损坏,或者有多个分区但是没有一个可以识别的分区,那么此时df命令无法查看到tf/sd卡,所以说直接列出dev下所有sd开头的设备,是终极方案。
(1)假设你的tf/sd卡只有一个分区,无论这个分区是否损坏,现象应该是类似这样的:
插上tf/sd卡之前:
NewImage
插上tf/sd卡之后:
NewImage
很明显多出的/dev/sdb就是本文后续操作的对象。
(2)假设你的tf/sd卡已有多个分区,无论这些分区是否损坏,现象应该是类似这样的:
插上tf/sd卡之前:
NewImage
插上tf/sd卡之后:
NewImage
这里多出5个设备,但是我们仍然将/dev/sdb作为本文后续操作的对象。
注意:我这里是/dev/sdb,但是还有可能是/dev/sdc等等其它符号,必须根据你实际出现的设备名称进行以下操作,否则有可能损坏系统分区,非常重要,切记!!!
2、使用16进制模式打开TF卡查看数据(可跳过)
我们使用linux自带命令hexmp查看tf/sd卡中的数据:
命令为:
sudo hexmp -n 1048576 /dev/sdb
其中-n 1048576代表打印出前1M=1024*1024=1048576字节的数据。
执行结果(部分)如下:
NewImage
*代表内容为0x00,为了节省空间故作省略。
3、清空TF卡上前1MB的数据
由于4412的uboot大小基本在几百kB的量级,所以清空前1MB空间足够用,注意这里的清空不是格式化,而是填充0x00。
我们利用系统/dev下的zero设备,清零tf/sd卡前1MB。
执行结果如下:
NewImage
这里的count=2000代表清空2000个block,一个block=512B,2000个正好为1MB。
再次hexmp查看tf/sd卡数据,发现:
NewImage
前1MB空间成功清0x00。
4、烧写uboot启动文件
在这里,我们待烧写的文件为 u-boot-iTOP-4412.bin 这个文件。
终端执行命令:
NewImage
if代表输入文件地址,以你u-boot-iTOP-4412.bin 这个文件的实际地址为准,of代表输出地址,以你tf/sd卡的实际设备号为准。
到这里,就可以将tf/sd卡插入开发板上电启动了,为了证明我们烧写无误,我们执行后续操作。
5、确认烧写正确(可跳过)
我们需要确定从tf/sd卡的第一个block开始处,确实正确烧写了u-boot-iTOP-4412.bin这个文件,下面我们对比一下,用到的命令同样还是hexmp。
在这里,我们为了显示方便,只打印前5KB数据,发现bin文件被正确的复制到了sd卡的512字节处:
NewImage
6、将TF卡接到开发板上,拨码开关选择TF启动,上电:
NewImage
Done。
9. 如何交叉编译mkfs.jffs2等工具链mtd-utils
首先说明一下:
在YAFFS2源文件的utils目录下,执行make就可以生成 mkyaffs2image工具,执行
.(要制作yaffs2的目录) (目标镜像)/mkyaffs2image
acl_2.2.47.orig.tar.gz
lzo-2.03.tar.gz
mtd-utils_20080508.orig.tar.gz
zlib-1.2.3.tar.gz
mkfs.jffs2.for.arm-linux-gcc.3.4.1平台.tar.bz2
mkfs.jffs2.for.arm-linux-gcc.4.3.2平台.tar.bz2
mkfs.jffs2.for.pc平台.tar.bz2
如果只需要mkfs.jffs2工具,那么ubuntu 8.10下直接安装jffnms软件包即可,
luther@gliethttp:~$ sudo apt-get install jffnms
如果需要将jffs2移植到arm开发板上,那么就需要下载源码进行交叉编译了,这就是本文的内容.
1.下载工具软件源码包
luther@gliethttp:~$ wget http://ftp.de.debian.org/debian/pool/main/m/mtd-utils/mtd-utils_20080508.orig.tar.gz
luther@gliethttp:~$ wget http://www.zlib.net/zlib-1.2.3.tar.gz
luther@gliethttp:~$ wget http://www.oberhumer.com/opensource/lzo/download/lzo-2.03.tar.gz
luther@gliethttp:~$ mkdir libs 用来存放下面生成的lib库.
2.编译zlib库
luther@gliethttp:~/zlib-1.2.3$ ./configure --prefix=~/libs --shared
对于交叉编译输入如下指令
luther@gliethttp:~/zlib-1.2.3$ CC=arm-linux-gcc ./configure --prefix=~/libs --shared
luther@gliethttp:~/zlib-1.2.3$ make -j4
luther@gliethttp:~/zlib-1.2.3$ make install
luther@gliethttp:~$ tree ~/libs
/home/ubuntu/libs
|-- include
| |-- zconf.h
| `-- zlib.h
|-- lib
| |-- libz.so -> libz.so.1.2.3
| |-- libz.so.1 -> libz.so.1.2.3
| `-- libz.so.1.2.3
`-- share
`-- man
`-- man3
`-- zlib.3
5 directories, 6 files
这就表示完成了.
3.编译lzo库
luther@gliethttp:~/lzo-2.03$ ./configure --prefix=/home/ubuntu/libs --enable-shared
对于交叉编译输入如下指令
luther@gliethttp:~/lzo-2.03$ CC=arm-linux-gcc ./configure --host=arm-linux --prefix=/home/ubuntu/libs --enable-shared --disable-static
这个还必须要绝对路径才行.
luther@gliethttp:~/lzo-2.03$ make
luther@gliethttp:~/lzo-2.03$ make install
luther@gliethttp:~$ tree ~/libs
.
|-- include
| |-- lzo
| | |-- lzo1.h
| | |-- lzo1a.h
| | |-- lzo1b.h
| | |-- lzo1c.h
| | |-- lzo1f.h
| | |-- lzo1x.h
| | |-- lzo1y.h
| | |-- lzo1z.h
| | |-- lzo2a.h
| | |-- lzo_asm.h
| | |-- lzoconf.h
| | |-- lzodefs.h
| | `-- lzoutil.h
| |-- zconf.h
| `-- zlib.h
|-- lib
| |-- liblzo2.a
| |-- liblzo2.la
| |-- liblzo2.so -> liblzo2.so.2.0.0
| |-- liblzo2.so.2 -> liblzo2.so.2.0.0
| |-- liblzo2.so.2.0.0
| `-- libz.a
`-- share
`-- man
`-- man3
`-- zlib.3
6 directories, 22 files
手工将静态库删掉就行了,
如果是arm平台还需要strip优化.
4.编译mtd-utils-20080508前的准备工作.
编译之前的代码工作
luther@gliethttp:~$ wget http://ftp.de.debian.org/debian/pool/main/a/acl/acl_2.2.47.orig.tar.gz
luther@gliethttp:~$ mkdir libs/include/sys -p
luther@gliethttp:~$ cp acl-2.2.47/include/acl.h libs/include/sys
luther@gliethttp:~/mtd-utils-20080508$ export LD_LIBRARY_PATH=~/libs/lib:$LD_LIBRARY_PATH
如果还找不到-llzo2,那么把他拷到/usr/lib下,对于交叉编译器,就是拷贝到
比如
luther@gliethttp:~/libs/lib$ sudo cp -a * /vobs/tools/arm-tools/arm-linux-gcc-3.4.1/arm-linux/lib/
luther@gliethttp:~/mtd-utils-20080508$ vim Makefile
修改安装路径
DESTDIR=.
SBINDIR=gliethttp/sbin
MANDIR=gliethttp/share/man
INCLUDEDIR=gliethttp/include
修改CFLAGS变量
CFLAGS := -I./include -I/home/ubuntu/libs/include $(OPTFLAGS)
如果是arm-linux-gcc定义为
CFLAGS := -I./include -I/home/ubuntu/libs/include -DAI_ADDRCONFIG=0x0020 $(OPTFLAGS)
来自/usr/include/netdb.h
luther@gliethttp:~/mtd-utils-20080508$ vim ubi-utils/Makefile
DESTDIR := ~/mtd-utils-20080508
SBINDIR=gliethttp/sbin
MANDIR=gliethttp/share/man
INCLUDEDIR=gliethttp/include
luther@gliethttp:~/mtd-utils-20080508$ vim recv_image.c
拷贝/usr/include/netinet/in.h文件中
arm-linux-gcc中不需要拷贝它.
struct ip_mreq
{
struct in_addr imr_multiaddr;
struct in_addr imr_interface;
};
结构体数据到头部,否则在u盘版的ubuntu 8.10上老是提示没有ip_mreq定义,虽然上面明明写了#define _USE_MISC
arm-linux-gcc中还需要创建如3下个目录
luther@gliethttp:~/mtd-utils-20080508$ mkdir arm-linux
luther@gliethttp:~/mtd-utils-20080508$ cp -r ubi-utils arm-linux/
luther@gliethttp:~/mtd-utils-20080508$ cp -r include arm-linux/
luther@gliethttp:~/mtd-utils-20080508$ vim ubi-utils/src/libpfiflash.c
将所有EBUF(PFIFLASH_ERRSTR[-rc]);全部替换为EBUF("%s", PFIFLASH_ERRSTR[-rc]);
vim下替换脚本为
:%s/EBUF(PFIFLASH_ERRSTR\[-rc\]);/EBUF("\%s", PFIFLASH_ERRSTR\[-rc\]);/g
luther@gliethttp:~/mtd-utils-20080508$ vim ubi-utils/src/ubimirror.c
将第206行的
fprintf(stderr, err_buf);
改为
fprintf(stderr, "%s", err_buf); // 想法是好的,因为err_buf中含有%d等format信息,这样接口更加统一,但是编译器似乎还并不支持这样的操作.[luther.gliethttp]
luther@gliethttp:~/mtd-utils-20080508$ vim ubi-utils/src/unubi.c
将第898行
char fname[PATH_MAX];
改为
char fname[PATH_MAX+1];
luther@gliethttp:~/mtd-utils-20080508$ cd ubi-utils/new-utils
因为-O2优化的原因,会导致如下log信息
error: ignoring return value of ‘scanf’, declared with attribute warn_unused_result
所有手工先编译.o
luther@gliethttp:~/mtd-utils-20080508/ubi-utils/new-utils$ gcc -Iinclude -Isrc -I../../include -Wall -Werror -Wall src/ubiformat.c -c -o ubiformat.o
对于交叉编译执行如下1条语句
luther@gliethttp:~/mtd-utils-20080508/ubi-utils/new-utils$ arm-linux-gcc -Iinclude -Isrc -I../../include -Wall -Werror -Wall src/ubiformat.c -c -o ubiformat.o
luther@gliethttp:~/mtd-utils-20080508/ubi-utils/new-utils$ cd -
好了,上面的所有修改完成之后,就可以执行make成功编译了[luther.gliethttp].
luther@gliethttp:~/mtd-utils-20080508$ make
如果是交叉编译,执行
luther@gliethttp:~/mtd-utils-20080508$ make CROSS=arm-linux-
luther@gliethttp:~/mtd-utils-20080508$ make install
对于交叉编译,执行
luther@gliethttp:~/mtd-utils-20080508$ make CROSS=arm-linux- install
luther@gliethttp:~/mtd-utils-20080508$ tree gliethttp/
gliethttp/
|-- sbin
| |-- bin2nand
| |-- doc_loadbios
| |-- docfdisk
| |-- flash_erase
| |-- flash_eraseall
| |-- flash_info
| |-- flash_lock
| |-- flash_otp_mp
| |-- flash_otp_info
| |-- flash_unlock
| |-- flashcp
| |-- ftl_check
| |-- ftl_format
| |-- jffs2mp
| |-- mkbootenv
| |-- mkfs.jffs2
| |-- mkpfi
| |-- mtd_debug
| |-- nand2bin
| |-- nandmp
| |-- nandtest
| |-- nandwrite
| |-- nftl_format
| |-- nftlmp
| |-- pddcustomize
| |-- pfi2bin
| |-- pfiflash
| |-- recv_image
| |-- rfdmp
| |-- rfdformat
| |-- serve_image
| |-- sumtool
| |-- ubiattach
| |-- ubicrc32
| |-- ubicrc32.pl
| |-- ubidetach
| |-- ubigen
| |-- ubimirror
| |-- ubimkvol
| |-- ubinfo
| |-- ubinize
| |-- ubirmvol
| |-- ubiupdatevol
| `-- unubi
`-- share
`-- man
`-- man1
`-- mkfs.jffs2.1.gz
4 directories, 45 files
ep9312开发板上没有任何文件系统flash数据读取
# ./mtd_debug read /dev/mtd0 0 100 gliethttp.bin
Copied 100 bytes from address 0x00000000 in flash to gliethttp.bin
# hexmp gliethttp.bin
0000000 03ff ea00 350c e59f 001c e583 410e e3a0
0000010 4004 e583 4a03 e3a0 4001 e254 fffd 1aff
0000020 4106 e3a0 4004 e583 420f e202 5000 e594
0000030 4001 e084 5000 e594 4001 e084 5000 e594
0000040 4001 e084 5000 e594 4010 e3a0 4008 e583
0000050 4050 e3a0 4001 e254 fffd 1aff 4e1e e3a0
0000060 4008 e583
0000064
#
# ./mtd_debug read /dev/mtd2 0 100 gliethttp.bin;hexmp gliethttp.bin -Cv
Copied 100 bytes from address 0x00000000 in flash to gliethttp.bin
00000000 1f 8b 08 00 ca 14 7d 4a 02 03 e4 5a 0f 70 93 e7 |......}J...Z.p..|
00000010 79 7f 3f 49 36 b2 31 41 80 a0 0e 38 cd 57 70 16 |y.?I6.1A...8.Wp.|
00000020 93 18 f3 19 3b 60 12 9a d9 60 08 09 4e 22 c0 a4 |....;`...`..N"..|
00000030 b4 81 ca 42 92 6d 0d 59 d2 49 72 02 2b 4d dd 60 |...B.m.Y.Ir.+M.`|
00000040 72 84 e1 86 03 a7 21 01 8a d2 b2 4b 2e f3 56 76 |r.....!....K..Vv|
00000050 63 b7 34 0b 1d cd b1 1d 6b b3 95 36 dc 95 db d1 |c.4.....k..6....|
00000060 8b 90 d1 ea |....|
00000064