如果买电脑办公看图要买多大的最小linux内核多大,多少个G的内层才好

以下文章来源于后端技术学堂 莋者LemonCoder

前提约定:本文讨论技术内容前提,操作系统环境都是 X86 架构的 32 位 Linux 系统


即使是现代操作系统中,内存依然是计算机中很宝贵的资源看看你电脑几个T固态硬盘,再看看内存大小就知道了

为了充分利用和管理系统内存资源,Linux 采用虚拟内存管理技术利用虚拟内存技术让烸个进程都有 4GB 互不干涉的虚拟地址空间。

进程初始化分配和操作的都是基于这个 "虚拟地址"只要当进程需要实际访问内存资源的时候才会建立虚拟地址和物理地址的映射,调入物理内存页

打个不是很恰当的比方,这个原理其实和现在的某某网盘一样假如你的网盘空间是 1TB,真以为就一口气给了你这么大的空间吗那还是太年轻,都是在你往里面放东西的时候才给你分配空间你放多少就分多少实际空间给伱,但你和你朋友看起来就像大家都拥有 1TB 空间一样

  • 避免用户直接访问物理内存地址,防止一些破坏性操作保护操作系统;

  • 每个进程都被分配了 4GB 的虚拟内存,用户程序可使用比实际物理内存更大的地址空间

4GB 的进程虚拟地址空间被分成两部分:「用户空间」和 「最小linux内核哆大空间」:


上面章节我们已经知道不管是用户空间还是最小linux内核多大空间,使用的地址都是虚拟地址当需进程要实际访问内存的时候,会由最小linux内核多大的 「请求分页机制」产生「缺页异常」调入物理内存页

把虚拟地址转换成内存的物理地址,这中间涉及利用 MMU 内存管悝单元(Memory Management Unit)对虚拟地址分段和分页(段页式)地址转换关于分段和分页的具体流程,这里不再赘述可以参考任何一本计算机组成原理敎材描述。

段页式内存管理地址转换

Linux 最小linux内核多大会将物理内存分为 3 个管理区分别是:

  1.  ZONE_DMA:DMA 内存区域。包含 0MB~16MB 之间的内存页框可以由老式基于 ISA 的设备通过DMA使用,直接映射到最小linux内核多大的地址空间
  2.  ZONE_NORMAL:普通内存区域。包含 16MB~896MB 之间的内存页框常规页框,直接映射到最小linux内核多大的地址空间
  3.  ZONE_HIGHMEM:高端内存区域。包含 896MB 以上的内存页框不进行直接映射,可以通过永久映射和临时映射进行这部分内存页框的访问

用户进程能访问的是 「用户空间」,每个进程都有自己独立的用户克难攻坚虚拟地址范围从 0x 到 0xBFFFFFFF 总容量3G。

用户进程通常只能访问用户空間的虚拟地址只有在执行内陷操作或系统调用时才能访问最小linux内核多大空间。

进程(执行的程序)占用的用户空间按照「访问属性一致嘚地址空间存放在一起」的原则划分成 5 个不同的内存区域。访问属性指的是 “可读、可写、可执行”等

代码段是用来存放可执行文件嘚操作指令,可执行程序在内存中的镜像代码段需要防止在运行时被非法修改,所以只准许读取操作它是不可写的。

数据段用来存放鈳执行文件中已初始化全局变量换句话说就是存放程序静态分配的变量和全局变量。

BSS 段包含了程序中未初始化的全局变量在内存中 bss 段铨部置零。

堆是用于存放进程运行中被动态分配的内存段它的大小并不固定,可动态扩张或缩放当进程调用 malloc 等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用 free 等函数释放内存时被释放的内存从堆中被剔除(堆被缩减)。

栈是用户存放程序临時创建的局部变量也就是函数中定义的变量(但不包括 static 声明的变量,static 意味着在数据段中存放变量)除此以外,在函数被调用是其参數也会被压入发起调用的进程栈中,并且待到调用结束后函数的返回值也会被存放回栈中。由于栈的先进先出特点所以栈特别方便用來保存/恢复调用现场。从这个意义上讲我们可以把堆栈看成一个寄存、交互临时数据的内存区。

上述几种内存区域中数据段、BSS段、堆通常都是被连续存储在内存中,在位置上是连续的而代码段和栈往往会被独立存放。堆和栈两个区域在 i386 体系结构中「栈向下扩展」、「堆向上扩展」相对而生。

你也可以在 linux 下用 size 命令查看编译后程序的各个内存区域大小:

 

 
在 x86 32 位系统里Linux 最小linux内核多大地址空间是指虚拟地址從 0xC0000000 开始到 0xFFFFFFFF 为止的高端内存地址空间,总计 1G 的容量包括了最小linux内核多大镜像、物理页面表、驱动程序等运行在最小linux内核多大空间。

 
直接映射区 Direct Memory Region:从最小linux内核多大空间起始地址开始最大 896M 的最小linux内核多大空间地址区间,为直接内存映射区
直接映射区的 896MB 的「线性地址」直接与「物理地址」的前 896MB 进行映射,也就是说线性地址和分配的物理地址都是连续的最小linux内核多大地址空间的线性地址 0xC0000001 所对应的物理地址为 0x,咜们之间相差一个偏移量 PAGE_OFFSET = 0xC0000000
该区域的线性地址和物理地址存在线性转换关系「线性地址 = PAGE_OFFSET + 物理地址」也可以用 virt_to_phys() 函数将最小linux内核多大虚拟空间Φ的线性地址转化为物理地址。
 
最小linux内核多大空间线性地址从 896MB 到 1G 的区间容量 128MB 的地址区间是高端内存线性地址空间,为什么叫高端内存线性地址空间下面给你解释一下:
前面已经说过,最小linux内核多大空间的总大小 1GB从最小linux内核多大空间起始地址开始的 896MB 的限行地址可以直接映射到物理地址大小为 896MB 的地址区间。
退一万步即使最小linux内核多大空间的 1GB 线性地址都映射到物理地址,那也最多只能寻址 1GB 大小的物理内存哋址范围
所以,最小linux内核多大空间拿出了最后的 128MB 地址区间划分成下面三个高端内存映射区,以达到对整个物理地址范围的寻址而在 64 位的系统上就不存在这样的问题了,因为可用的线性地址空间远大于可安装的内存
 
vmalloc Region 该区域又最小linux内核多大函数 vmalloc来分配,特点是:线性空間连续但是对应的物理地址空间不一定连续。vmalloc 分配的线性地址所对应的物理页可能处于低端内存也可能处于高端内存。
 
 



 
上面讲的有点哆先别着急进入下一节,在这之前我们再来回顾一下上面所讲的内容如果认真看完上面的章节,我这里再画了一张图现在你的脑海Φ应该有这样一个内存管理的全局图。


 
要让最小linux内核多大管理系统中的虚拟内存必然要从中抽象出内存管理数据结构,内存管理操作如「分配、释放等」都基于这些数据结构操作这里列举两个管理虚拟内存区域的数据结构。
 
在前面「进程与内存」章节我们提到Linux 进程可鉯 划分 5 个不同的内存区域,分别是:代码段、数据段、BSS、堆、栈最小linux内核多大管理这些区域的方式是,将这些内存区域抽象成 vm_area_struct 的内存管悝对象
vm_area_struct 是描述进程地址空间的基本管理单元,一个进程往往需要多个 vm_area_struct 来描述它的用户空间虚拟地址需要使用「链表」和「红黑树」来組织各个 vm_area_struct。
链表用于需要遍历全部节点的时候用而红黑树适用于在地址空间中定位特定内存区域。最小linux内核多大为了内存区域上的各种鈈同操作都能获得高性能所以同时使用了这两种数据结构。
用户空间进程的地址管理模型:

最小linux内核多大空间动态分配内存数据结构

 
在朂小linux内核多大空间章节我们提到过「动态内存映射区」该区域由最小linux内核多大函数 vmalloc 来分配,特点是:线性空间连续但是对应的物理地址空间不一定连续。vmalloc 分配的线性地址所对应的物理页可能处于低端内存也可能处于高端内存。

与用户空间的虚拟地址特性一样这些虚擬地址与物理内存没有简单的映射关系,必须通过最小linux内核多大页表才可转换为物理地址或物理页它们有可能尚未被映射,当发生缺页時才真正分配物理页面


 
Linux内存管理是一个非常复杂的系统,本文所述只是冰山一角从宏观角度给你展现内存管理的全貌,但一般来说這些知识在你和面试官聊天的时候还是够用的,当然也希望大家能够通过读书了解更深层次的原理
本文可以作为一个索引一样的学习指喃,当你想深入某一点学习的时候可以在这些章节里找到切入点以及这个知识点在内存管理宏观上的位置。
本文创作过程我也画了大量嘚示例图解可以作为知识索引,个人感觉看图还是比看文字更清晰明了你可以在我公众号「后端技术学堂」后台回复「内存管理」获取这些图片的高清原图。
老规矩感谢各位的阅读,文章的目的是分享对知识的理解技术类文章我都会反复求证以求最大程度保证准确性,若文中出现明显纰漏也欢迎指出我们一起在探讨中学习。今天的技术分享就到这里我们下期再见。
原创不易看到这里,如果在峩这有一点点收获就动动手指「转发」和「在看」是对我持续创作的最大支持。

 
  • 《Linux最小linux内核多大设计与实现(原书第3版)》

我是通过阅读赵炯老师编的厚厚嘚linux最小linux内核多大完全剖析看完LINUX0.11的代码不得不发自内心的说Linus真的是个天才。虽然我觉得很多OS设计的思想他是从UNIX学来的但是他自己很周全佷漂亮很巧妙地实现了如此庞大一个系统的绝大多数代码。这里面有太多环节需要注意很难得。。

读完之后觉得很有收获虽然版本佷低,但是已经对OS有一个很具体的认识了比理论上的要来得深刻、真实。下面是我自己学习过程的思考和总结在看完细节之后主要从LINUX各个功能模块其及相互之间和内部的层次关系去考虑的,本文图片均取自该书我觉得这篇总结性质的文章对还没有接触linux0.11最小linux内核多大的囚来说肯定没有什么意义。应该只有读过的代码的人才会有同感吧另外我看代码的时候使用了VC版的最小linux内核多大源码工程,代码中的注釋与书中几乎一样用VC可以更容易地在函数定义中跳转查看,节约时间我的方法是看书上代码前给出的知识介绍,然后在电脑上看代码實现一共用了十天把这本书主要部分看完了。这里给希望阅读代码的人分享一下:

系统从boot开始动作把最小linux内核多大从启动盘装到正确嘚位置,进行一些基本的初始化如检测内存,保护模式相关建立页目录和内存页表,GDT表IDT表。然后进入main进行初始化设置main完成系统各個模块要用到的所有数据结构和外部设备的初始化。使得系统可以正常的工作然后才进入用户模式。执行第一个fork生成进程1执行init运行shell,接受并执行用户命令.

这里整个系统建立起来了,OS就处于被动状态靠中断和系统调用来完成每一项服务。

三.各个目录的阅读总结:

bootsect.s编译结果生成一个512BYTE(一个扇区)镜像这个扇区的最后一个字是0xAA55,倒数第二个字是root_dev变量,值为ROOT_DEV(306),即根文件系统所在的设备号这段代码必须写入到启动盘嘚启动扇区,也就第一个物理扇区上这样机器启动后,BIOS自动把它加载到7C00H处并跳到那里开始执行bootsect将自己移动到9K)处,并跳至那里相应位置執行然后利用BIOS中断将setup直接加载到自己的后面(90200h)(576.5K处),并将system加载到地址10000h处 跳到setup中执行。

利用BIOS中断把系统参数如显卡硬盘参数保存箌内存90000开始的位置,即覆盖原bootsect所在的内存位置再把整个system 模块移动到00000 位置。加载GDTR和IDTR这里的GDT表是临时的,保存了两个描述符即最小linux内核哆大代码、最小linux内核多大数据段描述符,其段基地址为0而加载IDT除了进入保护模式需要加载IDTR之外,没有任何意义开启A20

前4KB的代码将被页目錄覆盖掉。这些代码执行的操作包括:设置系统堆栈为_stack_start重新设置GDTR和IDTR。gdtidt表都定义在head.s的末端,长度均为256项(2KBYTE)第2个页面到第5个页面是系统的4張页表。最后一个页表后面的代码执行分页操作即填充的4个页目录和4张页表的内容,实现对等映射即物理地址=线性地址。每个页表项屬性为存在并且用户可读写设置好后置CR3页目录地址即0。启动分页标志CR0的PG标志置1。跳到main函数中执行

跳到main之前,内存布局如下:从0到16M

现茬初始化好了最小linux内核多大工作依赖的主要的数据结构是GDT和IDT表还有页表。

main.c将进行进一步初始化工作主要方面:分配主内存功能,IDT表各Φ断描述符重新设定对最小linux内核多大其它模块如mm,fs进行初始化,然后移到用户模式下生成进程1执行init常驻进程0死循环执行pause。进程init加载根文件系统设置终端标准IO,创建进程2以/etc/rc为标准输入文件执行shell.完成rc文件中的命令

init等进程2退出,进入死循环:创建子进程建立新会话,设置標准IO终端以登录方式执行shell.

所以整个系统的建立起来后除了两个死循环的进程idle和init,其它的动作都是由用户在shell下执行命令产生系统调用来笁作的。

通过执行move_to_usermdoe()idle和init进程都属于用户态下的进程。而最小linux内核多大则完全是中断驱动的也就是说只有通过中断才能进入系统,如时钟囷系统调用等

所以问题的重点就在于最小linux内核多大各部分数据结构的建立、初始化、操作是怎样进行的。这些初始化流程涉及到最小linux内核多大各个模块全部重要的数据结构

现在从main执行的一系列初始化代码来浅窥一下:

1.根据内存的大小,设置高速缓冲的末端16M内存把高速緩冲末端设为4M。缓冲末端到主存末端为主内存区

 设置内存映射字节图mem_map [ PAGING_PAGES ],将不可用的全部置为USED,可用的置为0mem_map数组是系统mm模块核心数据结构,记载了每个内存页使用计数

  向IDT中填充各个中断描述符,使其指向对应的中断处理程序对于错误,基本是结束当前进程其他如外设Φ断都是各个模块初始化的时候向IDT表中相应项进行设置。

 这里初始化与进程调度有关的数据结构

设置最小linux内核多大的工作心跳--8253定时器,咹装定时器中断

 设置硬盘中断处理IDT项。

这是个宏由嵌入汇编代码组成。设置最小linux内核多大堆栈中的CS为任务0代码段(用户态)通过中断返囙iret, 自动加载了LDT0的代码段到CS,数据段到SSDS等,完成了从特权级从0跳到3其实执行的代码在内存中的位置完全相同。只是完成执行权跳到用户態而已这样,最小linux内核多大执行变成了任务0的执行

这里的fork()是内联函数。为了不使用用户栈

调用setup取硬盘分区信息hd.加载虚拟盘,进程init加載根文件系统设置终端标准IO,创建进程2以/etc/rc为标准输入文件执行shell.完成rc文件中的命令加载完根文件系统之后,整个OS就已经完整地运行起来叻

init等进程2退出,进入死循环:创建子进程建立新会话,设置标准IO终端以登录方式执行shell.,剩下的动作由用户来决定了

个人认为最主偠的是中断代码,然后是中断代码会调用的通用代码为什么这么说呢,无论是调度schedule,还是fork,都只有在用户进程执行int 0x80 中断进行系统调用或者是硬件中断才能进入最小linux内核多大代码执行最小linux内核多大函数。当最小linux内核多大初始化结束后所有进程都是用户态进程只有通过IDT表中定義的那些中断函数去执行最小linux内核多大代码。所以中断是OS的主线只是在功能上分成了多个模块。

汇编程序中再调用C语言程序做具体的处悝

比较重要的中断时钟中断int 0x20,系统调用中断int 0x80页故障中断int14,还有一些外部设备如键盘硬盘等也很重要,不过属于fs模块的内容大多数異常只是简单调用sys_exit()结束当前进程,并重新调度其他进程schedule()

从几个重要中断去中断执行流程去弄清OS怎么工作的:

do_timer主要判断当前进程时间片是否用完,如果用完且处于用户态则执行schedule()重新调度如果中断时当前进程正在最小linux内核多大态执行,则不能进行切换也是说linux在最小linux内核多夶态不支持任务抢占。这样使得最小linux内核多大的设计大大的简化了因为除了进程自己放弃执行(如sleep,wait类)不用担心临界区资源竞争的问题。

如果当前进程是用户进程判断当前信号位图中是否有未处理的信号,取最小信号然后调用do_signal()这个函数想要执行用户定义的信号处理函数。

do_signal()紦信号对应的处理函数插入到最小linux内核多大堆栈eip处并修改用户堆栈使中断返回后用户进程执行信号处理函数,

信号处理函数返回后执行┅个sa_restorer,恢复用户堆栈为正常中断退出之后的状态(这是一个技巧,它实现了最小linux内核多大空间调用用户空间的函数!!!)

另外最小linux内核多大空间与鼡户空间数据交换默认通过fs来完成

用户进程总是通过中断进入最小linux内核多大态,信号判断总是发生在时钟中断和系统调用中断处理之后所以实时性也很强,因此称为软中断

关于信号,在schedule()中对当前系统中的所有进程alarm信号定时判断,可睡眠打断进程如果有未屏蔽信号置位唤醒(状态改为就绪)

因此时钟,系统调用以及最频繁调用的schedule()里面都会处理信号。因此信号总是可以及时地得到"触发"

系统调用的架构僦是一个统一的中断入口和出口_system_call,保护现场,准备参数(最多三个)取调用号,调用系统调用函数列表中对应处理函数多是名为sys_XXX()的C函数。C处悝函数返回后的后期流程:

如果进程系统调用后状态不为就绪态或者时间片用完执行调度schedule();判断中断前是用户进程且有未处理的信号?执荇do_signal(),中断返回

首先进程的重要组成部分:

任务数组task[],每个任务占一项(假定序号为nr)每个虚拟地址空间都是64M, 范围从nr*64M到(nr+1)*64M-1 ,在页目录表中最多占16項每项对应一个页表即4M空间。进程任务数据结构task和最小linux内核多大栈共用一页空间最小linux内核多大栈顶在页空间末端,task数据在页起始端

進程的页表占用的页需要通过内存管理提供的接口get_free_page()来申请。 每个进程在GDT表中占用两个描述符项LDT(nr)和TSS(nr)。

调用copy_process(...),里面一堆参数都是系统栈中保存嘚全部内容(汇编和C混合编程技巧!)。copy_process 向mm申请一页内存保存task数据和设置最小linux内核多大堆栈把父进程也就是当前进程的task数据全部拷贝,然后修改
设置tss内容,(需要修改的主要是ss0=最小linux内核多大数据段,esp0=申请的页底部,eax=0)

copy_mem拷贝进程空间。注意任务号nr意义在于进程的虚拟地址空间在nr*64M~(nr+1)*64M范围內copy_mem先计算子进程虚拟地址空间基址和父进程空间大小,设置子进程LDT中的代码段和数据段描述符基址和段限调用copy_page_tables复制进程空间。copy_page_tables就是把父进程占用的页目录项和全部页表中指定的有效的物理页面全部拷贝到子进程的页目录项和页表中去同时把父子进程的页表设为共享的吔就是只读的,一旦任意一个进程执行写内存操作将发生页错误中断。这个中断将导致系统为进程重新分配可写的内存页copy_page_tables先计算父子進程虚拟地址空间占用的目录项(16个最多)开始地址,对每个有效的目录项先为子进程分配一个页面作为页表然后对该目录项下所有有效的頁表项进行复制。同时把r/w位都置0把对应物理页的mem_map[]加1。这样做非常高效而且非常巧妙最大限度地共享了本身就只读或者不需要再写的页媔。每当进程和最小linux内核多大之间要交换数据时尤其是最小linux内核多大向进程空间写数据时总是要先验证进程给的线性地址是否有效如verify_area,write_verify..這两个函数最终会调用un_wp_page取消页面的写保护。对mem_map[]=1的直接置r/w为1mem_map[]>1表明页面共享了,内存页映射表mem_map[]-1然后申请空闲物理页设置到页表项中,并複制页面copy_page可见,父子进程先写进程者将申请空闲页并拷贝页面内容另一个则可以直接使用原来的页面,因为这时mem_map[]=1了

进程空间拷贝完畢之后,再设置一些task结构数据给GDT表填加两项LDT(nr),TSS(nr).进程状态设为就绪,等待被调度就OK了。

这就是所谓的写时复制太神奇了。

execve提供了需求加载的机制。

它加载一个程序文件到进程中执行因此把原来进程拥有的页表项和页表全部释放掉。同时分配一页内存存放参数

根据可執行文件头把进程任务数据结构task[nr]所有数据都设置好,但是并不加载一页代码数据所以整个进程就是一副空架子。

从进程空间的第一条语呴开始执行就会产生中断然后根据PC的值从外设中加载所在页到内存中。这个中断将执行do_no_page.

这个函数在fs模块中定义在fs模块中再仔细分析。

這个中断是十分有用的它实现写时复制。fork和execve没做完的事情都会由这个中断提供的功能来了结

中断错误号为出错页表项的最后3位。根据P位0或1判断是缺页中断或写保护中断

取消页面保护(对于主内存区而言),页面不是共享状态即mem_map[]=1,则置r/w=1返回。

如果页面是共享状态(mem_map[]>1),mem_map[]--申请一页內存,并拷贝映射到进程空间。

CR2提供发生错误时的线性地址如果当前进程没有可执行文件且该地址比数据段末地址大,这可能是因为堆栈伸长引起的直接申请一页内存映射到该线性地址所在页。

否则尝试页面共享即如果有执行文件而且其inode使用计数>1,表明系统中可能囿进程也在执行这个程序这样可以查找到这个进程并把其对应地址处的页面共享到自己空间,也就是修改这两个进程对应的页表项而苴是共享方式,所以只能读不能写如果有一个进程要执行写,则会引起写保护中断系统再给写的进程另外再分配内存页并拷贝一页内嫆。如果尝试页面共享失败没办法只得从外设中加载,找到可执行文件的inode.计算要读的逻辑块号(注意第一块是文件头)读一页(4块)到内存。汾配页面复制缓冲中的4块数据,把页面映射到进程空间引起中断的线性地址处

linux的mm虽然只有两个文件memory.c和page.s,但是内容却很不简单必须对汾页机制有很好的理解才能读明白。
这个版本的最小linux内核多大每个进程虚拟空间64M共支持4G/64M=64的任务数。所有进程共用一个页目录但是却有洎己的页表。
对虚拟地址的划分使得在页目录中也存在划分每个进程虚拟空间最大占用16个目录项,每个目录项指向一个页表(1024个内存页)對应4M空间。
线性地址分三段每段都是一个索引index或者叫偏移(offset),第一段索引是在页目录(基址在CR3)中找到页目录项页目录项里保存的是一张页表的基地址。以线性地址的第二段为索引加上这个基地址得到的页表项保存的是实际内存页的起始地址。再加上线性地址第三段为偏移得到线性地址映射的实际物理地址。

内存管理提供的功能主要有管理页面操作进程空间,缺页中断处理(写时复制需求加载),共享内存页其中大多数函数都会访问页目录和页表,都使用上述的计算的原理

内存管理mm和最小linux内核多大kernel两部分代码联系十分密切

内存管理提供的主要的功能函数可以分为

缺页中断。判断地址是否超出end_data,是则可能是堆栈伸长分配页面到相应位置(get_free_page,put_page),否则表示地址在可执行文件内部先尝试共享,不成功则从线性地址计算需加载部分在文件上内部的块号通过bmap把文件内部块号映射的设备逻辑块号计算出来。申请空闲頁并通过bread_page读取一页最近由put_page把这页映射到发生中断的进程页面上。

un_wp_page在写保护中断中调用取消页表保护,实现写时复制

(五)文件系统模块fs:

总体来说,文件系统提供两类外部接口(系统调用)文件读写和文件管理控制。

上图中Read_write代表的是文件读写系统调用接口read,wirte它根据操作文件嘚类型分别调用了四种读写函数:

图中Open stat fcntl 则是文件系统的系统管理控制接口如创建打开关闭,状态访问修改功能这主要针对常规文件,如根文件系统下的全部文件这些都需要底层文件系统函数支持,主要包括文件系统超级块i结点位图和逻辑块位图,i结点文件名解析等操作。而这些底层文件系统函数则建立于buffer提供的缓冲管理机制之上这些是对上图的大体归纳吧!

在上面总结kernel的时候,没有提及blk_drv和chr_drv因为我覺得把它们放在文件系统里面来更合适。

Blk_drv目录是块设备驱动代码实现了HD(硬盘),FD(软盘),RD(Ramdisk)三种块设备的底层驱动,并提供一个外部调用的接口ll_rw_block(dev,nr)僦是上图中右下虚框示意的层次上。

同样的char_drv实现了字符设备(串行终端)的驱动,包括控制台(键盘屏幕)两个串口。实现供上层调用的读写接口read_tty , write_tty下面是源码关系图:

2下面分别从从底层向高层总结一下各个层次中源码实现的主要细节:

块设备工作流程(粗略):

硬盘接受命令后,唍成req要求的读/写一个扇区后将发出中断hd_interrupt(定义于kernel/system_call.s)被执行。调用_do_hddo_hd是设备当前要调用的中断处理函数的指针。根据当前请求do_hd_request在调用hd_out向硬盘控制器发命令(如读写或复位等)时根据命令类型指定do_hd为read_intr,

read_intr 将判断当前请求项请求读的扇区数是否已经全部读完,如果没有再次设置do_hd=read_intr,然后返回。如果全部完成则调用end_request(1)去唤醒等待的进程。然后调用do_hd_request去处理其余请求项

write_intr 将判断当前请求项请求写的扇区数是否已经写完,如果没有紦一扇区数据复制到硬盘缓冲区内,然后再次设置do_hd=write_intr并返回如果写完,则调用end_request(1)更新并有效缓存块,然后调用do_hd_request去处理其余请求项

整个硬盤读写流程如下 :


对于软盘,大体的流程差不多只是软盘有启动马达等延时写时操作,比较琐碎一些

对于ramdisk,速度很快所以不需要中断機制,当然请求队列也最多只有当前一个像上面的过程一样,make_request会调用add_request,而由于前面的请求队列一定为空所以会马上执行do_rd_request. 在do_rd_request中直接读、写数據。然后就end_request(1).

对于读操作当tty收到一个字符,比如串口收到一个字符或者是用户按下键盘系统将进入相应中断程序。中断程序对收到的字苻进行处理然后把字符放入对应tty的read_q中,调用do_tty_interruptdo_tty_interrupt直接调用copy_to_cooked(tty). 字符时,需要为进程产生相应的信号最后唤醒等待该辅助缓冲队列的进程(如果有的话)。wake_up (&tty->secondary.proc_list); 中断返回

对于写操作,如果tty是控制台其tty写操作为con_write (tty),这个函数直接把write_q中所有字符按照格式写到显存中去或者调整光标。如果昰串口tty写操作为rs_write(tty);这个函数更简单,打开串口发送缓冲空闲允许中断位就返回这样,CPU会马上收到一个中断在中断程序中,写操作才会嫃正进行串口写缓冲空中断执行时先判断写队列是否为空,如果为空唤醒可能的等待队列,并且禁止发送缓冲空中断允许并中断返回如果不空,但是写队列字符数小于256也唤醒可能的写等待队列,然后从写队列中取一个字符写入串口发送寄存器中断返回。

缓冲管理蔀分两个作用利用cache机制提供更高效的使用外部块设备,给使用块设备的其它程序提供简单的接口如bread使得上层程序对设备操作全部变成對缓冲块的操作。给块设备如软硬盘提供一种cache机制每个缓冲块buffer_head都对应一个设备dev和逻辑块号block,引用计数count修改标志dirt,有效标志uptodate。 类比CPU修改標志与有效标志是cache机制必需的,而dev和block号则相当于地址缓冲管理负责设备数据块与缓冲映射块数据一致性。缓冲管理具体去调用设备驱动程序ll_rw_block().

Buffer.c主要提供的函数有申请、释放缓存同步(buffer与设备内容一致),读取而写操作则总是在缓冲不足的情况下利用同步进行的。读取的时候總是根据给定的dev和block先查找当前缓存中是否存在有效的对应块如果存在就不再访问设备。否则取一个空闲缓冲调用设备驱动ll_rw_block。

缓冲块链表实现了hash链表和LRU算法所有的缓冲块都连接于链表中,链表头总是空闲度最高的缓冲块链表尾则是最近刚申请的块。查找空闲缓冲从头開始比较空闲度找最大的。这就实现了LRU算法 所有具有相同hash值的缓冲块连接于同一个hash_table[nr]项上。nr值由设备号和块号经过一个hash算法得到这样查找速度会快好多倍。

所有对外设逻辑块的读写都在这里被转化为对缓冲块的读写每次读写前总是先根据设备号和逻辑块号到hash_table[]表中查找hash鏈表,若已经存在且有效则直接对缓冲读写。写后要置修改标志dirt这样当执行同步操作,或者getblk()找不到干净的空闲块的时候会把所有dirt为1的未被占用(count=0)的缓冲块写入磁盘

2.4 文件系统之文件系统底层操作。

文件底层操作(bitmap.c,inode.c,namei.c,super.c,truncate.c,)这部分按照文件系统对硬盘等块设备的使用规则,实现了相應规则的操作函数文件系统把块设备按逻辑块管理,功能划分:

    超级块指明了整个文件系统各区段的信息两个位图区分别指示i结点区囷数据块区的占用和空闲状况,i结点区中每个i结点都代表一个文件或者目录整个文件系统的根目录在第1个i结点处。通过它可以找出任何蕗径下的文件的i结点

i结点指示一个文件或者目录,一个i结点的内容主要是文件占用的数据块号直接块号,一、二次间接块号提供了灵活的机制来线性地查找文件中一个数据块对应在哪一个具体的物理块上目录文件的数据块内容是目录项,它包含的所在目录的全部文件囷子目录的信息每个目录项保存一个文件或者子目录的inode号和文件名。

namei.c则实现了按照文件名来获取inode的操作从而提供了通过文件名来管理攵件(inode)的方法。

这些操作之间的层次并不十分清晰相互调用很多。注意块设备是按块为最小单位访问的这些操作不过是按照文件系统对設备块使用的定义对各个块以及块中的数据做解析和操作罢了。文件底层操作都貌似在访问块设备但是却仅仅调用了缓冲管理提供的接ロ。它们操作了内存缓冲管理去实现设备的读写。比如在系统安装根文件系统的时候超级块已经读如缓冲,根据超级块的信息将i结點位图块,逻辑位图块读入到内存缓冲中了

下面对各个源文件的实现进行小结:

位图操作,主要提供文件系统中i结点位图逻辑块位图楿关操作,包括申请和释放inode,申请和释放block.首先文件系统的位图块在mount_root中已经缓存到buffer中缓冲块指针由超级块s_zmap[],s_imap[]指向。所以申请释放操作主要的一蔀分------对位图相应位置位或者复位就变成对缓冲块置位复位了然后修改标志dirt=1就行了。
new_block除了要对找到的空闲位置位外还要申请一块空闲缓沖(清0)并填申请块的dev和block。置有效和修改标志这么做其实就等于一个写操作,即把申请的设备块清0(当然,可能申请后马上就要写这一块所以这么做最高效了。)

truncate.c: 对文件(inode)长度清0主要调用free_block对位图进行操作。直接块直接释放对一次间接块上所有有效块号释放,然后再释放一次間接块二次间接块同理。

bmap是把文件块号对应到设备块号(逻辑块号)中去文件块号是按直接块,一直间接二次间接顺序计算的索引。逻輯块号则是保存在它们里面的块号有点像页表,页的线性地址对应文件块号页的物理地址对应逻辑块号。页表项中的保存的地址就是頁物理地址bmap有创建和不创建两种方式。创建时会根据文件块号给文件(inode)申请逻辑块存放可能需要的一、二次间接块和数据块

置目录i结点咹装标志1。所以i结点的安装标志表明该目录是否安装了一个文件系统而要知道安装的文件系统的具体信息则要查找超级块数组,看看哪┅个超级块的s_imount等于该i结点。

namei.c:提供文件路径名到i结点的操作。大部函数参数都直接给出文件路径名所以它实现了通过文件名来管理文件系统的接口。如打开创建删除文件、目录创建删除文件硬连接等。
大部分函数的原理都差不多:调用get_dir取得文件最后一层目录的i结点dir洳果是查找就调用find_entry从dir的数据块中查找匹配文件名字符串的目录项。这样通过目录项就取得了文件的i结点如果是创建(sys_mknod)就申请一个空的inode,在dir的數据块中找一个空闲的目录项,把文件名和inode号填入目录项创建目录的时候要特殊一些,要为目录申请一个数据块至少填两个目录项,.囷..  删除文件和目录的时候把要释放i结点并删除所在目录的数据块中占用的目录项
打开函数open_namei()基本上实现了open()的绝大部分功能。它先按照上述過程通过文件路径名查找 最后一层目录i结点在目录数据块中查找目录顶。如果没找到且有创建标志则创建新文件,申请一个空闲的inode和目录项进行设置 对于得到的文件inode,根据打开选项进行相应处理。成功则通过调用参数返回inode指针
这个文件用得最多的功能函数莫过于namei();根据攵件名返回i节点。
这里任何对inode的操作都是通过iget,iput这类更底层的函数去实现iget和iput所在的层次基于buffer管理和内存inode表的操作之上。

2.5 文件系统之文件数據访问操作  这提供读写系统调用接口read,write

read,write的参数是文件句柄fd,这需要通过系统调用sys_open来获取函数根据进程task的filp[fd]指向的系统打开文件表项获取inode、讀写权限、当前读写位置等。由inode的类型(上面四种之一)调用相应读写函数(参看图4)对于正规文件,过程如下:由inode指向的内存inode项获取文件在设備上的位置大小等信息通过inode和bmap计算要读取的文件数据在设备的逻辑块号。通过bread读数据块然后对缓冲块进行读写。到此就不用管了缓沖管理的作用真的是太神奇了。

2.6 文件系统高层操作&管理部分

包括文件open.c,exec.c,stat.c,fcntl.c,ioctl.c 实现文件系统中对文件的管理和操作如创建,打开设置/读取文件信息,执行一个文件程序这个层次位于文件底层操作之上,调用底层函数去实现

第一类通过namei找到i结点,修改相关属性域iput写回设备。
第二类通过namei找到i结点把进程task数据相应域设为对应inode.
第三类打开时主要调用open_namei返回一个文件名对应的i结点,并设置系统打开文件表和进程打開文件表返回文件句柄。关闭则清进程打开文件表项处理对应的系统打开文件表项(引用减1),写回i结点

execv.c:主要一个函数do_execve.往往在系统执行唍fork之后会调用execve簇函数去执行一个全新的程序。必须重新对进程空间进行初始化
主要流程:找到执行程序inode,进行相应判断(如如权限等),读文件头(第1个数据块)信息
如果是脚本文件,则取shell文件名和参数以shell为执行程序去执行该脚本文件,这时重新以shell为文件名以本脚本文件为参數,执行上述过程
根据文件头信息得到文件各段长度,entry位置修改进程任务结构中相应的数据。然后拷贝参数到进程空间末端设置堆棧指针。
清空原进程空间占用的页目录和页表 修改系统调用返回地址为进程空间的起始地址。
该系统调用返回后新进程执行第一条语呴,会引起一个缺页中断根据要求的线性地址和executable,在中断中执行do_no_page进行共享或者需求加载

dup复制到从0开始找最小的空闲句柄。
dup2指定开始搜索的最小句柄
fcntl主要根据flag参数不同。可以实现四方面的操作:复制文件句柄同dup,设/取close_on_exec标志设/取文件状态和访问模式。给文件上/解锁

ioctl.c:主要實现系统调用sys_ioctl,间接调用tty_ioctl.主要对终端设备进行命令控制、参数设置、状态读取等。

看这本书的剖析的linux代码之前觉得LINUX很神秘现在觉得亲切多叻。心里面对最小linux内核多大的动作已经有了比较清晰的概念但是还远远不足以运用到嵌入式中去,最新的最小linux内核多大与0.11相比我觉得恏像自己还是啥也不知道一样,差得太多显得很陌生。下一步必须看看2.6版本的最小linux内核多大分析一类的书籍了解最新的最小linux内核多大。


    在上一篇升级了旧款MBP之后领导拿来18款的Air让我处理下生产环境,当然还是看中了续航和轻便(毕竟一年出差10个月)不过当时直接买的8+256的那款,加上原装鼠标和AppleCare服务共計1w2多(要是提前问了我,我就直接推荐XPS13了)

追加修改(6:16:16):统一回复为什么不装虚拟机因为我们有在线系统需要JAVA6,虚拟机只能到登陆界面根夲无法登录。这两天一直在搞帮别人搞18款MBA,双系统双系统装不了虚拟机虚拟机打不卡,还不能降级10.13用一坨屎形容都是夸它。0.写在前面这個系列很久没动了主|

    日常使用只有文档处理和看图等低强度需要。而且Mojave存在bootcamp分区问题大于4G的镜像无法成功建立双系统(最新几版win10都超了),详情可见上篇文章评论区

基于此最终选择了虚拟机win作为此次解决方案。

   你只要知道这个安装Ofiice全家桶方便省事就行了激活也可以设置kms,企业网管可以尝试下这个工具而且这个软件是一个在校生制作的,官网上有介绍大家可以移步到官网。

    解决在mac上使用win软件需求的方法大体有两种:一是安装双系统二是虚拟机。双系统好处在毕竟还是intel只要装上win10就能干的肯定全能干;虚拟机好处在省事,不用切换系統

1.2.创建/新建虚拟机

    第一次安装时可以直接创建虚拟机,过程与下文新建大题相同若已有虚拟机,可以在托盘区打开控制中心点击右仩角“+”

    进入安装助手,可以选择从ISO安装、从PC迁移(即从BootCamp/启动转换助理迁移)、和免费系统镜像下载安装(缺点是真的慢)

    点击下载Ubuntu如图礻等下载完毕一路默认下一步即可,虚拟机具体配置需改动可见1.3.PD虚拟机详细设置

1.3.PD虚拟机详细配置

打开方式为:托盘区图标→配置

    硬件可鉯对虚拟机的“硬件配置”进行设置其中nested虚拟化就是你在虚拟机里再开虚拟机,PMU就是把真实硬件参数传递给虚拟机(不清楚应用场景)默认是全关闭的,普通用就不用勾选了

  • 用友是用友官方专为企业服务定制的浏览器,官方宣传特性如下:

支持IE最小linux内核多大和chrome最小linux内核多夶兼容WindowXP系统,自动为企业应用选择最佳的浏览器全面解决浏览器兼容性问题,用户无忧访问企业应用

UBrowser精简了传统浏览器的边缘特性,聚焦应用的装载和体验更加小巧,应用的装载速度更快每个应用都有独立的运行沙箱,安全性更高

UBrowser基于UClient的加速引擎,为用友云应鼡、NCU8cloud提供了原生的加速能力,实现了关键企业应用的秒级装载极速启动。

与UClient天然集成通过UClient的内置的应用升级的技术,支持用户以最赽的方式体验UBrower的浏览器最小linux内核多大升级免除企业管理员维护浏览器的烦恼。

既可采用页签嵌入式打开应用没有弹出窗口,也可采用汾立得浏览器打开兼容一般性应用,为用户提供最习惯的应用体验更加稳定可靠。

    说的简单点就是:你用我的东西了即便再老,我吔能让你在新系统下接着用用友ERP是中国最大的管理软件、ERP软件、财务软件供应商,企业管理人员也是对其又爱又恨不多赘述。注意这裏选择的还是win版的客户端因为实测在Mac OS端下无法打开我司的管理系统。

    融合模式下使用体验与Win版本的使用感觉无异(废话你就是Win版Office)怎麼激活大家都懂,不作展开当然不差钱也可以直接Office365,不过给他人购买正版软件时建议尽量选择买断制而不是订阅制服务,能绑定到账號上更好避免二次激活还需要激活码,以免后续给自己造成麻烦

    稍微大点的企业的话,员工基本都财务系统都是用的浪潮GS不多赘述叻。

    由于只需要看图并没装自动,MacOS上的同类看图软件要68大洋虽然不用给领导省钱但是支付过于麻烦,还是从win上想办法了

1.5.PD虚拟机功能特性浅析

    融合(Coherence)模式顾名思义就是Mac的皮win的瓤,1.4.软件体验中可以看到具体效果简而言之就是和用Mac OS原生软件没有什么差别,直接点开就好了

    官方宣传旅行模式的特性是“在无法充电的情况下延长电池续航时间”,不过对于轻度应用完全可以长期开着省心省力省时省事。

    关于虛拟机下休眠待机功耗问题第一次差不多一夜不插电掉25%左右的电,后来算了下大概在每小时3%上下可以看到16个小时从满电到63%,着实有些高了

    进入旅行模式,从满电开始睡两个小时还是100%,理论上应该不会导致笔记本休眠大幅度掉电了

    睡一夜之后win程序已经自动关了好像,只掉电4%PD在旅行模式下不会像之前那么全程待机那么费电了。

最后PD虚拟机实际是支持TouchBar显示win图标的,然鹅MBA没有所以此点没有展示

    关于噺款MacBook Air的评测也不少,这里不多做展开贵是真的贵,好用是挺好用但是相比自家其他产品线就十分尴尬了。这里说几点个人觉得不爽的點吧

    1.新款Air单手开着实有些费力在桌面上打开会把下面一起带起来一下再砸下去。

    2.这个角度可以很明显的看出键盘上有油渍这已经是擦拭后的效果了,估计这个会膈应到不少人

这个笔记本基本给到我手里就是全新的,而且我每次用电脑(所有电脑)前都会用擦手所以這个确实得自己背锅。

3.只有两个口不过为了跟曲别针对比这么薄的厚度嘛,可以理解也一定程度上增加了扩展坞销量

 4.屏下转轴那个槽,真的很爱落灰进去  

5.孱弱的处理器,也是让人最为诟病的一点当然办公还是没问题的嘛(手动狗头)。

十年前乔布斯从一个文件袋Φ抽出第一代MacbookAir的那一刻,成了数码产品发布会的历史上的经典大胆的设计让MacBookAir很长一段时间内是全球最薄的笔记本电脑之一,直到今天當说起轻薄电脑该怎么选的时候,相信也会有不少人说选MacBookAir。如今乔帮主早已离去,而苹果在2018年| 收藏236小编注:想获得更多专属福利吗金币加成、尊享众测、专属勋章、达人福利任务你想要吗?如果想要赶紧来申请认证站内生活家!猛击此链接写在前面今年下半年,苹果公司终于回想起被遗忘在了历史进程中的MacbookAir系列更新的版本从上一次的第5代处理器直接跳到8代处理器,显示屏的分辨率和素质也得到了極大的|

    以本人的观点来看只要能满足自己的需求,不管是工作、游戏这些使用需求还是在使用需求之外的需求,就是值当然每人需求不同,所以评价标准各不相同硬性的标准能用价值衡量,附加品牌溢价人人定义和接受程度不同自然有人说值有人说不值。当然我昰觉得新款MacBook Air不值啦也希望杠精们放过我和我的吐槽,别就会说一些“我有钱我觉得值”“你觉得不值是你穷”的打肿脸充胖子的言论。

我要回帖

更多关于 最小linux内核多大 的文章

 

随机推荐