导航:首页 > 源码编译 > 怎么把ramdirk编译进内核

怎么把ramdirk编译进内核

发布时间:2023-08-26 04:17:07

A. 怎样在linux系统下直接打开移动硬盘

的一个非常好的文章可以清楚地解释如何启动火线和USB设备 Linux操作系统的原理。

希望它在对任何有兴趣把Linux操作系统安装到外部设备的人有所帮助。
原始的网址

从火线设备上启动Linux

可移动驱动器上安装Linux操作系统

难度等级:中等

Martyn Honeyford([email protected]) IBM英国实验室 软件工程师
宣可达([email protected])翻译 webzi@linuxsir

2004年7月15日
2005年7月26日开始翻译,7月28日完成。
翻译经验不多。如有不妥,欢迎EMAIL交流。

使用一个外部驱动器是一个极棒的方法,能给你的老硬件带来新生和让你在你不能(或者不想)改变内置硬盘的计算机上使用Linux系统。
假设你想使用Linux在一个双启动环境,但是你的计算机硬盘又没有任何空余的空间。一种解决方法是使用"live"的linux发行版本象是Knoppix,他们这能直接从CD启动运行。 对于偶尔使用,这是一种可行的办法,但是它有若干的劣势:

*你将会仍然需要些固定文件存储。如果你只是操作少量的文件,一张1.44MB的磁盘就可以胜任,或者一个USB闪存棒适合中等量的文件,但是这些都不够理想。
*当使用一个LiveCD 的时候,最困难、最糟糕、最不可能的是安装你自己的应用程序或者定制现存的程序。
*使用LiveCD在性能上的牺牲,在启动初所有的设备检测时尤为明显,同样发生使用中(所有的文件从 CD 载入通常是比从硬盘中载入慢的多)。

的确,还有其他可选方案。举例来说,你可以买额外的内置驱动器并且在此安装Linux操作系统。但是常常,你可能没有任何空闲的扩展阜。(这特别容易发生在笔记本上,通常他们只允许一个内置硬盘。)

或者,你可以使用一个较大的硬盘取代当前的硬盘, 获得额外空间用于安装 Linux操作系统。 然而,这的确是一个耗费大量时间的方案,需要你重新安装现有的操作系统在新的硬盘, 重新安装和配置你所有应用程序, 和恢复所有数据。

更好的解决方案是购买一个外置硬盘并安装 Linux操作系统。 这样使得你在想使用Linux系统时候不必涉及现有的硬件和软件而只是简单连接外部驱动器。

可选的可移动设备

可用于安装Linux操作系统设备涵盖磁盘驱动器、USB-闪存设备、通过USB/火线连接的硬盘等等。

在一个小容量的设备中安装linux是可行的,例如在一个1.44MB的磁盘或者一个32MB的USB棒中,他们通常(必须)为特定目的定制,采用裁减的发行版本,例如,拯救中断的安装过程。

外置的硬盘在为使用一个常规目的的linux系统提供最大的灵活性同时,带来一个合理的成本。

许多不同的厂商提供许多种不同容量的外置的驱动器。 (Maxtor, 西西部数据, 等等)。这些驱动器还会包含一个外置盒子,用于固定标准的 3-1/2 寸或 2-1/2 寸 IDE 硬盘。 然后这些驱动器经由 USB 或 IEEE1394(火线) 连接到计算机。

USB 受到在二个主要的版本中的影响,1.1 和 2.0. 1.1 版速度为12 Mbit/ s(每秒1Mbit) ,而 2.0 版支持最高达到 480 Mbit/s 的传输速度。 大多数2.0相容的驱动器也向后兼容1.1,通常建议尽量不要采用1.1接口除非没有其他的选择(因为其低速不适应此环境。)

火线标准也定义若干不同的速度, 实际上,大部分人所指的FireWire ,是“FireWire400”标准 ,支持最大传输速度为 400 Mbit/s 。

USB2.0和火线在速度上不分伯仲: 虽然 USB 2.0 有比较高的传输速度, 但是实际中因为协议的不同两者速度十分的接近。 如果你的计算机拥有2种接口, 最好使用USB而非火线(理由我将后将解释), 但是如果只有火线接口,当然你就选择它了。为了实现最大的灵活性, 可以选择众多同时支持 USB 2.0 和火线的驱动器中的一种。(像我稍后将在这一个文章中使用的那个一样。)

对于那些没有必须的接口, PCI(对于桌面) 和 PCMCIA(对于笔记本型电脑) ,现在火线和USB 2.0扩展卡也并非贵不可及: 举例来说, 我稍后将在文章中提及PCMCIA火线扩展卡大约为10英镑.($20 美元以下)

为了达到本文的目的,我已经购买 5-1/4寸外置驱动器的硬盘盒。 这是一件非常灵活的硬盘盒,并没提供驱动器而且能固定任何的标准 IDE 设备,包括 3-1/2 寸驱动器和像CD-RW/DVD-RW等5-1/4 寸 IDE 设备 。硬盘盒兼有 USB 2.0 和火线接口。

为了把硬盘盒连接到我的IBM Thinkpad T30笔记本电脑,我也购买了一个 PCMCIA 火线转接卡。 ( 因为内置的USB 接口只支持USB 1.1)

硬盘盒和火线转接卡相对比较便宜。 (大约分别为50英镑和10英镑。)

测试期间, 我把一个手边闲置的13 GB 3-1/2 寸 IDE 硬盘放进硬盘盒——对于真实情况,我会买一个较大的容量驱动器, 现在另购一个硬盘相当低廉( 大约每个50英镑!)

Linux 支持

正如你所期待,linux对这些硬盘盒支持的确非常好。任何遵从SBP(串行总线协议)标准的大储存设备在linux中使用非常简单。

大体上, 使对这些装置的支持你能够将会需要在你的核心中支持某些选项( 或直接地编译或通过模块。)

对于USB和火线,SBP 装置通过SCSI模拟来实现-- 也就是说,Linux会把他们当作SCSI硬盘来处理 。 这是在 Linux 世界里面使用存储设备的一个常规方法。 ( 举例来说, IDE CD/DVD设备通常通过SCSI模拟来连接)。基于以上原因,下列的选项需要被内核支持:

* SCSI support
* SCSI emulation
* SCSI disk support

除此之外,不同连接方式需要一下的内核支持:

* 针对火线:
* IEEE1394 support
* OHCI1394 support
* RAW1394 support
* SBP-2 support

* 针对USB:
*(host-side) USB support
* OHCI support
* UHCI support
* USB mass-storage support

明显地,你还必须为其他的硬件 ( 如显卡等等)编译常规的支持, 而且可能需要一些额外的模块,取决你的具体硬件。

举例来说,我正在使用 PCMCIA(cardbus) 火线转接卡,因此,我还需要增加:

* PCMCIA support
* cardbus support

安装

现在我们有很完美外置驱动器,我们将开始安装在其安装Linux美妙之旅。

目前最简单的安装linux方法(当然仅个人意见) , 是连接你的所有硬件;(我的情况是,插入火线转接卡,连上转接线盒驱动器,然后打开驱动器的电源) 然后从你选择的发行版安装CD上启动你的计算机。

我采用的发行版是Gentoo(资源详见链接),因此,我用了最新的 “通用”x86 LiveCD。 (2004.1) 其他的发行版本必须的步骤大致和此相似。

一旦你使用安装CD启动,要借由一点运气让他要辨认出你的驱动器。 磁盘应该出现在/dev/sdX, X 是一个小写字母从“a”开始。 在我的系统上,外置硬盘被当做 /dev/sda, 但是如果你有其他的 SCSI硬盘,这数字将会改变;( 或模拟了SCSI硬盘) 那种情况下,它可能是 /dev/sdb 或一些其他的字母。 如果你的驱动器不能被自动检测到, 就需要进一步采取措施 -- 举例来说,你可能必须打开启动选项使用火线或者PCMCIA接口, 或你可能必须手动装载一些内核模块 , 或其他一类选项。 (资源详见故障发现与维修指导链接)

一旦驱动器被辨认出来,安装过程种其运作起来就像一个内置的硬盘。然后就你可以对其分区并且用常规方法安装linux。

有一句话我着重要提醒,小心选择何处安装boot loader(通常是GRUB和LILO)--我建议不要装到主引导记录(MBR)中( 通常是默认值) 而是装到外置驱动器的根分区 ( 或/boot分区,如果你单独分了一个话)。

既然我们已经安装 Linux 在这个设备上,我们想要从上面启动它。 事情到此开始变的有点复杂了。

启动

在我前讨论在如何的新驱动器上面启动,我要讲解一些boot loader的小知识。

boot loader程序通常安装在计算机的第一个硬盘的MBR上。 当boot loader被调用 (BIOS自动地运行MBR里的代码),它通常显示一份可启动操作系统的菜单。以便选择一个给定的操作系统启动计算机。

两件细节在这个章节中应该注意:

* 操作系统选择菜单(通常)从磁盘中载入。
*为了启动有关的操作系统, boot loader 需要从磁盘中读取相关的内核。

在操作系统被装载之前 ,以上各步骤已经执行,这意味着所有的磁盘读取在BIOS调用时。 这是一个必须的前提,即,为了直接启动磁盘,你的 BIOS必须支持通过火线或USB被连接的磁盘。通常能在BIOS中看到关于从这些设备上启动选项。 火线BIOS支持现在的确非常的少见,但是 USB 支持正在变得相当的平常。 因此,如果你正在使用一部相对比较新的计算机上的USB接口,应该可以直接启动驱动器进Linux。

当经由 USB 连接,在安装外部的驱动器的 MBR 的幼虫之后,我能够直接地启动它。 当以被连接的磁盘片启动的时候,只是进入 BIOS 装备公用程序。 外部的磁盘片将会出现如一个一般的硬盘: 移动它,如此它在启动次序中的内在驱动器之前。

我也能够在一个内置的硬盘的MBR上安装一个boot loader而且使用其启动USB硬盘(在GRUB中被成为hd1)。 如果你正在使用火线, 有可能你的 BIOS 将会无法直接地启动硬盘,而且你需要更多一点步骤。

幸运的是,由于 Linux 的多样性,这有非常容易解决,如果你不能直接地启动,( 我就是这样的情况,使用一个PCMCIA转接卡!) 你能运行初始启动步骤,来自一个支持的设备 , 像是一台软驱,CD-ROM,USB棒,或在主硬盘上的小分区, 然后使用外部的驱动器继续其他步骤。

创建一个启动镜像

我们有2种方法启动:

*单阶启动
内核启动, 挂载根分区文件系统, 接着调用初始化教本继续初始化( 通常是/sbin/init)
*双阶启动 (initrd)的启动
内核启动,挂载一个初始ram disk (initrd),进一步运行定制的初始化, 然后挂载根分区文件系统继续初始化(同样, 通常调用/sbin/init)

每种方法都有它自己的优点和缺点。

单阶启动

为了要使用一个单阶的启动,我们需要建立一个内核包含挂载一个根分区文件系统所需的所有驱动程序。( 任何其他的驱动能作为模块编译并在根分区载入时候进行常规初始化。)

如果我们正在从像软盘这样的一个非常小的装置尝试启动, 最好的方式是创建的一个正合适内核,编译进所有挂载根外部分区系统所需驱动 -- 而且编译其他的作为模块。 举例来说,我的内核编译进了SCSI支持, PCMCIA 支持, IEE1394 , SBP ,和其他相似的支持, 但是其他的(包括显卡支持,网络设备支持,等等)当做模块编译并储存在根分区上(在外部的驱动器的),而不是存储在软盘上。

这种方法的主要问题是需要我们给内核源代码打补丁-- 那是一种最糟糕的痛苦(当新的内核发布),而真正的问题是如果补丁没有在维护,这样就不能跟上内核的变化。

你可能以为如果计算机BIOS支持USB和火线直接启动,我们能避免发生以上的2个问题。 不幸地,事情不是这样:这一个方法使用BIOS在启动时调用磁盘,一旦内核开始初始化, BIOS就失去了作用,而且使用内核驱动来调用磁盘-- 所以你仍然会碰到同样的问题。

二阶启动

内核2.0.X版本 ,添加了一个有趣的功能到内核 -- 使用“initial RAM disk(初始内存磁盘)”(or initrd)来实现二阶启动。

简言之,内核一概既往的启动;挂载一个创建在内存里迷你的根分区文件系统取代挂载“真正”的根分区系统。 无论任何命令都在这个初始环境中执行在“真正”的根分区系统被挂载之前直到我们切换到真正的根分区文件系统并销毁初始内存磁盘(initial RAM disk)。

这点在各种环境中都非常有用,但是我们的目标仅仅是简单的利用我们的迷你环境去重新扫描SCSI总线,等待外部驱动器识别,然后用它切换到我们真正的根而后继续启动。

使用这种方法,我们需要创建2个文件,一个内核和一个初始镜像文件。

内核仅是一个内建启动镜像(initrd)支持常规内核。 initrd 镜像是一个包涵我们迷你根分区系统的环路(loopback)文件系统镜像。 (该镜像可以有选折地使用gzip压缩来减小它的大小)。

你能在资源章节里找到关于如何创建和定制你自己的初始镜像的更多信息。

在镜像文件里,有一个linuxrc的文件。当镜像给载入时,该文件自动运行,所以请确定其有运行权限!为了达到我们的目的,linuxrc文件非常的简单:

列举 1. initrd linuxrc

#!/bin/sh
REAL_ROOT=/dev/sda1
# mount the /proc filesystem
mount -t proc none /proc

#for scsi-emulation (SCSI模拟)
# modprobe sd_mod

#for pcmcia (PCNCIA卡)
# modprobe pcmcia_core

#for FireWire (火线)
# modprobe ieee1394
# modprobe ohci1394
# modprobe raw1394
# modprobe sbp2

#for USB (USB)
# modprobe usbcore
# modprobe ohci-hcd
# modprobe uhci-hcd
# modprobe usb-storage

# loop rescanning the scsi bus + rerunning devfsd
retries=5
i=1
until [ -e $REAL_ROOT ]
do
if [ $i -gt $retries ]
then
echo "Unable to mount real root ($REAL_ROOT) - Giving up!"
/bin/ash
exit
fi

echo "Real root ($REAL_ROOT) not found, retrying ($i)"
sleep 1
echo "scsi add-single-device 0 0 0" > /proc/scsi/scsi
echo "scsi add-single-device 1 0 0" > /proc/scsi/scsi
echo "scsi add-single-device 2 0 0" > /proc/scsi/scsi
/bin/devfsd /dev -np
i=$((i+1))
done

#umount /proc as it will be remounted by the normal init process
(解除挂载/proc分区当它会给常规的INIT进程重新挂载)
umount /proc

#now we simply exit, and the normal boot process should continue
(现在我们可以退出了,常规的启动进程将会继续)
exit 0

我们正在做的是载入适当的模块去支持外部驱动器: 请按需注视相应行。 (我把所有需要的支持编译进内核,因此不需要模块)。 然后循环, 再扫描 SCSI 总线 (回应一个命令到/proc虚拟文件系统下一个特别文件并调用devfsd程序) 直到根分区设备出现(我的情况是/dev/sda1 )。在我的情况,被访问的火线模拟SCSI总线是1 0 0,但是并不影响尝试部分其他的总线 -- 如果你知道将会使用哪一个,你可以裁减这个教本。 同时, 如果你有其他的 SCSI 设备 (或模拟 SCSI设备), 驱动器可能有一个不同的字母。(例如,/dev/sdb1) 而且如果你没有使用外置驱动器上的第一个分区, 你将会需要使用一个不同的数字。( 例如,/dev/sda2)

现在我们需要做的全部是复制相关的文件进initrd镜像.( 你能够使用mount -o loop 命令挂载未压缩的镜像)尤其,我们需要确定我们有 linuxrc 文件、所有被用到的命令和其依赖的库。 这个(未挂载的)镜像可以有选折的压缩。

复制内核 (bzImage) 和 initrd 镜像 (initrd.gz)到磁盘。

最后的步是在磁盘上安装一个boot loader, 而且用下列的选项启动内核: kernel bzImage root=/dev/sda1 initrd=initrd.gz.

你现在应该可以使用磁盘来启动了:它会从软盘中载入内核,载入initrd镜像入内存,然后从那里继续常规启动。这点以后,磁盘就可以拿开了。

如果磁盘不合适 ( 例如,计算机没有软驱),任何设备在BIOS能用于启动都可以使用。 个人而言,我就使用一个小小的32MB的USB棒来达到这个目的。
参考资料:

另外,虚机团上产品团购,超级便宜

B. Ubuntu编译了新的内核,进入新内核时一直显示载入Linux 5.6.7,载入初始化内存盘咋回事

概述====1)当内核配置了内存盘时, 内核在初始化时可以将软盘加载到内存盘中作为根盘.当同时配置了初始化内存盘(Initail RAM Disk)时, 内核在初始化时可以在安装主盘之前,通过引导程序所加载的initrd文件建立一个内存初始化盘, 首先将它安装成根文件系统, 然后执行其根目录下的linuxrc 文件,可用于在安装主盘之前加载一些内核模块. 等到linuxrc 程序退出后, 再将主盘安装成根文件系统,并将内存初始化盘转移安装到其/initrd目录下.2)当主盘就是initrd所生成的内存初始化盘时, 不再进行重新安装,在DOS下用loadlin加载的抢救盘就是这种工作方式.3)引导程序所加载的initrd为文件系统的映象文件, 可以是gzip压缩的, 也可以是不压缩的.能够识别的文件系统有minix,ext2,romfs三种.4)当内核的根盘为软盘时,内核初始化时会测试软盘的指定部位是否存在文件系统或压缩文件映象, 然后将之加载或解压到内存盘中作为根盘. 这是单张抢救软盘的工作方式.有关代码========; init/main.c#ifdef CONFIG_BLK_DEV_INITRDkdev_t real_root_dev; 启动参数所设定的根盘设备#endifasmlinkage void __init start_kernel(void){ char * command_line; unsigned long mempages; extern char saved_command_line[]; lock_kernel(); printk(linux_banner); setup_arch(&command_line);arch/i386/kernel/setup.c中,初始化initrd_start和initrd_end两个变量 ...#ifdef CONFIG_BLK_DEV_INITRD if (initrd_start && !initrd_below_start_ok && initrd_start < min_low_pfn << PAGE_SHIFT) { ; min_low_pfn为内核末端_end所开始的物理页号,initrd_start,initrd_end在rd.c中定义 printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - " "disabling it./n",initrd_start,min_low_pfn << PAGE_SHIFT); initrd_start = 0; }#endif ... kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL); 创建init进程 unlock_kernel(); current->need_resched = 1; cpu_idle();}static int init(void * unused){ lock_kernel(); do_basic_setup(); /* * Ok, we have completed the initial bootup, and * we're essentially up and running. Get rid of the * initmem segments and start the user-mode stuff.. */ free_initmem(); unlock_kernel(); if (open("/dev/console", O_RDWR, 0) < 0) printk("Warning: unable to open an initial console./n"); (void) p(0); (void) p(0); /* * We try each of these until one succeeds. * * The Bourne shell can be used instead of init if we are * trying to recover a really broken machine. */ if (execute_command) execve(execute_command,argv_init,envp_init); execve("/sbin/init",argv_init,envp_init); execve("/etc/init",argv_init,envp_init); execve("/bin/init",argv_init,envp_init); execve("/bin/sh",argv_init,envp_init); panic("No init found. Try passing init= option to kernel.");}static void __init do_basic_setup(void){#ifdef CONFIG_BLK_DEV_INITRD int real_root_mountflags;#endif ...#ifdef CONFIG_BLK_DEV_INITRD real_root_dev = ROOT_DEV; ROOT_DEV为所请求根文件系统的块设备 real_root_mountflags = root_mountflags; if (initrd_start && mount_initrd) root_mountflags &= ~MS_RDONLY; else mount_initrd =0; #endif start_context_thread(); do_initcalls(); 会调用partition_setup()中加载内存盘 /* .. filesystems .. */ filesystem_setup(); /* Mount the root filesystem.. */ mount_root(); mount_devfs_fs ();#ifdef CONFIG_BLK_DEV_INITRD root_mountflags = real_root_mountflags; if (mount_initrd && ROOT_DEV != real_root_dev && MAJOR(ROOT_DEV) == RAMDISK_MAJOR && MINOR(ROOT_DEV) == 0) { ; 如果当前根盘为initrd所建立的内存盘 int error; int i, pid; pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD); 创建新的任务去执行程序/linuxrc if (pid>0) while (pid != wait(&i)); 等待linuxrc进程退出 if (MAJOR(real_root_dev) != RAMDISK_MAJOR || MINOR(real_root_dev) != 0) { ; 如果原来的根盘不是0号内存盘,则使用原来的根文件系统, ; 并且将内存盘转移到其/initrd目录下 error = change_root(real_root_dev,"/initrd"); if (error) printk(KERN_ERR "Change root to /initrd: " "error %d/n",error); } }#endif}#ifdef CONFIG_BLK_DEV_INITRDstatic int do_linuxrc(void * shell){ static char *argv[] = { "linuxrc", NULL, }; close(0);close(1);close(2); setsid(); 设置新的session号 (void) open("/dev/console",O_RDWR,0); (void) p(0); (void) p(0); return execve(shell, argv, envp_init);}#endif; arch/i386/kernel/setup.c#define RAMDISK_IMAGE_START_MASK 0x07FF#define RAMDISK_PROMPT_FLAG 0x8000#define RAMDISK_LOAD_FLAG 0x4000 #define PARAM ((unsigned char *)empty_zero_page)#define RAMDISK_FLAGS (*(unsigned short *) (PARAM+0x1F8)) 可用rdev设置的参数#define LOADER_TYPE (*(unsigned char *) (PARAM+0x210))#define INITRD_START (*(unsigned long *) (PARAM+0x218)) 初始化盘映象起始物理地址#define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c)) 初始化盘字节数void __init setup_arch(char **cmdline_p){ ...#ifdef CONFIG_BLK_DEV_RAM rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK; 以块为单位 rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);#endif ...#ifdef CONFIG_BLK_DEV_INITRD if (LOADER_TYPE && INITRD_START) { if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) { ; max_low_pfn表示内核空间1G范围以下最大允许的物理页号 reserve_bootmem(INITRD_START, INITRD_SIZE); initrd_start = INITRD_START ? INITRD_START + PAGE_OFFSET : 0; 转变为内核逻辑地址 initrd_end = initrd_start+INITRD_SIZE; } else { printk("initrd extends beyond end of memory " "(0x%08lx > 0x%08lx)/ndisabling initrd/n", INITRD_START + INITRD_SIZE, max_low_pfn << PAGE_SHIFT); initrd_start = 0; } }#endif ...}; fs/partitions/check.c:int __init partition_setup(void){ device_init(); 包含ramdisk设备的初始化#ifdef CONFIG_BLK_DEV_RAM#ifdef CONFIG_BLK_DEV_INITRD if (initrd_start && mount_initrd) initrd_load(); ;如果启动时加载了initrd文件,则用它去初始化根内存盘 else#endif rd_load(); 如果内核配置了内存盘并且根盘指定为软盘则试图将软盘加载为根内存盘#endif return 0;}__initcall(partition_setup);; drivers/block/rd.c:int rd_doload; /* 1 = load RAM disk, 0 = don't load */int rd_prompt = 1; /* 1 = prompt for RAM disk, 0 = don't prompt */int rd_image_start; /* starting block # of image */#ifdef CONFIG_BLK_DEV_INITRDunsigned long initrd_start, initrd_end;int mount_initrd = 1; /* zero if initrd should not be mounted */int initrd_below_start_ok;void __init rd_load(void){ rd_load_disk(0); 加载到0号内存盘}void __init rd_load_secondary(void){ rd_load_disk(1); 加载到1号内存盘}static void __init rd_load_disk(int n){#ifdef CONFIG_BLK_DEV_INITRD extern kdev_t real_root_dev;#endif if (rd_doload == 0) return; if (MAJOR(ROOT_DEV) != FLOPPY_MAJOR 如果根盘是不软盘#ifdef CONFIG_BLK_DEV_INITRD && MAJOR(real_root_dev) != FLOPPY_MAJOR#endif ) return; if (rd_prompt) {#ifdef CONFIG_BLK_DEV_FD floppy_eject();#endif#ifdef CONFIG_MAC_FLOPPY if(MAJOR(ROOT_DEV) == FLOPPY_MAJOR) swim3_fd_eject(MINOR(ROOT_DEV)); else if(MAJOR(real_root_dev) == FLOPPY_MAJOR) swim3_fd_eject(MINOR(real_root_dev));#endif printk(KERN_NOTICE "VFS: Insert root floppy disk to be loaded into RAM disk and press ENTER/n"); wait_for_keypress(); } rd_load_image(ROOT_DEV,rd_image_start, n); 将根软盘加载到n号内存盘}void __init initrd_load(void){ ; 使用initrd设备盘作为源盘去建立内存根盘 rd_load_image(MKDEV(MAJOR_NR, INITRD_MINOR),rd_image_start,0);}static void __init rd_load_image(kdev_t device, int offset, int unit){ struct inode *inode, *out_inode; struct file infile, outfile; struct dentry in_dentry, out_dentry; mm_segment_t fs; kdev_t ram_device; int nblocks, i; char *buf; unsigned short rotate = 0; unsigned short devblocks = 0; char rotator[4] = { '|' , '/' , '-' , '//' }; ram_device = MKDEV(MAJOR_NR, unit); 建立输出内存盘设备号 if ((inode = get_empty_inode()) == NULL) return; memset(&infile, 0, sizeof(infile)); memset(&in_dentry, 0, sizeof(in_dentry)); infile.f_mode = 1; /* read only */ infile.f_dentry = &in_dentry; in_dentry.d_inode = inode; infile.f_op = &def_blk_fops; init_special_inode(inode, S_IFBLK | S_IRUSR, kdev_t_to_nr(device)); if ((out_inode = get_empty_inode()) == NULL) goto free_inode; memset(&outfile, 0, sizeof(outfile)); memset(&out_dentry, 0, sizeof(out_dentry)); outfile.f_mode = 3; /* read/write */ outfile.f_dentry = &out_dentry; out_dentry.d_inode = out_inode; outfile.f_op = &def_blk_fops; init_special_inode(out_inode, S_IFBLK | S_IRUSR | S_IWUSR, kdev_t_to_nr(ram_device)); if (blkdev_open(inode, &infile) != 0) 打开输入盘文件 goto free_inode; if (blkdev_open(out_inode, &outfile) != 0) 打开输出内存盘文件 goto free_inodes; fs = get_fs(); set_fs(KERNEL_DS); nblocks = identify_ramdisk_image(device, &infile, offset); 鉴定输入盘的文件类型 if (nblocks < 0) 出错 goto done; if (nblocks == 0) { 表示输入盘是gzip文件#ifdef BUILD_CRAMDISK if (crd_load(&infile, &outfile) == 0) 将输入盘文件解压到输出盘文件中去 goto successful_load;#else printk(KERN_NOTICE "RAMDISK: Kernel does not support compressed " "RAM disk images/n");#endif goto done; } /* * NOTE NOTE: nblocks suppose that the blocksize is BLOCK_SIZE, so * rd_load_image will work only with filesystem BLOCK_SIZE wide! * So make sure to use 1k blocksize while generating ext2fs * ramdisk-images. */ if (nblocks > (rd_length[unit] >> BLOCK_SIZE_BITS)) { ; 如果输入盘的尺寸超过了输出内存盘的允许尺寸 printk("RAMDISK: image too big! (%d/%ld blocks)/n", nblocks, rd_length[unit] >> BLOCK_SIZE_BITS); goto done; } /* * OK, time to in the data */ buf = kmalloc(BLOCK_SIZE, GFP_KERNEL); if (buf == 0) { printk(KERN_ERR "RAMDISK: could not allocate buffer/n"); goto done; } if (blk_size[MAJOR(device)]) devblocks = blk_size[MAJOR(device)][MINOR(device)]; 取输入盘的容量#ifdef CONFIG_BLK_DEV_INITRD if (MAJOR(device) == MAJOR_NR && MINOR(device) == INITRD_MINOR) devblocks = nblocks; 如果输入是初始化内存盘,则盘的容量为它的实际尺寸#endif if (devblocks == 0) { printk(KERN_ERR "RAMDISK: could not determine device size/n"); goto done; } printk(KERN_NOTICE "RAMDISK: Loading %d blocks [%d disk%s] into ram disk... ", nblocks, ((nblocks-1)/devblocks)+1, nblocks>devblocks ? "s" : ""); for (i=0; i < nblocks; i++) { if (i && (i % devblocks == 0)) { printk("done disk #%d./n", i/devblocks); rotate = 0; invalidate_buffers(device); 使输入盘设备缓冲区无效 if (infile.f_op->release) infile.f_op->release(inode, &infile); printk("Please insert disk #%d and press ENTER/n", i/devblocks+1); wait_for_keypress(); if (blkdev_open(inode, &infile) != 0) { printk("Error opening disk./n"); goto done; } infile.f_pos = 0; printk("Loading disk #%d... ", i/devblocks+1); } infile.f_op->read(&infile, buf, BLOCK_SIZE, &infile.f_pos); outfile.f_op->write(&outfile, buf, BLOCK_SIZE, &outfile.f_pos);#if !defined(CONFIG_ARCH_S390) if (!(i % 16)) { printk("%c/b", rotator[rotate & 0x3]); rotate++; }#endif } printk("done./n"); kfree(buf);successful_load: invalidate_buffers(device); ROOT_DEV = MKDEV(MAJOR_NR, unit); 将根盘设备设置为当前加载的内存盘 if (ROOT_DEVICE_NAME != NULL) strcpy (ROOT_DEVICE_NAME, "rd/0");done: if (infile.f_op->release) infile.f_op->release(inode, &infile); set_fs(fs); return;free_inodes: /* free inodes on error */ iput(out_inode); blkdev_put(inode->i_bdev, BDEV_FILE);free_inode: iput(inode);}int __init identify_ramdisk_image(kdev_t device, struct file *fp, int start_block){ const int size = 512; struct minix_super_block *minixsb; struct ext2_super_block *ext2sb; struct romfs_super_block *romfsb; int nblocks = -1; unsigned char *buf; buf = kmalloc(size, GFP_KERNEL); if (buf == 0) return -1; minixsb = (struct minix_super_block *) buf; ext2sb = (struct ext2_super_block *) buf; romfsb = (struct romfs_super_block *) buf; memset(buf, 0xe5, size); /* * Read block 0 to test for gzipped kernel */ if (fp->f_op->llseek) fp->f_op->llseek(fp, start_block * BLOCK_SIZE, 0); fp->f_pos = start_block * BLOCK_SIZE; fp->f_op->read(fp, buf, size, &fp->f_pos); ; 读取offset开始的512字节 /* * If it matches the gzip magic numbers, return -1 */ if (buf[0] == 037 && ((buf[1] == 0213) || (buf[1] == 0236))) { printk(KERN_NOTICE "RAMDISK: Compressed image found at block %d/n", start_block); nblocks = 0; goto done; } /* romfs is at block zero too */ if (romfsb->word0 == ROMSB_WORD0 && romfsb->word1 == ROMSB_WORD1) { printk(KERN_NOTICE "RAMDISK: romfs filesystem found at block %d/n", start_block); nblocks = (ntohl(romfsb->size)+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS; goto done; } /* * Read block 1 to test for minix and ext2 superblock */ if (fp->f_op->llseek) fp->f_op->llseek(fp, (start_block+1) * BLOCK_SIZE, 0); fp->f_pos = (start_block+1) * BLOCK_SIZE; fp->f_op->read(fp, buf, size, &fp->f_pos); /* Try minix */ if (minixsb->s_magic == MINIX_SUPER_MAGIC || minixsb->s_magic == MINIX_SUPER_MAGIC2) { printk(KERN_NOTICE "RAMDISK: Minix filesystem found at block %d/n", start_block); nblocks = minixsb->s_nzones << minixsb->s_log_zone_size; goto done; } /* Try ext2 */ if (ext2sb->s_magic == cpu_to_le16(EXT2_SUPER_MAGIC)) { printk(KERN_NOTICE "RAMDISK: ext2 filesystem found at block %d/n", start_block); nblocks = le32_to_cpu(ext2sb->s_blocks_count); goto done; } printk(KERN_NOTICE "RAMDISK: Couldn't find valid RAM disk image starting at %d./n", start_block);done: if (fp->f_op->llseek) fp->f_op->llseek(fp, start_block * BLOCK_SIZE, 0); fp->f_pos = start_block * BLOCK_SIZE; kfree(buf); return nblocks;}; fs/super.cvoid __init mount_root(void){ struct file_system_type * fs_type; struct super_block * sb; struct vfsmount *vfsmnt; struct block_device *bdev = NULL; mode_t mode; int retval; void *handle; char path[64]; int path_start = -1;#ifdef CONFIG_BLK_DEV_FD if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) { 当根盘还是软盘,表示没有加载过内存盘#ifdef CONFIG_BLK_DEV_RAM extern int rd_doload; extern void rd_load_secondary(void);#endif floppy_eject();#ifndef CONFIG_BLK_DEV_RAM printk(KERN_NOTICE "(Warning, this kernel has no ramdisk support)/n");#else /* rd_doload is 2 for a al initrd/ramload setup */ ; 只有当加载了initrd但没有释放到内存盘中(mount_inird=0)才有可能到这一步 if(rd_doload==2) rd_load_secondary(); 加载另一张软盘到1号内存盘作为根盘 else#endif { printk(KERN_NOTICE "VFS: Insert root floppy and press ENTER/n"); wait_for_keypress(); } }#endif devfs_make_root (root_device_name); handle = devfs_find_handle (NULL, ROOT_DEVICE_NAME, MAJOR (ROOT_DEV), MINOR (ROOT_DEV), DEVFS_SPECIAL_BLK, 1); if (handle) /* Sigh: bd*() functions only paper over the cracks */ { unsigned major, minor; devfs_get_maj_min (handle, &major, &minor); ROOT_DEV = MKDEV (major, minor); } /* * Probably pure paranoia, but I'm less than happy about delving into * devfs crap and checking it right now. Later. */ if (!ROOT_DEV) panic("I have no root and I want to scream"); bdev = bdget(kdev_t_to_nr(ROOT_DEV)); if (!bdev) panic(__FUNCTION__ ": unable to allocate root device"); bdev->bd_op = devfs_get_ops (handle); path_start = devfs_generate_path (handle, path + 5, sizeof (path) - 5); mode = FMODE_READ; if (!(root_mountflags & MS_RDONLY)) mode |= FMODE_WRITE; retval = blkdev_get(bdev, mode, 0, BDEV_FS); if (retval == -EROFS) { root_mountflags |= MS_RDONLY; retval = blkdev_get(bdev, FMODE_READ, 0, BDEV_FS); } if (retval) { /* * Allow the user to distinguish between failed open * and bad superblock on root device. */ printk ("VFS: Cannot open root device /"%s/" or %s/n", root_device_name, kdevname (ROOT_DEV)); printk ("Please append a correct /"root=/" boot option/n"); panic("VFS: Unable to mount root fs on %s", kdevname(ROOT_DEV)); } check_disk_change(ROOT_DEV); sb = get_super(ROOT_DEV); 取根盘的超级块 if (sb) { fs_type = sb->s_type; goto mount_it; } read_lock(&file_systems_lock); for (fs_type = file_systems ; fs_type ; fs_type = fs_type->next) { if (!(fs_type->fs_flags & FS_REQUIRES_DEV)) continue; 根文件系统必须依赖于块设备 if (!try_inc_mod_count(fs_type->owner)) continue; 当文件系统模块正在删除过程中 read_unlock(&file_systems_lock); sb = read_super(ROOT_DEV,bdev,fs_type,root_mountflags,NULL,1);建立根盘的超级块结构 if (sb) goto mount_it; read_lock(&file_systems_lock); put_filesystem(fs_type); 释放对文件系统模块的引用 } read_unlock(&file_systems_lock); panic("VFS: Unable to mount root fs on %s", kdevname(ROOT_DEV));mount_it: printk ("VFS: Mounted root (%s filesystem)%s./n", fs_type->name, (sb->s_flags & MS_RDONLY) ? " readonly" : ""); if (path_start >= 0) { devfs_mk_symlink (NULL, "root", DEVFS_FL_DEFAULT, path + 5 + path_start, NULL, NULL); memcpy (path + path_start, "/dev/", 5); vfsmnt = add_vfsmnt(NULL, sb->s_root, path + path_start); } else vfsmnt = add_vfsmnt(NULL, sb->s_root, "/dev/root"); 建立根盘的安装结构 /* FIXME: if something will try to umount us right now... */ if (vfsmnt) { set_fs_root(current->fs, vfsmnt, sb->s_root); 设置当前进程的根盘和根目录 set_fs_pwd(current->fs, vfsmnt, sb->s_root); 设置当前进程的当前盘和当前目录 if (bdev) bdput(bdev); /* sb holds a reference */ return; } panic("VFS: add_vfsmnt failed for root fs");}#ifdef CONFIG_BLK_DEV_INITRDint __init change_root(kdev_t new_root_dev,const char *put_old){ 以new_root_dev作为根盘重新安装根文件系统,原来的根转移到put_old目录下 struct vfsmount *old_rootmnt; struct nameidata devfs_nd, nd; int error = 0; read_lock(¤t->fs->lock); old_rootmnt = mntget(current->fs->rootmnt); 取当前进程的根盘安装结构 read_unlock(¤t->fs->lock); /* First unmount devfs if mounted */ if (path_init("/dev", LOOKUP_FOLLOW|LOOKUP_POSITIVE, &devfs_nd)) error = path_walk("/dev", &devfs_nd); if (!error) { if (devfs_nd.mnt->mnt_sb->s_magic == DEVFS_SUPER_MAGIC && devfs_nd.dentry == devfs_nd.mnt->mnt_root) { dput(devfs_nd.dentry); down(&mount_sem); /* puts devfs_nd.mnt */ do_umount(devfs_nd.mnt, 0, 0); up(&mount_sem); } else path_release(&devfs_nd); } ROOT_DEV = new_root_dev; mount_root(); 改变根盘设备重新安装根文件系统#if 1 shrink_dcache(); 清除目录项缓冲中所有自由的目录项 printk("change_root: old root has d_count=%d/n", atomic_read(&old_rootmnt->mnt_root->d_count));#endif mount_devfs_fs (); /* * Get the new mount directory */ error = 0; if (path_init(put_old, LOOKUP_FOLLOW|LOOKUP_POSITIVE|LOOKUP_DIRECTORY, &nd)) error = path_walk(put_old, &nd); 在新的根盘中寻找put_old目录 if (error) { int blivet; printk(KERN_NOTICE "Trying to unmount old root ... "); blivet = do_umount(old_rootmnt, 1, 0); 卸载原始的根盘 if (!blivet) { printk("okay/n"); return 0; } printk(KERN_ERR "error %d/n", blivet); return error; } /* FIXME: we should hold i_zombie on nd.dentry */ move_vfsmnt(old_rootmnt, nd.dentry, nd.mnt, "/dev/root.old"); mntput(old_rootmnt); path_release(&nd); return 0;}#endifstatic struct vfsmount *add_vfsmnt(struct nameidata *nd, 在虚拟文件系统中的安装点 struct dentry *root, 安装盘的根目录项 const char *dev_name) 安装盘名称{ struct vfsmount *mnt;
————————————————
版权声明:本文为CSDN博主“huanghaibin”的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/huanghaibin/java/article/details/478215

C. make moles编译驱动模块,只生成.o文件没有.ko文件...这是怎么回事

file1.o和file2.o指的是编译出来的源文件有两个分别是file1.c和file2.c

D. 如何把自己的驱动编译进内核或模块

我们知道若要给Linux内核添加模块(驱动)有如下两种方式:
(1)动态方式:采用insmod命令来给运行中的linux加载模块。
(2)静态方式:修改linux的配置菜单,添加模块相关文件到源码对应目录,然后把模块直接编译进内核。
对于动态方式,比较简单,下面我们介绍如何采用静态的方式把模块添加到内核。
最终到达的效果是:在内核的配置菜单中可以配置我们添加的模块,并可以对我们添加的模块进行编译。
一. 内核的配置系统组成
首先我们要了解Linux 2.6内核的配置系统的原理,比如我们在源码下运行“make menuconfig ”为神马会出现一个图形配置菜单,配置了这个菜单后又是如何改变了内核的编译策略滴。
内核的配置系统一般由以下几部分组成:
(1)Makefile:分布在Linux内核源代码中的Makefile,定义Linux内核的编译规则。
(2)配置文件(Kconfig):给用户提供配置选项,修改该文件来改变配置菜单选项。
(3)配置工具:包括配置命令解释器(对配置脚本中使用的配置命令进行解释),配置用户界面(提供字符界面和图形界面)。这些配置工具都是使用脚本语言编写的,如Tcl/TK、Perl等。
其原理可以简述如下:这里有两条主线,一条为配置线索,一条为编译线索。配置工具根据kconfig配置脚本产生配置菜单,然后根据配置菜单的配置情况生成顶层目录下的.config,在.config里定义了配置选择的配置宏定义,如下所示:

如上所示,这里定义的这些配置宏变量会在Makefile里出现,如下所示:

然后make 工具根据Makefile里这些宏的赋值情况来指导编译。所以理论上,我们可以直接修改.config和Makefile来添加模块,但这样很麻烦,也容易出错,下面我们将会看到,实际上我们有两种方法来很容易的实现。

二. 如何添加模块到内核
实际上,我们需要做的工作可简述如下:
(1)将编写的模块或驱动源代码(比如是XXOO)复制到Linux内核源代码的相应目录。
(2)在该目录下的Kconfig文件中依葫芦画瓢的添加XXOO配置选项。
(3)在该目录的Makefile文件中依葫芦画瓢的添加XXOO编译选项。
可以看到,我们奉行的原则是“依葫芦画瓢”,主要是添加。
一般的按照上面方式又可出现两种情况,一种为给XXOO驱动添加我们自己的目录,一种是不添加目录。两种情况的处理方式有点儿不一样哦。

三. 不加自己目录的情况
(1)把我们的驱动源文件(xxoo.c)放到对应目录下,具体放到哪里需要根据驱动的类型和特点。这里假设我们放到./driver/char下。
(2)然后我们修改./driver/char下的Kconfig文件,依葫芦添加即可,如下所示:

注意这里的LT_XXOO这个名字可以随便写,但需要保持这个格式,他并不需要跟驱动源文件保持一致,但最好保持一致,等下我们在修改Makefile时会用到这个名字,他将会变成CONFIG_LT_XXOO,那个名字必须与这个名字对应。如上所示,tristate定义了这个配置选项的可选项有几个,help定义了这个配置选项的帮助信息,具体更多的规则这里不讲了。

(3)然后我们修改./driver/char下的Makefile文件,如下所示:

这里我们可以看到,前面Kconfig里出现的LT_XXOO,在这里我们就需要使用到CONFIG_XXOO,实际上逻辑是酱汁滴:在Kconfig里定义了LT_XXOO,然后配置完成后,在顶层的.config里会产生CONFIG_XXOO,然后这里我们使用这个变量。
到这里第一种情况下的添加方式就完成了。
四. 添加自己目录的情况
(1)在源码的对应目录下建立自己的目录(xxoo),这里假设为/drivers/char/xxoo 。
(2) 把驱动源码放到新建的xxoo目录下,并在此目录下新建Kconfig和Makefile文件。然后给新建的Kconfig和Makefile添加内容。
Kconfig下添加的内容如下:

这个格式跟之前在Kconfig里添加选项类似。
Makefile里写入的内容就更少了:

添加这一句就可以了。
(3)第三也不复杂,还是依葫芦画瓢就可以了。
我们在/drivers/char目录下添加了xxoo目录,我们总得在这个配置系统里进行登记吧,哈哈,不然配置系统怎么找到们呢。由于整个配置系统是递归调用滴,所以我们需要在xxoo的父目录也即char目录的Kconfig和Makefile文件里进行登记。具体如下:
a). 在drivers/char/Kconfig中加入:source “drivers/char/xxoo/Kconfig”
b). 在drivers/char/Makefile中加入:obj-$(CONFIG_LT_XXOO) += xxoo/
添加过程依葫芦画瓢就可以了,灰常滴简单。

E. 如何编译Linux内核

编译linux内核步骤:
1、安装内核
如果内核已经安装(/usr/src/目录有linux子目录),跳过。如果没有安装,在光驱中放入linux安装光盘,找到kernel-source-2.xx.xx.rpm文件(xx代表数字,表示内核的版本号),比如RedHat linux的RPMS目录是/RedHat/RPMS/目录,然后使用命令rpm -ivh kernel-source-2.xx.xx.rpm安装内核。如果没有安装盘,可以去各linux厂家站点或者www.kernel.org下载。
2、清除从前编译内核时残留的.o 文件和不必要的关联
cd /usr/src/linux
make mrproper
3、配置内核,修改相关参数,请参考其他资料
在图形界面下,make xconfig;字符界面下,make menuconfig。在内核配置菜单中正确设置个内核选项,保存退出
4、正确设置关联文件
make dep
5、编译内核
对于大内核(比如需要SCSI支持),make bzImage
对于小内核,make zImage
6、编译模块
make moles
7、安装模块
make moles_install
8、使用新内核
把/usr/src/linux/arch/i386/boot/目录内新生成的内核文件bzImage/zImage拷贝到/boot目录,然后修改/etc/lilo.conf文件,加一个启动选项,使用新内核bzImage/zImage启动。格式如下:
boot=/dev/hda
map=/boot/map
install=/boot/boot.b
prompt
timeout=50
linear
default=linux-new ### 告诉lilo缺省使用新内核启动linux ###
append="mem=256M"
image=/boot/vmlinuz-2.2.14-5.0
label=linux
read-only
root=/dev/hda5
image=/boot/bzImage(zImage)
label=linux-new
read-only
root=/dev/hda5
保留旧有的启动选项可以保证新内核不能引导的情况,还可以进入linux进行其他操作。保存退出后,不要忘记了最重要的一步,运行/sbin/lilo,使修改生效。
9、重新生成ram磁盘
如果您的系统中的/etc/lilo.conf没有使用了ram磁盘选项initrd,略过。如果您的系统中的/etc/lilo.conf使用了ram磁盘选项initrd,使用mkinitrd initrd-内核版本号,内核版本号命令重新生成ram磁盘文件,例如我的Redhat 6.2:
mkinitrd initrd-2.2.14-5.0 2.2.14-5.0
之后把/etc/lilo.conf中的initrd指向新生成的initrd-2.2.14-5.0文件:
initrd=/boot/initrd-2.2.14-5.0
ram磁盘能使系统性能尽可能的优化,具体参考/usr/src/linux/Documents/initrd.txt文件
10、重新启动,OK!

F. 如何把新驱动编译进内核 ubuntu

工具/原料

Ubuntu12.04操作系统和测试驱动程序(beep_arv.c)
方法/步骤

在介绍2种方法前,必须知道的知识点:
1.关联文件Makefile:
Makefile:分布在Linux内核源代码中的Makefile用于定义Linux内核的编译规则;
2.管理文件Kconfig:
给用户提供配置选择的功能;
配置工具:
1)包括配置命令解析器;
2)配置用户界面;menuconfig || xconfig;
3)通过脚本语言编写的;

3.
---tristate 代表三种状态:1.[ ]不选择,2.[*]选择直接编译进内核,加载驱动到内核里,3.[m]动态加载驱动;
---bool 代表两种状态,1.[ ]不选择,2.[*]选择;
---"Mini2440 mole sample"这个是在make menuconfig时刷出的提示字符;
---depends on MACH_MINI2440 这个配置选项出现在make menuconfig菜单栏下,在内核配置中必须选中、MACH_MINI2440;
---default m if MACH_MINI2440 这个如果选中了MACH_MINI2440,默认是手
动加载这个驱动;
help:提示帮助信息;
在了解了基本的知识点,便开始进行第一种添加驱动的方法,本次交流是以beep_arv.c蜂鸣驱动程序为基础的
方法一:
1)进入内核的驱动目录;
#cp beep_arv.c /XXX/.../linux-XXXl/drivers/char
2)进入Kconfig添加驱动信息;
#cd /XXX/linux-XXX/.../drivers/char
#vim Kconfig
添加基本信息:
config BEEP_MINI2440
tristate "---HAH--- BEEP"
default
help
this is test makefile!

3)进入Makefile添加驱动编译信息;
#vim Makefile
添加基本信息:
obj-$(CONFIG-BEEP_MINI2440) +=beep_drv.o

方法一结果:
在--Character devices下就能看到配置信息了;

方法二:
1)进入驱动目录,创建BEED目录;
#cd /XXX/.../linux-XXX/drivers/char
#mkdir beep
2)将beep_arv.c驱动程序复制到新建目录下;
#cp beep_arv.c /XXX/.../linux-XXXl/drivers/char/beep
3)创建Makefile和Kconfig文件
#cd char/beep
#mkdir Makefile Kconfig
#chmod 755 Makefile
#chmod 755 Kconfig

4)进入Kconfig添加驱动信息;
#vim Kconfig
添加基本信息:
config BEEP_MINI2440
tristate "---HAH--- BEEP"
default
help
this is test makefile!

5)进入Makefile添加驱动编译信息;
#vim Makefile
添加基本信息:
obj-$(CONFIG_BEEP_MINI2440) +=beep_drv.o

6)并且要到上一级目录的Makefile和Kconfig添加驱动信息;
#cd ../
#vim Makefile
#vim Kconfig

G. 怎样才能把framebuffer正确编译进内核

GRUB配置文件 grub.conf 里现在使用的内核的 kernel 一行最后加上vga=ask(前面加空格和别的部分隔开); 重启linux,会停在一个系统支持分辨率列表的界面,选择想要的分辨率进入。 进系统后应该有framebuffer开启,有设备文件 /dev/fb0 。

阅读全文

与怎么把ramdirk编译进内核相关的资料

热点内容
冒险岛什么服务器好玩 浏览:541
如何在服务器上做性能测试 浏览:793
命令序列错 浏览:257
javaif的条件表达式 浏览:576
手机app上传的照片怎么找 浏览:531
云服务器面临哪些威胁 浏览:746
c语言各种编译特点 浏览:177
路由器多种加密方法 浏览:604
程序员阻止电脑自动弹出定位 浏览:168
如何做服务器服务商 浏览:761
su剖切命令 浏览:726
devc编译背景 浏览:211
学习单片机的意义 浏览:51
音频算法AEC 浏览:911
加密货币容易被盗 浏览:82
苹果平板如何开启隐私单个app 浏览:704
空调压缩机一开就停止 浏览:528
如何下载虎牙app 浏览:847
日语年号的算法 浏览:955
dev里面的编译日志咋调出来 浏览:298