免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: chenrvmldd
打印 上一主题 下一主题

也谈谈这四年来对内核的研究 [复制链接]

论坛徽章:
0
11 [报告]
发表于 2011-07-01 13:14 |显示全部楼层
第二题:
关于Bootloader方面的问题:我相信Bootloader有些兄弟研究过Linux的启动过程应该不陌生,在前面的一篇文章中,我曾经说过,Linux内核的内存管理和其他模块几乎都有联系,在这里又一次验证了我说过的话,在这边我想通过Bootloader和内存管理之间的关系提出一个大问题,然后提出几个小问题!
大问题:bootloader和内存管理之间的关系
第一个问题:内存管理既然要去管理内存,前提是它要知道内存有多大,然后才去管理,那么请问内存管理是怎么知道内存有多大的了?
第二个问题:bootloader在嵌入式领域和我们PC机领域关于内存的探测有什么区别?
其实Bootloader这块问题很多,比如:bootloader怎么知道linux内核文件放在哪的?就算知道它在哪,又是怎么确定内核文件没有被破坏,但是我只想问两个关于内存管理相关的!
第一个小问:关于第一个小问,其实我喜欢哪位兄弟能从系统启动开始一直到内存管理初始化结束,整个流程来分析
第二个小问:这个问题要理解Bootloader的作用,以及bootloader关于一些方面的实现细节,同时考察对不同体系结构来讲bootloader的差异化

评分

参与人数 1可用积分 +6 收起 理由
Godbach + 6 感谢分享

查看全部评分

论坛徽章:
0
12 [报告]
发表于 2011-07-01 14:46 |显示全部楼层
我在想一个问题,想了很久,如果版内想研究内存管理的兄弟比较多的话,对内存管理这边比较感兴趣的话,我想到时候能不能抽个时间,谈谈内存管理在整个系统中的架构设计,接口设计,效率设计,流程设计,从各个方面解释一下内存管理,但是我想总结整个内存管理的架构,这确实不易,怕我水平还没有到那个地步,到时候什么地方弄错了会误导大家,因为架构的东西一旦有错误的地方,那么带来的问题是巨大的,所以不敢轻易做这样的总结,虽然我在CU的内核源码版混迹了多年,确实我们版出现了无数篇的好文,但是说实在话:我没有看到一篇关于讲解架构的,这样设计的背后的原理是什么,我希望我能出一篇这样的文章,说实在话,就算ULK这本书虽然是众多搞内核所推崇的一本书,但是它也没有设计到架构方面的讲解,从整个系统的流程角度去讲解,所以当我们看完ULK这本书的时候,其实我们对内核还是一知半解,这个时候如果我们去看源码,再回来看书,可是突然发现源码我们算是看懂了,想去弄懂为什么要这么设计的时候,发现书本上很多东西就没有了!所以,我想抽个时间我一定要弄一个内存管理方面的架构讲解出来!其实,做完我们那个项目的时候,曾经有出版社找过我们希望我们能出一本关于内存管理的书,从架构设计,到整个子模块的设计,从系统的初始化到系统的运作,来讲解内存管理,还是那句话,怕自己水平有限,误导别人,还是婉言拒绝了!

评分

参与人数 1可用积分 +6 收起 理由
Godbach + 6 非常支持

查看全部评分

论坛徽章:
0
13 [报告]
发表于 2011-07-01 14:55 |显示全部楼层
回复 36# Godbach


    好的,到时候我们可以抽个时间大家一起讨论讨论!

论坛徽章:
0
14 [报告]
发表于 2011-07-02 23:38 |显示全部楼层
回复 42# smalloc


    中断其实我觉得不是特别的难理解,操作系统书上讲的比较具体,如果你再去看一下Linux的实现,会发现其实和书上讲的差不多,可是内存管理操作系统书上虽然讲了,但是很笼统,甚至有些东西都没有讲到,比如:碎片管理算法slab,大内存管理buddy system,都没有涉及到,可是中断这么多年了,原理还是老一套的,主要是对8259A的控制,自己去注册相关的中断处理函数,不过对于Linux来讲,为了提高系统的实时性,增加了中断线程化得概念而已!也许我理解的还不够深刻,希望广大兄弟提出批评!

论坛徽章:
0
15 [报告]
发表于 2011-07-02 23:39 |显示全部楼层
回复 43# goter


    呵呵,其实这个项目不是在公司里面参加的,是作为学生的时候参加的!

论坛徽章:
0
16 [报告]
发表于 2011-07-02 23:40 |显示全部楼层
为什么第二个问题到现在为止还没有兄弟解答了?难道我表达的有问题,今天暂时就不把答案贴出来了,等有兄弟回答,或者提出疑问,我再来公布我理解的答案,希望广大内核爱好者积极参与我们的讨论,让我们的版更活跃

论坛徽章:
0
17 [报告]
发表于 2011-07-04 11:24 |显示全部楼层
今天上来看了一下,发现几个兄弟做了一些回复,基本上和我理解的差不多,可是,我喜欢兄弟们更深的去思考一下,问题背后的不同设计的差异,为什么会使用A设计而不使用B设计,目的是什么?这才是我提问题的目的,其实,工作不到1年的时间,我发现,知识没有思维重要,这也就解释了公司里面有些人工作了5年还是老样子,有的人工作才1-2年就成为项目负责人(当然这还有其他的原因),知识学起来很快,可是思维就没有那么快形成!
先回答几个兄弟的问题:
Smalloc 兄弟的问题:中断的重要性,你说的非常对,中断让整个系统的设计变的复杂,但是中断本身并不复杂,其实操作系统中任何一部分都是重要的,没有最重要,也没有相对重要,只是说内存管理比价复杂,难以理解,中断本身不难理解,但是它的出现使得系统变的复杂,这正是我想表达的!
futex:这个兄弟说的非常的对,可是中断你觉得难理解吗?如果你学过计算机组成原理,相信你也写过中断处理程序吧?8259A
懂医术的厨师:这个兄弟说,内存管理是东凑西拼出来的,这句我不太理解,希望你能详细的解释一下!

下面公布一下我理解的答案:
其实“懂医术的厨师:”这个兄弟的答案和我的差不多:
我先把他的答案贴出来,然后再补充一下:
一:
1.内核启动先执行bios, bios则通过探测总线获取所有的内存区。
2,setup.s中会搬运这些探测结果到memory 0页
3.内核引导,读取这些内存区信息,e820。先验证,若通过直接用,否则猜测使用。继而形成PGlist, zone等区域

二:
boatload则依赖于不同硬件体系结构,一般会预先定义好内存BANK。并在一个文件中定义。形如lowmemory.S
内核启动时直接传入
关于第一个问题,我想说的,回答的非常好:就是在第三个小点漏了一点:e820形成之后到PGLIST和zone这块,其实还应该有过关于bootmem这样的一个过程,bootmem是初始化的时候为各个初始化模块提供内存管理的!
第二个问题:其实在嵌入式的bootloader中,我们是根据不同的板子信息,在板子的/include/configs下面的板子头文件中定义了内存的大小,物理地址的编址,而在x86的体系结构下,我们是通过“int 0x15,功能号为0xe820:的BIOS调用
其实这个为问题的本身,我觉得不是特别的难,看过linux内核情景分析的都知道,看过嵌入式的Uboot也清楚,可是我系统通过这个问题:让大家进一步思考:为什么嵌入式的Bootloarder和PC机下的bootloader就应该不一样了?
其实我的理解是:在嵌入式领域:Uboot和内核都是靠我们自己去移植的,因为,我们会自己去配置自己的硬件(比如:nandflash,nor flash,等等,地址都是我们自己去编的,大小,我们在移植也已经订好了,以后就不会改变了),比如不同的flash,不同的phy,等等,不同的应用会导致硬件差别特别的大,而且灵活性也很大!
而在PC机领域就不存在上面的问题:比如,有可能内存条我们会自己变换,如果我们变换一次就需要修改操作系统,那么对于操作系统的用户来讲,那是不可能的!

评分

参与人数 1可用积分 +6 收起 理由
Godbach + 6 感谢分享

查看全部评分

论坛徽章:
0
18 [报告]
发表于 2011-07-04 16:30 |显示全部楼层
回复 54# smalloc


我来回答一下smalloc兄弟的问题吧:
Vfree()这系统调用对应的是vmalloc,我们还知道系统调用中还有kmalloc和kfree,那么他们之间到底有什么联系?弄清楚smalloc兄弟提出的这个问题和vmalloc和kmalloc(这个问题,我当时面试一家大公司的时候,面试官曾经问过这个问题),最重要的是理解vmalloc和vfree在什么前提下提出来的,他们背后的原理是什么,弄懂原理性的东西,我觉得smalloc兄弟的问题就会迎刃而解了!
Vmalloc和vfree是在非连续存储区管理中提供出来的接口,那么为什么会有非连续存储区管理了?这到底是解决一个什么样的问题了?
在ULK这本书中有一段话如下:
把存储器映射到一组连续的页框是最好的选择,这样会充分利用高速缓存并达到较低的平均访问时间。不过,如果对存储区域的请求并不是很频繁,那么通过连续的线性地址来访问非连续的页框这样一种分配模式就会有很有意义。这种模式的主要缺点是避免了外部碎片,而缺点是必须打乱内核页表。显然非连续的存储区的大小必须是4096的倍数。Linux在几个方面使用非连续存储区。例如:为活动的交换区分配数据结构,为模块分配空间,或者给某些I/O驱动程序分配缓冲区。
好了,其实这段话并不长,但是蕴藏了很多问题和玄机在里面!
第一个疑问:把存储器映射到一组连续的页框是最好的选择,这样会充分利用高速缓存并达到较低的平均访问时间。这样为什么是最好的选择了? 为什么会充分利用高速缓存了?
很简单的一个道理:高速缓存也就是我们所说的cache,cache是基于局部性原来提出的:连续的页框,在局部的时间内被缓存在cache中,降低了访问页框的时间。如果这个时候,页框不是连续的,线性地址是连续的会局部时间内这些线性地址会被访问,但是他们对应的页框不是连续的,有的会在cache中,有的不在,那么势必会降低cache利用效率(其实说直白一点:就是连续的页框在cache中的访问时候的命中的机率要比非连续的要高)
第二个疑问:缺点是打乱了内核页表,为什么会打乱了内核页表?打乱了内核页表有什么坏处?
从这段话,我们可以知道在原来的连续的页框的情况下,内核是什么样的有序的,这种有序是一个什么样的有序了?我们知道线性地址和物理地址有个这样的关系线性地址-3G=物理地址(在896M一下会有这样的对应关系),所以在页表初始化的时候,前面896M对于内核页表来讲是直接映射过来的,在系统初始化的时候就建立好了映射关系,注意这个和用户进程的页表是不一样的!那么3G+896M后就会存在不一一映射的情况!这种有序根据局部性原理会大大提高cache的命中率,但是如果这种顺序被打乱了,势必导致cache的命中率会降低(在一段时间访问的物理地址不连续)!
第三个疑问:连续的页框这种模式的缺点是外部碎片?显然非连续存储区的大小是4096的倍数?
假设如果这个时候只有10个页框,这10个页框是非连续的(3个连续,其他的都不连续),10个页框的大小正好是10*4K=40K,这个时候我要通过kmalloc申请4个连续的页框,势必会失败,但是我的内存可用的空间大于4个页框,这也是为什么会提出vmalloc和vfree的问题了!
下面来说说在Linux中它是如何来实现的,下面也通过一些程序来验证我的想法:
ULK书上这么说的:
为非连续内存保留的线性地址空间的其实地址由VMALLOC_START宏定义,而末尾地址由VMALLOC_END宏定义,那么如果我通过vmalloc分配的地址范围一定会在VMALLOC_START和VMALLOC_END之间了,通过一个程序来验证:
  1. #ifndef __KERNEL__
  2. #define __KERNEL__
  3. #endif
  4. #ifndef __MODULE__
  5. #define __MODULE__
  6. #endif


  7. #include <linux/module.h>
  8. #include <linux/kernel.h>
  9. #include <linux/init.h>
  10. #include <linux/vmalloc.h>
  11. #include <linux/mm.h>
  12. #include <asm/pgtable.h>
  13. #include <asm/uaccess.h>

  14. int  __init test_init(void)
  15. {
  16.         char *vmalloc_mem;
  17.         size_t count=128;

  18.         printk("VMALLOC_START=:%x\n",VMALLOC_START);

  19.     vmalloc_mem=(char *)vmalloc(count);
  20.         printk("vamalloc_mem=:%x\n",vmalloc_mem);
  21.         printk("VMALLOC_END=:%x\n",VMALLOC_END);

  22.         return 0;
  23. }
  24. void __exit test_exit(void)
  25. {
  26.         printk("Bye test\n");
  27.         return;
  28. }
  29. module_init(test_init);
  30. module_exit(test_exit);
  31. MODULE_LICENSE("GPL");
复制代码
  1. /home # insmod vmalloc_test.ko
  2. VMALLOC_START=:c8000000
  3. vamalloc_mem=:c8060000
  4. VMALLOC_END=:f0000000
复制代码
发现我们新申请的区域果然在VMALLOC_START和VMALLOC_END之间

对于非连续区域的管理vm_struct数据结构来描述的,它的管理方式应该和vma的管理差不多,其实可以通过vmalloc函数和vfree函数的实现可以看的出来,对于vm_struct数据结构,在vmalloc中会通过kmalloc分配一个物理空间给vm_struct来描述新的连续的线性地址区域!
当通过vfree释放的时候会相应的调用kfree释放vm_struct的数据结构占用的空间

论坛徽章:
0
19 [报告]
发表于 2011-07-04 16:34 |显示全部楼层
希望大家都过来发表一下自己的意见和见解,把自己不清楚的地方贴出来,大家共同来讨论,我相信每个人在学内核的时候都会有很多问题不清楚,既然我们在论坛上,那么我们就是兄弟,就应该像一家人一样,大家互相帮组,把各自的不懂的问题贴出来,让更多的人帮助你,我也希望看到别人的问题的时候,兄弟们积极一点帮助别人,当我们遇到问题的时候别人也会积极的来帮助我们!希望大家积极起来!

论坛徽章:
0
20 [报告]
发表于 2011-07-04 16:48 |显示全部楼层
第三个问题:
进程管理相关的:
第一个小问:记得在学操作系统的时候,老师曾经提过进程上下文切换,说进程上下文切换比较耗时,在这点上线程要比进程有优势,那么进程的上下文是什么了?切换的时候都做了些什么?我相信这个对于看过内核代码的兄弟都比较容易,那好,我们知道在进程切换的时候:在古老的Linux中采用的方法和现代版本的Linux中采用的是不同办法?这两个办法有什么差别了?为什么新版本的内核采用现在的切换机制?其实,这个问题我想考察大家对Linux各种版本之间的关系,因为Linux内核不停的再优化,为什么会这么优化基于什么样的考虑?这个可以从内核不停的修改这方面可以看得出,这样也可以为我们去优化内核提供思路

第二个小问:在Linux中创建进程通过fork调用,按照fork调用的实现,它是写时复制机制,我们知道新创建的内核时复制的父进程的,那么父进程复制的是它的父进程的,那么系统中第一个进程是复制谁的了?它是怎么产生的了?第一个进程有什么作用了?
我们知道windows中是通过CreateProcess这样的系统调用来实现创建进程的,那么windows实现的进程模型和Linux是一样的吗?如果不一样他们各自有什么差别,或者说各自有什么优缺点?其实我们在设计linux内核的时候也应该参照其他操作系统的内核的设计思想,就比如windows NT的机构就基于CMU 的MACH操作系统,基于消息传递的机制!

第三个小问:
进程调度的算法,你对现有的进程调度算法了解吗?如果让你在现有的调度算法中,你能不能做到让一个进程永远的在CPU上运行,如果能,你怎么做?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP