《Linux内核完全注释》阅读笔记——搭建实验环境(转载)

  不看linux内核实在没有学习linux的必要,最近又开始看《Linux内核完全注释》,现在开始看比以前感觉好多了,一些以前难以明白的问题现在也不是什么问题。有人说时间可以解决很多问题,以前不懂,现在终于明白了。下面是我参考别人写的文章,自己照着上面在Ubuntu9.04上做了下,一切顺利。好了,废话少说!

******************************************************************************
搭建linux-0.11(0.95)源代码的阅读、编译、运行和调试环境
*******************************************************************************

    这里将详细介绍如何在ubuntu 8.04下阅读、编译、运行和调试linux-0.11(0.95)。选择ubuntu 8.04的理由很简单:开放源代码,可免费获得,使用方便……
    该阅读笔记主要参考《Linux内核完全注释》的第14章。

1、搭建阅读环境

    首先需要安装ubuntu 8.04,关于该linux发行版的安装和使用办法,建议到ubuntu china的官方[1]转一转。安装好ubuntu 8.04以后,基本的工具都有了。不过为了能够更好地阅读源代码,还是建议确保把vim,cscope,ctags等工具都安装上了,vim是一款“古典 ”而又有“超级牛力”的编辑器,cscope和ctags是两款非常友善的代码阅读辅助工具,在ubuntu 8.04下,都可以直接结合vim使用。

$ sudo apt-get install vim cscope exuberant-ctags



    关于vim, cscope, ctags的用法,由于时间关系,这里不便详细介绍,请分别参考资料[2],[3],[4]。

2、搭建编译环境

    在ubuntu下,安装C语言开发环境(主要是gnu的一些Toolchains)还是蛮简单的,直接把build-essential这个虚拟包安装上即可。

$ sudo apt-get install build-essential



    不过上述软件包中并未包含as86和ld86,这两个工具用于编译和链接linux-0.11的boot目录下汇编语言文件bootsect.s和 setup.s,它们采用as86汇编语法,而linux-0.11下的其他汇编语言文件采用gas的语法(AT&T),所以我们还需要单独安装包含as86和ld86的软件包bin86。
   

// 查找as86和ld86两个工具所在的软件包
$ apt-cache search as86 ld86
bin86 - 16-bit x86 assembler and loader
// 安装该软件包
$ apt-get install bin86



    如果想把相关的文档也安装上,请参考资料[5]。

    不过需要特别注意的是:默认安装的gcc版本是4.0以上,而这些版本可能引入了一些新的特性,在使用时总会遇到一些问题,因此在后续的所有实验中我们将采用更早的一个版本,即gcc 3.4版。下面把gcc-3.4版安装上,并把gcc文件链接到该版本。

$ sudo apt-get install gcc-3.4
$ which gcc-3.4 gcc
/usr/bin/gcc-3.4
/usr/bin/gcc
$ sudo ln -sf /usr/bin/gcc-3.4 /usr/bin/gcc
$ gcc --version | sed -n -e "1p"
gcc (GCC) 3.4.6 (Ubuntu 3.4.6-6ubuntu5)



    这个环境搭建好以后就可以编译linux-0.11的源代码了,不过如果想在ubuntu 8.04下直接编译它,还得打上赵老师提供的补丁,不过赵老师提供的补丁在redhat 9.0下实验通过,而在ubuntu 8.04下则不能直接使用,所以经过实验,我重新做了一个linux-0.11在ubuntu 8.04下能正常编译通过的补丁,即附件中的linux-0.11-080529-ubuntu8.04.patch。
    下面介绍具体的编译过程。

// 下载linux-0.11的源代码并解压
$ wget -c http://mirror.lzu.edu.cn/os/oldlinux.org/kernel/0.1x/linux-0.11.tar.gz
$ tar zxf linux-0.11-080529-ubuntu8.04.patch.tar.gz
$ tar zxf linux-0.11.tar.gz
// 打上linux-0.11-080529-ubuntu8.04.patch补丁
$ cd linux-0.11
$ patch -p1 < ../linux-0.11-080529-ubuntu8.04.patch
// 确保gcc-3.4版已经安装上(为确保使用gcc的3.4版,该补丁已经直接在所有Makefile文件中指定CC为gcc-3.4了)
$ which gcc-3.4
/usr/bin/gcc-3.4
// 编译
$ make
// 正常情况下,你应该可以看到两个新的文件Image和System.map已经生成了
$ ls
boot  fs  Image  include  init  kernel  lib  Makefile  mm  System.map  tools


    Image文件就是我们编译后的linux-0.11内核,如何使用它呢?下面一节将进行介绍。
    这里简单介绍一下补丁的内容,补丁是在赵老师提供的linux-0.11-040327-rh9.tar.gz文件的基础上修改的,具体修改的地方,大家可以从附件linux-0.11-080529-rh9-to-ubuntu8.04.patch看到。

    如果想直接编译最原始的linux-0.11源代码呢?书中介绍了一个sls-0.99pl系统,可以从bochs的官方站点[6]下载到,通过 bochs把该系统启动后就可以用来编译linus当初(1991年,想一想都是17年前的事情了,光阴似箭阿!)写的linux-0.11的源代码。原书已经详细介绍了使用方法,这里不再深入介绍。

    注:上面忘记提到我的实验机器的处理器类型为(AMD Athlon(tm)),因为linux-0.11是为x86写的,所以如果想直接在自己的主机上编译和运行它,请确保你的处理器与x86兼容,比如 Intel或者是AMD产的处理器。否则,你得构建目标处理器架构(--target)为x86的交叉编译器并用qemu等仿真器来构建一个x86的实验环境。

3、搭建运行环境

    考虑到实验的方便,这里不直接在真实的硬件上运行编译好的linux-0.11内核,而是用bochs这个“虚拟机”来跑。bochs是一个仿真器,能够仿真x86的硬件环境。在ubuntu 8.04下可以直接安装它,这里把一些相关的文档和工具都安装上。

$ sudo apt-get install bochs vgabios bochs-x bochsbios bochs-doc



    这样一个“虚拟”的机器就免费“买”来了,下面介绍如何通过它来运行linux-0.11内核。

    在上一节中我们已经编译好了linux-0.11的内核,不过为了能够完整地运行它,我们还得为它提供一个文件系统,这个文件系统主要提供各种相关的工具,其中包括用户和内核交互的接口——shell。

    为了简单起见,这里直接采用赵老师提供的linux-0.11-devel-060625.zip文件中的hdc-0.11-new.img硬盘映像文件作为我们的文件系统。这里先下载该文件。

$ wget -c http://mirror.lzu.edu.cn/os/oldlinux.org/bochs/linux-0.11-devel-060625.zip
$ unzip linux-0.11-devel-060625.zip
$ ls linux-0.11-devel-060625/hdc-0.11-new.img
linux-0.11-devel-060625/hdc-0.11-new.img


   
    现在我们有了linux-0.11的内核和相应的文件系统以及运行它的bochs“虚拟机”,这样就可以运行该内核了。不过运行内核之前需要通过一个文件作一些配置。配置的目的主要是为了告知“虚拟机”我们想从什么位置加载linux-0.11的内核和文件系统。这里是一份配置文件,命名为 bochsrc-hd.bxrc(见附件)。

    首先先确保如下两个配置正确。第一行告知bochs要从第一个软盘floppya加载内核,这里通过linux-0.11目录下的虚拟软盘映像文件 Image指定;第二行告知bochs要从第一个硬盘加载文件系统,它通过./linux-0.11-devel-060625/hdc-0.11- new.img磁盘映像文件指定。

floppya: 1_44="./linux-0.11/Image", status=inserted
ata0-master: type=disk, path="./linux-0.11-devel-060625/hdc-0.11-new.img", mode=flat, cylinders=410, heads=16, spt=38



    需要补充的是:linux-0.11内核自身也需要知道文件系统所在位置,否则内核加载以后将不知道从哪里启动根文件系统。而这个位置通过linux-0.11/tools/build.c文件中的如下两行指定:

#define DEFAULT_MAJOR_ROOT 3
#define DEFAULT_MINOR_ROOT 1



    这两行实际上对应编译过后的Image文件中的第509、510个字节,它告知linux-0.11内核从哪里加载文件系统。

$ hexdump -s 508 -n 2 linux-0.11/Image
00001fc 0301                                  
00001fe



    0301表示第一个硬盘的第一个分区,刚好对应ata0-master。如果需要从不同的位置加载文件系统,请参考原书的第14章的“根文件系统和根文件设备"一节,调整源代码中DEFAULT_MAJOR_ROOT和DEFAULT_MINOR_ROOT或者是在编译好linux-0.11内核后,直接通过二进制编辑器hexedit修改Image文件中的第509和510个字节处的内容。

    关于bochs配置文件的更多细节,也请参考原书,或者直接查看"man bochsrc"。

    现在,我们可以通过下面的命令运行linux-0.11的内核了,其中-f参数用于指定配置文件bochsrc-hd.bxrc。

$ bochs -f bochsrc-hd.bxrc



4、搭建调试环境

    在linux下,如果编译bochs之前带上了--enable-gdb-stub参数进行配置,那么就可以把gdbstub编译进bochs。 gdbstub可以使得bochs程序在本地指定网络端口侦听接收gdb的命令,它的工作原理跟gdbserver类似,是一个调试服务器。当启动该 gdbstub后,我们可以通过gdb和它进行通信,协同调试linux内核。不过在调试之前,需要修改linux 0.11的编译参数,确保产生一个带有调试信息的内核文件。

    下面介绍大概的步骤。

4.1 重新编译linux-0.11的内核

    编译之前需要修改所有Makefile文件,确保去除LDFLAGS中的-s参数,并在CFLAGS中添加-g参数,这样就可以让最终产生的内核文件中带有调试信息,以便用gdb来调试它。不过,因为通过bochs运行的内核映像文件的大小受到boot/bootsect.s文件中SYSSIZE大小的限制(可以考虑直接增加SYSSIZE的大小),所以可以考虑生成两份内核映像文件,一份用于bochs加载;一份用于gdb来调试,因此linux- 0.11主目录下的Makefile文件还需要进行修改。为了方便,我把这些修改都放到了附件linux-0.11-080529- ubuntu8.04-dbg.patch。
    这里重新编译内核:

// 从附件中下载linux-0.11-080529-ubuntu8.04-dbg.patch.tar.gz并解压
$ tar zxf linux-0.11-080529-ubuntu8.04-dbg.patch.tar.gz
// 进入打过补丁linux-0.11-080529-ubuntu8.04.patch的linux-0.11
$ cd linux-0.11
// 打上用于 编译产生带有调试信息内核 的补丁
$ patch -p1 < ../linux-0.11-080529-ubuntu8.04-dbg.patch
// 重新编译
$ make clean
$ make



    编译好以后得到一个不带调试信息的Image文件和一个带调试信息的tools/system文件,前者用于bochs启动,而后者用于gdb调试。

4.2 重新编译bochs确保编译进gdbstub,并确保已经安装了gdb

    貌似ubuntu 8.04下默认安装的bochs没有编译进gdbstub,所以重新编译一个。从资料[6]下载最新版的bochs,解压、编译。

// 下载并解压
$ wget -c http://bochs.sourceforge.net/cvs-snapshot/bochs-20080527.tar.gz
$ tar zxf bochs-20080527.tar.gz
// 配置和编译,配置时记得加上--enable-gdb-stub以及--enable-plugins和 --enable-disasm
$ cd ./bochs-20080527
$ ./configure  --enable-plugins --enable-disasm --enable-gdb-stub
$ make



    如果配置时提示缺少X window libraries, 那么请把xorg-dev这个包安装上看看,如果还不行,把xserver-xorg-dev这个包也安装上。
    编译好带有gdbstub的bochs后,需要确保已经安装了gdb。

$ sudo apt-get install gdb



4.3 调试

    调试时,需要调整bochs的配置文件,以便告知bochs,让它在启动linux-0.11内核时在指定端口开启gdbstub,并暂停在linux-0.11内核的开头,等待用户开启gdb调试器对它发起连接。
    在原配置文件的开头添加如下一行,并命名为bochsrc-hd-dbg.bxrc:

gdbstub: enabled=1, port=1234, text_base=0, data_base=0, bss_base=0


    上面一行中的“port=1234”指定gdbstub的端口。你可以设置为任意一个当前没有没有被占用的端口。
    另外,请把如下一行删除或者注册掉,因为最新版本的bochs貌似不支持这个标记。

floppy_command_delay: 50000


   
    下面,先开启一个终端根据新的配置文件,用bochs启动linux-0.11内核。

// 自己注意一下编译后的bochs的路径以及bochsrc-hd-dbg.bxrc文件的路径
$ ./bochs-20080527/bochs -f bochsrc-hd-dbg.bxrc
...
Waiting for gdb connection on port 1234


    正常bochs启动后,根据提示按下数字6,即可看到最后一行信息:bochs等待用户开启gdb调试器客户端对它发起连接。下面,另开一个终端运行gdb。

// 用gdb启动编译好的带有调试信息的内核文件:tools/system
$ gdb linux-0.11/tools/system
...
(gdb) break main
(gdb) target remote localhost:1234    //连接bochs开启的gdbstub的1234端口开始调试
(gdb) c                     // 这里不要直接单步,先执行到内核部分再说(因为开头有一部分是引导部分),详细原因见资料[14]的后面部分。
(gdb) si                    // 单步调试(指令级别的),后续用法参考gdb首页就okay了


    关于使用bochs和gdb调试内核的方法,你还可以参考一下资料[13]。
    到这里为止,相应的环境就搭建完毕了。

    下面再列出几则资料,生成补丁和打补丁的工具diff和patch的用法见资料[7],gdb以及gdb远程调试的用法见资料[8]。

补充和更新

1、在64位的ubuntu/debian上编译linux-0.11(update: 2008-09-24)

之前介绍的是在32位的Intel或者amd的机器上编译linux-0.11的方法,没有介绍64位的,这里新增了一个补丁linux-0.11- 080924-debian-amd64.patch,把该补丁打到最原始的linux-0.11的源代码上,我们就可以在64位的Intel或者amd 的机器上编译它了。关于补丁的细节,大家可以阅读一下资料[9,15]。

2、在bochs-2.3中遇到HD controller not ready而无法启动的问题(update: 2008-10-27)

请参考网友在3#的回复,这里对该网友表示感谢。

3、如何使用另外一个虚拟机qemu(update: 2008-10-27)

3.1 引导linux-0.11,就这么简单,比bochs简单得多

$ qemu -m 16 -boot a -fda linux-0.11/Image -hda rootfs/hdc-0.11-new.img



注意:在qemu中也需要参考网友在3#的回复,修改kernel/blk_drv/hd.c中的代码,否则,也会提示相同的错误而无法引导linux-0.11。

3.2 调试linux-0.11

启动的时候,可以用图形的方式,也可以用非图形的方式,例如,这里用后者:

$ qemu -boot a -fda linux-0.11/Image -hda rootfs/hdc-0.11-new.img -s -S -nographic -serial '/dev/ttyS0'


qemu貌似直接开始在1234端口监听,然后类似原blog的方法用gdb来连接该端口以便对linux-0.11进行调试。

注意:有些版本的qemu还需要添加-no-kqemu,如果没有安装qemu的加速器的话。另外,关于使用qemu调试内核你还可以参考资料[10,11,12]。

4、把linux-0.11移植到最新的gcc 4.3.2中(update: 2008-10-30)

你可以从资料[14]的附件下载该代码,或者从这里下载该代码对应的完整的实验环境:
ftp://mirror.lzu.edu.cn/software/linux-0.11/
关于移植的细节,请并参考资料[14],并直接对比分析源代码,其实修改的部分非常少。不过我对大部分的Makefile文件进行了调整。

5、发布同时支持gcc 3.4, 4.1, 4.2, 4.3的linux-0.11(update: 2008-10-30)

请直接从ftp://mirror.lzu.edu.cn/software/linux-0.11/下载,包括纯源代码部分 linux-0.11-081030.tar.gz和完整的实验环境部分linux-0.11-dev-081030.tar.gz
搭建linux-0.11(0.95)源代码的阅读、编译、运行和调试环境

(上接 "《Linux内核完全注释》阅读笔记——资料准备")

    这里将详细介绍如何在ubuntu 8.04下阅读、编译、运行和调试linux-0.11(0.95)。选择ubuntu 8.04的理由很简单:开放源代码,可免费获得,使用方便……
    该阅读笔记主要参考《Linux内核完全注释》的第14章。

1、搭建阅读环境

    首先需要安装ubuntu 8.04,关于该linux发行版的安装和使用办法,建议到ubuntu china的官方[1]转一转。安装好ubuntu 8.04以后,基本的工具都有了。不过为了能够更好地阅读源代码,还是建议确保把vim,cscope,ctags等工具都安装上了,vim是一款“古典 ”而又有“超级牛力”的编辑器,cscope和ctags是两款非常友善的代码阅读辅助工具,在ubuntu 8.04下,都可以直接结合vim使用。

$ sudo apt-get install vim cscope exuberant-ctags



    关于vim, cscope, ctags的用法,由于时间关系,这里不便详细介绍,请分别参考资料[2],[3],[4]。

2、搭建编译环境

    在ubuntu下,安装C语言开发环境(主要是gnu的一些Toolchains)还是蛮简单的,直接把build-essential这个虚拟包安装上即可。

$ sudo apt-get install build-essential



    不过上述软件包中并未包含as86和ld86,这两个工具用于编译和链接linux-0.11的boot目录下汇编语言文件bootsect.s和 setup.s,它们采用as86汇编语法,而linux-0.11下的其他汇编语言文件采用gas的语法(AT&T),所以我们还需要单独安装包含as86和ld86的软件包bin86。
   

// 查找as86和ld86两个工具所在的软件包
$ apt-cache search as86 ld86
bin86 - 16-bit x86 assembler and loader
// 安装该软件包
$ apt-get install bin86



    如果想把相关的文档也安装上,请参考资料[5]。

    不过需要特别注意的是:默认安装的gcc版本是4.0以上,而这些版本可能引入了一些新的特性,在使用时总会遇到一些问题,因此在后续的所有实验中我们将采用更早的一个版本,即gcc 3.4版。下面把gcc-3.4版安装上,并把gcc文件链接到该版本。

$ sudo apt-get install gcc-3.4
$ which gcc-3.4 gcc
/usr/bin/gcc-3.4
/usr/bin/gcc
$ sudo ln -sf /usr/bin/gcc-3.4 /usr/bin/gcc
$ gcc --version | sed -n -e "1p"
gcc (GCC) 3.4.6 (Ubuntu 3.4.6-6ubuntu5)



    这个环境搭建好以后就可以编译linux-0.11的源代码了,不过如果想在ubuntu 8.04下直接编译它,还得打上赵老师提供的补丁,不过赵老师提供的补丁在redhat 9.0下实验通过,而在ubuntu 8.04下则不能直接使用,所以经过实验,我重新做了一个linux-0.11在ubuntu 8.04下能正常编译通过的补丁,即附件中的linux-0.11-080529-ubuntu8.04.patch。
    下面介绍具体的编译过程。

// 下载linux-0.11的源代码并解压
$ wget -c http://mirror.lzu.edu.cn/os/oldlinux.org/kernel/0.1x/linux-0.11.tar.gz
$ tar zxf linux-0.11-080529-ubuntu8.04.patch.tar.gz
$ tar zxf linux-0.11.tar.gz
// 打上linux-0.11-080529-ubuntu8.04.patch补丁
$ cd linux-0.11
$ patch -p1 < ../linux-0.11-080529-ubuntu8.04.patch
// 确保gcc-3.4版已经安装上(为确保使用gcc的3.4版,该补丁已经直接在所有Makefile文件中指定CC为gcc-3.4了)
$ which gcc-3.4
/usr/bin/gcc-3.4
// 编译
$ make
// 正常情况下,你应该可以看到两个新的文件Image和System.map已经生成了
$ ls
boot  fs  Image  include  init  kernel  lib  Makefile  mm  System.map  tools


    Image文件就是我们编译后的linux-0.11内核,如何使用它呢?下面一节将进行介绍。
    这里简单介绍一下补丁的内容,补丁是在赵老师提供的linux-0.11-040327-rh9.tar.gz文件的基础上修改的,具体修改的地方,大家可以从附件linux-0.11-080529-rh9-to-ubuntu8.04.patch看到。

    如果想直接编译最原始的linux-0.11源代码呢?书中介绍了一个sls-0.99pl系统,可以从bochs的官方站点[6]下载到,通过 bochs把该系统启动后就可以用来编译linus当初(1991年,想一想都是17年前的事情了,光阴似箭阿!)写的linux-0.11的源代码。原书已经详细介绍了使用方法,这里不再深入介绍。

    注:上面忘记提到我的实验机器的处理器类型为(AMD Athlon(tm)),因为linux-0.11是为x86写的,所以如果想直接在自己的主机上编译和运行它,请确保你的处理器与x86兼容,比如 Intel或者是AMD产的处理器。否则,你得构建目标处理器架构(--target)为x86的交叉编译器并用qemu等仿真器来构建一个x86的实验环境。

3、搭建运行环境

    考虑到实验的方便,这里不直接在真实的硬件上运行编译好的linux-0.11内核,而是用bochs这个“虚拟机”来跑。bochs是一个仿真器,能够仿真x86的硬件环境。在ubuntu 8.04下可以直接安装它,这里把一些相关的文档和工具都安装上。

$ sudo apt-get install bochs vgabios bochs-x bochsbios bochs-doc



    这样一个“虚拟”的机器就免费“买”来了,下面介绍如何通过它来运行linux-0.11内核。

    在上一节中我们已经编译好了linux-0.11的内核,不过为了能够完整地运行它,我们还得为它提供一个文件系统,这个文件系统主要提供各种相关的工具,其中包括用户和内核交互的接口——shell。

    为了简单起见,这里直接采用赵老师提供的linux-0.11-devel-060625.zip文件中的hdc-0.11-new.img硬盘映像文件作为我们的文件系统。这里先下载该文件。

$ wget -c http://mirror.lzu.edu.cn/os/oldlinux.org/bochs/linux-0.11-devel-060625.zip
$ unzip linux-0.11-devel-060625.zip
$ ls linux-0.11-devel-060625/hdc-0.11-new.img
linux-0.11-devel-060625/hdc-0.11-new.img


   
    现在我们有了linux-0.11的内核和相应的文件系统以及运行它的bochs“虚拟机”,这样就可以运行该内核了。不过运行内核之前需要通过一个文件作一些配置。配置的目的主要是为了告知“虚拟机”我们想从什么位置加载linux-0.11的内核和文件系统。这里是一份配置文件,命名为 bochsrc-hd.bxrc(见附件)。

    首先先确保如下两个配置正确。第一行告知bochs要从第一个软盘floppya加载内核,这里通过linux-0.11目录下的虚拟软盘映像文件 Image指定;第二行告知bochs要从第一个硬盘加载文件系统,它通过./linux-0.11-devel-060625/hdc-0.11- new.img磁盘映像文件指定。

floppya: 1_44="./linux-0.11/Image", status=inserted
ata0-master: type=disk, path="./linux-0.11-devel-060625/hdc-0.11-new.img", mode=flat, cylinders=410, heads=16, spt=38



    需要补充的是:linux-0.11内核自身也需要知道文件系统所在位置,否则内核加载以后将不知道从哪里启动根文件系统。而这个位置通过linux-0.11/tools/build.c文件中的如下两行指定:

#define DEFAULT_MAJOR_ROOT 3
#define DEFAULT_MINOR_ROOT 1



    这两行实际上对应编译过后的Image文件中的第509、510个字节,它告知linux-0.11内核从哪里加载文件系统。

$ hexdump -s 508 -n 2 linux-0.11/Image
00001fc 0301                                  
00001fe



    0301表示第一个硬盘的第一个分区,刚好对应ata0-master。如果需要从不同的位置加载文件系统,请参考原书的第14章的“根文件系统和根文件设备"一节,调整源代码中DEFAULT_MAJOR_ROOT和DEFAULT_MINOR_ROOT或者是在编译好linux-0.11内核后,直接通过二进制编辑器hexedit修改Image文件中的第509和510个字节处的内容。

    关于bochs配置文件的更多细节,也请参考原书,或者直接查看"man bochsrc"。

    现在,我们可以通过下面的命令运行linux-0.11的内核了,其中-f参数用于指定配置文件bochsrc-hd.bxrc。

$ bochs -f bochsrc-hd.bxrc



4、搭建调试环境

    在linux下,如果编译bochs之前带上了--enable-gdb-stub参数进行配置,那么就可以把gdbstub编译进bochs。 gdbstub可以使得bochs程序在本地指定网络端口侦听接收gdb的命令,它的工作原理跟gdbserver类似,是一个调试服务器。当启动该 gdbstub后,我们可以通过gdb和它进行通信,协同调试linux内核。不过在调试之前,需要修改linux 0.11的编译参数,确保产生一个带有调试信息的内核文件。

    下面介绍大概的步骤。

4.1 重新编译linux-0.11的内核

    编译之前需要修改所有Makefile文件,确保去除LDFLAGS中的-s参数,并在CFLAGS中添加-g参数,这样就可以让最终产生的内核文件中带有调试信息,以便用gdb来调试它。不过,因为通过bochs运行的内核映像文件的大小受到boot/bootsect.s文件中SYSSIZE大小的限制(可以考虑直接增加SYSSIZE的大小),所以可以考虑生成两份内核映像文件,一份用于bochs加载;一份用于gdb来调试,因此linux- 0.11主目录下的Makefile文件还需要进行修改。为了方便,我把这些修改都放到了附件linux-0.11-080529- ubuntu8.04-dbg.patch。
    这里重新编译内核:

// 从附件中下载linux-0.11-080529-ubuntu8.04-dbg.patch.tar.gz并解压
$ tar zxf linux-0.11-080529-ubuntu8.04-dbg.patch.tar.gz
// 进入打过补丁linux-0.11-080529-ubuntu8.04.patch的linux-0.11
$ cd linux-0.11
// 打上用于 编译产生带有调试信息内核 的补丁
$ patch -p1 < ../linux-0.11-080529-ubuntu8.04-dbg.patch
// 重新编译
$ make clean
$ make



    编译好以后得到一个不带调试信息的Image文件和一个带调试信息的tools/system文件,前者用于bochs启动,而后者用于gdb调试。

4.2 重新编译bochs确保编译进gdbstub,并确保已经安装了gdb

    貌似ubuntu 8.04下默认安装的bochs没有编译进gdbstub,所以重新编译一个。从资料[6]下载最新版的bochs,解压、编译。

// 下载并解压
$ wget -c http://bochs.sourceforge.net/cvs-snapshot/bochs-20080527.tar.gz
$ tar zxf bochs-20080527.tar.gz
// 配置和编译,配置时记得加上--enable-gdb-stub以及--enable-plugins和 --enable-disasm
$ cd ./bochs-20080527
$ ./configure  --enable-plugins --enable-disasm --enable-gdb-stub
$ make



    如果配置时提示缺少X window libraries, 那么请把xorg-dev这个包安装上看看,如果还不行,把xserver-xorg-dev这个包也安装上。
    编译好带有gdbstub的bochs后,需要确保已经安装了gdb。

$ sudo apt-get install gdb



4.3 调试

    调试时,需要调整bochs的配置文件,以便告知bochs,让它在启动linux-0.11内核时在指定端口开启gdbstub,并暂停在linux-0.11内核的开头,等待用户开启gdb调试器对它发起连接。
    在原配置文件的开头添加如下一行,并命名为bochsrc-hd-dbg.bxrc:

gdbstub: enabled=1, port=1234, text_base=0, data_base=0, bss_base=0


    上面一行中的“port=1234”指定gdbstub的端口。你可以设置为任意一个当前没有没有被占用的端口。
    另外,请把如下一行删除或者注册掉,因为最新版本的bochs貌似不支持这个标记。

floppy_command_delay: 50000


   
    下面,先开启一个终端根据新的配置文件,用bochs启动linux-0.11内核。

// 自己注意一下编译后的bochs的路径以及bochsrc-hd-dbg.bxrc文件的路径
$ ./bochs-20080527/bochs -f bochsrc-hd-dbg.bxrc
...
Waiting for gdb connection on port 1234


    正常bochs启动后,根据提示按下数字6,即可看到最后一行信息:bochs等待用户开启gdb调试器客户端对它发起连接。下面,另开一个终端运行gdb。

// 用gdb启动编译好的带有调试信息的内核文件:tools/system
$ gdb linux-0.11/tools/system
...
(gdb) break main
(gdb) target remote localhost:1234    //连接bochs开启的gdbstub的1234端口开始调试
(gdb) c                     // 这里不要直接单步,先执行到内核部分再说(因为开头有一部分是引导部分),详细原因见资料[14]的后面部分。
(gdb) si                    // 单步调试(指令级别的),后续用法参考gdb首页就okay了


    关于使用bochs和gdb调试内核的方法,你还可以参考一下资料[13]。
    到这里为止,相应的环境就搭建完毕了。

    下面再列出几则资料,生成补丁和打补丁的工具diff和patch的用法见资料[7],gdb以及gdb远程调试的用法见资料[8]。

补充和更新

1、在64位的ubuntu/debian上编译linux-0.11(update: 2008-09-24)

之前介绍的是在32位的Intel或者amd的机器上编译linux-0.11的方法,没有介绍64位的,这里新增了一个补丁linux-0.11- 080924-debian-amd64.patch,把该补丁打到最原始的linux-0.11的源代码上,我们就可以在64位的Intel或者amd 的机器上编译它了。关于补丁的细节,大家可以阅读一下资料[9,15]。

2、在bochs-2.3中遇到HD controller not ready而无法启动的问题(update: 2008-10-27)

请参考网友在3#的回复,这里对该网友表示感谢。

3、如何使用另外一个虚拟机qemu(update: 2008-10-27)

3.1 引导linux-0.11,就这么简单,比bochs简单得多

$ qemu -m 16 -boot a -fda linux-0.11/Image -hda rootfs/hdc-0.11-new.img



注意:在qemu中也需要参考网友在3#的回复,修改kernel/blk_drv/hd.c中的代码,否则,也会提示相同的错误而无法引导linux-0.11。

3.2 调试linux-0.11

启动的时候,可以用图形的方式,也可以用非图形的方式,例如,这里用后者:

$ qemu -boot a -fda linux-0.11/Image -hda rootfs/hdc-0.11-new.img -s -S -nographic -serial '/dev/ttyS0'


qemu貌似直接开始在1234端口监听,然后类似原blog的方法用gdb来连接该端口以便对linux-0.11进行调试。

注意:有些版本的qemu还需要添加-no-kqemu,如果没有安装qemu的加速器的话。另外,关于使用qemu调试内核你还可以参考资料[10,11,12]。

4、把linux-0.11移植到最新的gcc 4.3.2中(update: 2008-10-30)

你可以从资料[14]的附件下载该代码,或者从这里下载该代码对应的完整的实验环境:
ftp://mirror.lzu.edu.cn/software/linux-0.11/
关于移植的细节,请并参考资料[14],并直接对比分析源代码,其实修改的部分非常少。不过我对大部分的Makefile文件进行了调整。

5、发布同时支持gcc 3.4, 4.1, 4.2, 4.3的linux-0.11(update: 2008-10-30)

请直接从ftp://mirror.lzu.edu.cn/software/linux-0.11/下载,包括纯源代码部分 linux-0.11-081030.tar.gz和完整的实验环境部分linux-0.11-dev-081030.tar.gz

你可能感兴趣的:(kernel,linux内核,ubuntu,makefile,image,gcc,工具)