学习linux内核的意义有多大?

学习linux内核的意义有多大?,第1张

linux内核级代码是高级程序员的必会课程之一,学习linux内核不仅能帮我们了解linux是怎么运作的,便于我们编写程序的时候考虑到 *** 作系统的执行情况,还能够开拓我们的编程思路,应为应该没有什么软件比 *** 作系统还复杂的了。

linux内核最经典的书是《深入理解Linux内核》,这本书内核编程看;如果你是搞UNIX/Linux环境下的应用程序编程,那么就看《UNIX环境高级编程》;如果做Linux下设备驱动程序开发,就看《Linux设备驱动》(第三版)。这几本都是老外写的,都是很经典的书。

都是好书啊,我都有,linux内核设计比较理论,讲述 *** 作系统的一些基本概念但结合linux这个特定的OS,从总体上把握linux内核的设计思想,而深入理解Linux内核则比较具体的讲解内核的设计实现引用的代码比较多,比较细,比较杂,要细细分析。都挺不错,如何你比较入门,可以先看linux内核设计,但要结合代码分析,不然也很难入门,深入理解比较难,如果有一定水平,可以入手。

图2-1显示了基于x86计算机Linux系统的启动顺序。第一步是BIOS从启动设备中导入主引导记录(MBR),接下来MBR中的代码查看分区表并从活动分区读取GRUB、LILO或SYSLINUX等引导装入程序,之后引导装入程序会加载压缩后的内核映像并将控制权传递给它。内核取得控制权后,会将自身解压缩并投入运转。
基于x86的处理器有两种 *** 作模式:实模式和保护模式。在实模式下,用户仅可以使用1 MB内存,并且没有任何保护。保护模式要复杂得多,用户可以使用更多的高级功能(如分页)。CPU 必须中途将实模式切换为保护模式。但是,这种切换是单向的,即不能从保护模式再切换回实模式。
内核初始化的第一步是执行实模式下的汇编代码,之后执行保护模式下init/mainc文件(上一章修改的源文件)中的 start_kernel()函数。start_kernel()函数首先会初始化CPU子系统,之后让内存和进程管理系统就位,接下来启动外部总线和 I/O设备,最后一步是激活初始化(init)程序,它是所有Linux进程的父进程。初始化进程执行启动必要的内核服务的用户空间脚本,并且最终派生控制台终端程序以及显示登录(login)提示。
图2-1 基于x86硬件上的Linux的启动过程
本节内的3级标题都是图2-2中的一条打印信息,这些信息来源于基于x86的笔记本 电脑的Linux启动过程。如果在其他体系架构上启动内核,消息以及语义可能会有所不同。
211 BIOS-provided physical RAM map
内核会解析从BIOS中读取到的系统内存映射,并率先将以下信息打印出来:
BIOS-provided physical RAM map:
BIOS-e820: 0000000000000000 - 000000000009f000 (usable)

BIOS-e820: 00000000ff800000 - 0000000100000000 (reserved)
实模式下的初始化代码通过使用BIOS的int 0x15服务并执行0xe820号函数(即上面的BIOS-e820字符串)来获得系统的内存映射信息。内存映射信息中包含了预留的和可用的内存,内核将随后使用这些信息创建其可用的内存池。在附录B的B1节,我们会对BIOS提供的内存映射问题进行更深入的讲解。
图2-2 内核启动信息
212 758MB LOWMEM available
896 MB以内的常规的可被寻址的内存区域被称作低端内存。内存分配函数kmalloc()就是从该区域分配内存的。高于896 MB的内存区域被称为高端内存,只有在采用特殊的方式进行映射后才能被访问。
在启动过程中,内核会计算并显示这些内存区内总的页数。
213 Kernel command line: ro root=/dev/hda1
Linux的引导装入程序通常会给内核传递一个命令行。命令行中的参数类似于传递给C程序中main()函数的argv[]列表,唯一的不同在于它们是传递给内核的。可以在引导装入程序的配置文件中增加命令行参数,当然,也可以在运行过程中修改引导装入程序的提示行[1]。如果使用的是GRUB 这个引导装入程序,由于发行版本的不同,其配置文件可能是/boot/grub/grubconf或者是/boot/grub/menulst。如果使用的是LILO,配置文件为/etc/liloconf。下面给出了一个grubconf文件的例子(增加了一些注释),看了紧接着title kernel 2623的那行代码之后,你会明白前述打印信息的由来。
default 0 #Boot the 2623 kernel by default
timeout 5 #5 second to alter boot order or parameters
title kernel 2623 #Boot Option 1
#The boot image resides in the first partition of the first disk
#under the /boot/ directory and is named vmlinuz-2623 'ro'
#indicates that the root partition should be mounted read-only
kernel (hd0,0)/boot/vmlinuz-2623 ro root=/dev/hda1
#Look under section "Freeing initrd memory:387k freed"
initrd (hd0,0)/boot/initrd
#
命令行参数将影响启动过程中的代码执行路径。举一个例子,假设某命令行参数为bootmode,如果该参数被设置为1,意味着你希望在启动过程中打印一些调试信息并在启动结束时切换到runlevel的第3级(初始化进程的启动信息打印后就会了解runlevel的含义);如果bootmode 参数被设置为0,意味着你希望启动过程相对简洁,并且设置runlevel为2。既然已经熟悉了init/mainc文件,下面就在该文件中增加如下修改:
static unsigned int bootmode = 1 ;
static int __init
is_bootmode_setup( char str)
{
get_option( & str, & bootmode);
return 1 ;
}
/ Handle parameter "bootmode=" /
__setup( " bootmode= " , is_bootmode_setup);
if (bootmode) {
/ Print verbose output /
/ /
}
/ /
/ If bootmode is 1, choose an init runlevel of 3, else
switch to a run level of 2 /
if (bootmode) {
argv_init[ ++ args] = " 3 " ;
} else {
argv_init[ ++ args] = " 2 " ;
}
/ /
请重新编译内核并尝试运行新的修改。
214 Calibrating delay119746 BogoMIPS (lpj=2394935)
在启动过程中,内核会计算处理器在一个jiffy时间内运行一个内部的延迟循环的次数。jiffy的含义是系统定时器2个连续的节拍之间的间隔。正如所料,该计算必须被校准到所用CPU的处理速度。校准的结果被存储 在称为loops_per_jiffy的内核变量中。使用loops_per_jiffy的一种情况是某设备驱动程序希望进行小的微秒级别的延迟的时候。
为了理解延迟—循环校准代码,让我们看一下定义于init/calibratec文件中的calibrate_ delay()函数。该函数灵活地使用整型运算得到了浮点的精度。如下的代码片段(有一些注释)显示了该函数的开始部分,这部分用于得到一个 loops_per_jiffy的粗略值:
loops_per_jiffy = ( 1 << 12 ); / Initial approximation = 4096 /
printk(KERN_DEBUG “Calibrating delay loop“);
while ((loops_per_jiffy <<= 1 ) != 0 ) {
ticks = jiffies; / As you will find out in the section, “Kernel
Timers," the jiffies variable contains the
number of timer ticks since the kernel
started, and is incremented in the timer
interrupt handler /
while (ticks == jiffies); / Wait until the start of the next jiffy /
ticks = jiffies;
/ Delay /
__delay(loops_per_jiffy);
/ Did the wait outlast the current jiffy Continue if it didn't /
ticks = jiffies - ticks;
if (ticks) break ;
}
loops_per_jiffy >>= 1 ; / This fixes the most significant bit and is
the lower-bound of loops_per_jiffy /
上述代码首先假定loops_per_jiffy大于4096,这可以转化为处理器速度大约为每秒100万条指令,即1 MIPS。接下来,它等待jiffy被刷新(1个新的节拍的开始),并开始运行延迟循环__delay(loops_per_jiffy)。如果这个延迟循环持续了1个jiffy以上,将使用以前的loops_per_jiffy值(将当前值右移1位)修复当前loops_per_jiffy的最高位;否则,该函数继续通过左移loops_per_jiffy值来探测出其最高位。在内核计算出最高位后,它开始计算低位并微调其精度:
loopbit = loops_per_jiffy;
/ Gradually work on the lower-order bits /
while (lps_precision -- && (loopbit >>= 1 )) {
loops_per_jiffy |= loopbit;
ticks = jiffies;
while (ticks == jiffies); / Wait until the start of the next jiffy /
ticks = jiffies;
/ Delay /
__delay(loops_per_jiffy);
if (jiffies != ticks) / longer than 1 tick /
loops_per_jiffy &= ~ loopbit;
}
上述代码计算出了延迟循环跨越jiffy边界时loops_per_jiffy的低位值。这个被校准的值可被用于获取BogoMIPS(其实它是一个并非科学的处理器速度指标)。可以使用BogoMIPS作为衡量处理器运行速度的相对尺度。在16G Hz 基于Pentium M的笔记本 电脑上,根据前述启动过程的打印信息,循环校准的结果是:loops_per_jiffy的值为2394935。获得BogoMIPS的方式如下:
BogoMIPS = loops_per_jiffy 1秒内的jiffy数 延迟循环消耗的指令数(以百万为单位)
= ( 2394935 HZ 2 ) / ( 1000000 )
= ( 2394935 250 2 ) / ( 1000000 )
= 119746 (与启动过程打印信息中的值一致)
在24节将更深入阐述jiffy、HZ和loops_per_jiffy。
215 Checking HLT instruction
由于Linux内核支持多种硬件平台,启动代码会检查体系架构相关的bug。其中一项工作就是验证停机(HLT)指令。
x86处理器的HLT指令会将CPU置入一种低功耗睡眠模式,直到下一次硬件中断发生之前维持不变。当内核想让CPU进入空闲状态时(查看 arch/x86/kernel/process_32c文件中定义的cpu_idle()函数),它会使用HLT指令。对于有问题的CPU而言,命令行参数no-hlt可以禁止HLT指令。如果no-hlt被设置,在空闲的时候,内核会进行忙等待而不是通过HLT给CPU降温。
当init/mainc中的启动代码调用include/asm-your-arch/bugsh中定义的check_bugs()时,会打印上述信息。
216 NET: Registered protocol family 2
Linux套接字(socket)层是用户空间应用程序访问各种网络 协议的统一接口。每个协议通过include/linux/socketh文件中定义的分配给它的独一无二的系列号注册。上述打印信息中的Family 2代表af_inet(互联网协议)。
启动过程中另一个常见的注册协议系列是AF_NETLINK(Family 16)。网络链接套接字提供了用户进程和内核通信 的方法。通过网络链接套接字可完成的功能还包括存取路由表和地址解析协议(ARP)表(include/linux/netlinkh文件给出了完整的用法列表)。对于此类任务而言,网络链接套接字比系统调用更合适,因为前者具有采用异步机制、更易于实现和可动态链接的优点。
内核中经常使能的另一个协议系列是AF_Unix或Unix-domain套接字。X Windows等程序使用它们在同一个系统上进行进程间通信。
217 Freeing initrd memory: 387k freed
initrd是一种由引导装入程序加载的常驻内存的虚拟磁盘映像。在内核启动后,会将其挂载为初始根文件系统,这个初始根文件系统中存放着挂载实际根文件系统磁盘分区时所依赖的可动态连接的模块。由于内核可运行于各种各样的存储控制器硬件平台上,把所有可能的磁盘驱动程序都直接放进基本的内核映像中并不可行。你所使用的系统的存储设备的驱动程序被打包放入了initrd中,在内核启动后、实际的根文件系统被挂载之前,这些驱动程序才被加载。使用 mkinitrd命令可以创建一个initrd映像。
26内核提供了一种称为initramfs的新功能,它在几个方面较initrd更为优秀。后者模拟了一个磁盘(因而被称为 initramdisk或initrd),会带来Linux块I/O子系统的开销(如缓冲);前者基本上如同一个被挂载的文件系统一样,由自身获取缓冲 (因此被称作initramfs)。
不同于initrd,基于页缓冲建立的initramfs如同页缓冲一样会动态地变大或缩小,从而减少了其内存消耗。另外,initrd要求你的内核映像包含initrd所使用的文件系统(例如,如果initrd为EXT2文件系统,内核必须包含EXT2驱动程序),然而initramfs不需要文件系统支持。再者,由于initramfs只是页缓冲之上的一小层,因此它的代码量很小。
用户可以将初始根文件系统打包为一个cpio压缩包[1],并通过initrd=命令行参数传递给内核。当然,也可以在内核配置过程中通过 INITRAMFS_SOURCE选项直接编译进内核。对于后一种方式而言,用户可以提供cpio压缩包的文件名或者包含initramfs的目录树。在启动过程中,内核会将文件解压缩为一个initramfs根文件系统,如果它找到了/init,它就会执行该顶层的程序。这种获取初始根文件系统的方法对于嵌入式系统而言特别有用,因为在嵌入式系统中系统资源非常宝贵。使用mkinitramfs可以创建一个initramfs映像,查看文档 Documentation/filesystems/ramfs- rootfs-initramfstxt可获得更多信息。
在本例中,我们使用的是通过initrd=命令行参数向内核传递初始根文件系统cpio压缩包的方式。在将压缩包中的内容解压为根文件系统后,内核将释放该压缩包所占据的内存(本例中为387 KB)并打印上述信息。释放后的页面会被分发给内核中的其他部分以便被申请。
在嵌入式系统开发过程中,initrd和initramfs有时候也可被用作嵌入式设备上实际的根文件系统。
218 io scheduler anticipatory registered (default)
I/O调度器的主要目标是通过减少磁盘的定位次数来增加系统的吞吐率。在磁盘定位过程中,磁头需要从当前的位置移动到感兴趣的目标位置,这会带来一定的延迟。26内核提供了4种不同的I/O调度器:Deadline、Anticipatory、Complete Fair Queuing以及NOOP。从上述内核打印信息可以看出,本例将Anticipatory 设置为了默认的I/O调度器。
219 Setting up standard PCI resources
启动过程的下一阶段会初始化I/O总线和外围控制器。内核会通过遍历PCI总线来探测PCI硬件,接下来再初始化其他的I/O子系统。从图2-3中我们会看到SCSI子系统、USB控制器、视频 芯片(855北桥芯片组信息中的一部分)、串行端口(本例中为8250 UART)、PS/2键盘 和鼠标 、软驱 、ramdisk、loopback设备、IDE控制器(本例中为ICH4南桥芯片组中的一部分)、触控板、以太网控制器(本例中为e1000)以及PCMCIA控制器初始化的启动信息。图2-3中 符号指向的为I/O设备的标识(ID)。
图2-3 在启动过程中初始化总线和外围控制器
本书会以单独的章节讨论大部分上述驱动程序子系统,请注意如果驱动程序以模块的形式被动态链接到内核,其中的一些消息也许只有在内核启动后才会被显示。
2110 EXT3-fs: mounted filesystem
EXT3文件系统已经成为Linux事实上的文件系统。EXT3在退役的EXT2文件系统基础上增添了日志层,该层可用于崩溃后文件系统的快速恢复。它的目标是不经由耗时的文件系统检查(fsck) *** 作即可获得一个一致的文件系统。EXT2仍然是新文件系统的工作引擎,但是EXT3层会在进行实际的磁盘改变之前记录文件交互的日志。EXT3向后兼容于EXT2,因此,你可以在你现存的EXT2文件系统上加上EXT3或者由EXT3返回到EXT2 文件系统。
EXT3会启动一个称为kjournald的内核辅助线程(在接下来的一章中将深入讨论内核线程)来完成日志功能。在EXT3投入运转以后,内核挂载根文件系统并做好“业务”上的准备:
EXT3-fs: mounted filesystem with ordered data mode
kjournald starting Commit interval 5 seconds
VFS: Mounted root (ext3 filesystem)
2111 INIT: version 285 booting
所有Linux进程的父进程init是内核完成启动序列后运行的第1个程序。在init/mainc的最后几行,内核会搜索一个不同的位置以定位到init:
if (ramdisk_execute_command) { / Look for /init in initramfs /
run_init_process(ramdisk_execute_command);
}
if (execute_command) { / You may override init and ask the kernel
to execute a custom program using the
"init=" kernel command-line argument If
you do that, execute_command points to the
specified program /
run_init_process(execute_command);
}
/ Else search for init or sh in the usual places /
run_init_process( " /sbin/init " );
run_init_process( " /etc/init " );
run_init_process( " /bin/init " );
run_init_process( " /bin/sh " );
panic( " No init found Try passing init= option to kernel " );
init会接受/etc/inittab的指引。它首先执行/etc/rcsysinit中的系统初始化脚本,该脚本的一项最重要的职责就是激活对换(swap)分区,这会导致如下启动信息被打印:
Adding 1552384k swap on /dev/hda6
让我们来仔细看看上述这段话的意思。Linux用户进程拥有3 GB的虚拟地址空间(见27节),构成“工作集”的页被保存在RAM中。但是,如果有太多程序需要内存资源,内核会释放一些被使用了的RAM页面并将其存储到称为对换空间(swap space)的磁盘分区中。根据经验法则,对换分区的大小应该是RAM的2倍。在本例中,对换空间位于/dev/hda6这个磁盘分区,其大小为1 552 384 KB。
接下来,init开始运行/etc/rcd/rcXd/目录中的脚本,其中X是inittab中定义的运行级别。runlevel是根据预期的工作模式所进入的执行状态。例如,多用户文本模式意味着runlevel为3,X Windows则意味着runlevel为5。因此,当你看到INIT: Entering runlevel 3这条信息的时候,init就已经开始执行/etc/rcd/rc3d/目录中的脚本了。这些脚本会启动动态设备命名子系统(第4章中将讨论 udev),并加载网络、音频、存储设备等驱动程序所对应的内核模块:
Starting udev: [ OK ]
Initializing hardware network audio storage [Done]

最后,init发起虚拟控制台终端,你现在就可以登录了。

Linux内核基于ARM64架构。Linux最早是由芬兰LinusTorvalds为尝试在英特尔x86架构上提供自由免费的类Unix *** 作系统而开发的。

该计划开始于1991年,该计划的早期有一些Minix黑客提供了协助,而今天全球无数程序员正在为该计划无偿提供帮助。

嵌入式里做linux内核开发有没有前途

搜索“linux”,更可以获得近2000条记录。从这些职位上看,市场上需要的嵌入式人才必须具备C语言编程经验、嵌入式 *** 作系统(嵌入式Linux)、具有内核裁剪经验、具有驱动程序开发经验。这些都是在学校无法学到的知识。尽管很多大学的电子、计算机专业都开设了程序设计、微机原理、单片机等课程,但高校输送的人才与企业需要的人才却始终没有对应上。
根据《2011-2012年中国嵌入式开发从业人员调查报告》得出结论:在社会生活压力不断增大、大学生就业难的今天,随着高校专业学科建设更加趋于灵活高效,嵌入式及相关专业在大学校园内的普及和发展也达到了前所未有的速度。在高校更加贴近企业需求的实训模式的引导下,越来越多的计算机、电子、自动化等相关专业的本科生和研究生开始将自己的职业规划定位到高薪诱人且发展前景极为广阔的专业嵌入式开发领域。

arm嵌入式编程和linux内核开发有什么区别,哪个有前途

一个做应用,一个做底层移植(注意哦是移植,谁敢从0开始写),两者都会更有前途,反正单纯搞应用最没前途

嵌入式软件开发有没有前途?

没有吧?其实软件并不总是需要创新,干的时间长了,好多软件都做成了模块,大多数新工程都是重新搭建一下,新写的东西比较少。

做嵌入式linux内核开发要不要学数电模电吗

标准的答案!1:嵌入式是必须要和处理器架构打交道的!和处理器有关的电路可以说都是数字电路;所以嵌入式必须要懂数字电路; 2:linux内核开发:个人感觉还是要懂的!因为linux内核有两部分代码:和处理器架构有关的:~/arch/目录下面的代码;和通用代码;和架构相关的就是和硬件打交道了; 3:个人感觉能高Linuxkernel开发的人都是特别大神级的人物;中国好像不多;搞LinuxDriver的倒是挺多!但真正大牛(像linux社区的大牛)也不多! 4:个人感觉你问这个问题问的有点问题……把自己的目标放的太大了!

linux应用开发和linux内核开发有区别吗,哪个有前途

当然有区别了:linux应用开发是上层软件应用的开发,主要利用linux中的开源代码进行软件开发,是一些应用性的,跟人的需求关系有关系。
linux内核开发是开发系统底层的软件开发,用硬件关系很大,主要跟底层的硬件有关,比如: *** 作寄存器,驱动一些模块等。
底层较难,主要跟兴趣有关,linux内核开发的前途很好,转行业比较好转,灵活性很强

linux网络编程和linux内核开发哪个有前途

在中国真正有内核开发需求的公司并不多。
但是真正做的好的话,钱一定少不了
内核开发难度更大,首先是你要整体掌握linux结构层次,还需要对硬件很熟悉
网络编程相对简单一些

嵌入式系统linux内核开发实战指南 这本书好么

《嵌入式系统Linux内核开发实战指南(ARM平台)》凝聚了作者12年的工作经验和学习心得与体会,内容覆盖了嵌入式系统Linux内核开发的各个方面。作者根据自己11年的一线工作经验,介绍了嵌入式系统的概念、组织架构、工作原理、软硬件设计流程、开发调试方法以及嵌入式Linux的开发方法与技能,其中列举了许多作者工作中的实际案例;
●对于经验非常丰富的高手,可以参照详细目录直接阅读代码透析Linux内核实现原理的相关章节
●对于入行多年的工程师,本书包含作者10多年的实战经验与技能,让你遇到难题不求人
●对于刚起步的初学者,本书详细介绍了嵌入式Linux开发流程和方法,让你快速入门,不走弯路

Windows内核开发 vs 嵌入式开发 前途问题,谢谢!

这两个方向都是比较好的方向,但学起来确实不容易。不知道你的基础如何。做开发的人不要永远在一线做开发,做到一定的程度应该转型搞管理。Windows内核、驱动开发我不了解,前景如何不得而知;VxWorks我倒是了解一些,这个方向不错,它代表了嵌入式 *** 作系统的最高水平。能熟练掌握VxWorks平台下的嵌入式系统研发,你就真成牛人了,不是象牛一样工作哦,而是牛B哦

请问LINUX内核开发,LINUX应用开发,LINUX嵌入式开发LINUX开发前景如何,高分求助

linux开发前景不错的,个人建议你这个时期主要是学习,丰富自己的开发经验,内核开发会让你更深入扎实的了解linux系统,嵌入式开发经验能给你更多的硬件知识的补充,建议你在这2方面若有机会有好的环境来学习的话就优先先学习吧,这2方面我认为前景更远大

去日本做嵌入式开发有前途吗

就是赚点打工钱,提高些经验,也没什么坏处,但前途还是在国内,很多人都回来了,毕竟软件都是外包给我们做的,核心架构人家不用我们开发。


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/yw/12688955.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-27
下一篇 2023-05-27

发表评论

登录后才能评论

评论列表(0条)

保存