免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 4288 | 回复: 18
打印 上一主题 下一主题

[PATCH] 2.6.27: 内核中的内存保护 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-11-02 22:31 |只看该作者 |倒序浏览
首先我在linux内核上还是个新手,还请大家多帮助。
在linux内核中,用户进程之间和用户与内核之间存在内存保护,内核之内各模块(通常意义上的模块,不特指可装载模块)间是没有保护的,这是因为内核对于简洁和效率的要求所决定的。但随着linux在各种嵌入式系统上的广泛应用,传统的嵌入式系统中各任务运行在内核态,并共享内存空间,linux使用内核线程来移植会比较容易,这样内核会有大量的任务运行,产生内存问题的可能性会越
来越高。在vxworks 6.0以后,就提供了进程间内存保护的特性。在linux上为了解决这个问题,我想了一种内核的内存保护方案,作为调试选项来实现。

基本来说,就是为内存分配模块ID,只有本模块的代码可以访问本模块内存,避免其他模块的意外访问。为实现这个目标,最简单的想法是进入模块时,将它的内存的页表设置present标志,离开模块前再清除present标志,但在SMP下,页表是被各CPU共享的,虽然也可以使用多内核页表,各CPU使用自己的内核页表,但修改比较复杂,并且不利于移植到其它没有硬件页表的架构上。我的办法是页表中始终清除present标志,各CPU通过自己的TLB来访问内存。在分配内存时保存一个地址-模块表,记录该页所属的模块ID,将页表项清除present标志,在缺页异常中查找地址-模块表,如果属于当前模块ID,暂时设置present标志,然后装入TLB,然后马上再清除present标志,但这次不刷新TLB,让这个页表项保留在TLB中,虽然会有个窗口时间,但这也是难以避免的。

因为内存保护只是部分模块需要,很多内存是必须要被共享访问的,所以必须可以同时使用不保护方式,这样就要为分配私有内存单独提供一套接口,这个接口应该尽可能的简单,并且在调试选项关
闭时变为原来的接口。可以有两种方法,一种是为每个alloc_pages、kmalloc这样的接口提供另一套alloc_pages_p、kmalloc_p,在调试选项关闭时定义宏为alloc_pages、kmalloc,这个方法需要增加很多函数接口,另一种是我现在使用的,使用原来的函数接口,增加一些标志位,在调试选项关闭时将标志位定义为0。这其中kmap_high和vmalloc的输入参数中没有flag,可以使用page的最低位和size的最高位来传递,正常情况下它们是不会被使用的。

我现在只是修改了最基本的__alloc_pages_internal、__free_pages两个接口,以分配页为基础,可以很容易的修改slab和vmalloc,中断处理我只修改了smp_apic_timer_interrupt和do_IRQ,其它中断大概也没太大需要修改。这个patch是基于2.6.27版本的,没考虑PAE和64位,仅仅是个概念性的东西。

刚才我在linux内核列表上贴了这个PATCH,真奇怪那里PATCH不能贴为附件。以前在论坛上发过一部分,这次算是比较全的。

[ 本帖最后由 bjhpf 于 2008-11-2 22:35 编辑 ]

km_protect.rar

3.27 KB, 下载次数: 52

论坛徽章:
0
2 [报告]
发表于 2008-11-03 11:23 |只看该作者
不知楼主有没有测试过,行吗?

论坛徽章:
0
3 [报告]
发表于 2008-11-03 12:29 |只看该作者

回复 #2 qtdszws 的帖子

在km_protect.c中有测试代码,用/proc/km_protect访问,我用QEMU测试的,我的电脑还不是多核的,要更新了。

论坛徽章:
0
4 [报告]
发表于 2008-11-03 14:18 |只看该作者

回复 #1 bjhpf 的帖子

我想请问一下lz, 是在公司的项目作的还是在自己家的电脑上做的。

如果在自己家作的话,那么怎么进行内核调试的, 环境是怎么个搭法阿?

论坛徽章:
0
5 [报告]
发表于 2008-11-03 14:19 |只看该作者
原帖由 bjhpf 于 2008-11-2 22:31 发表
首先我在linux内核上还是个新手,还请大家多帮助。
在linux内核中,用户进程之间和用户与内核之间存在内存保护,内核之内各模块(通常意义上的模块,不特指可装载模块)间是没有保护的,这是因为内核对于简洁和 ...

首先赞一下LZ大胆探索的精神,但你的方法是不可取的,先不说性能问题。我假设一种情况你看如何解决:
首先内核线程A在CPU1上运行,按照你的方法插入了一个TLB项,但没有刷新TLB,页表对应的entry的p位被清掉。这时线程A被迁移到CPU2上,此时CPU1中关于线程A的TLB项会在一段较长时间内有效,因为你修改页表的时候不会刷新TLB,这导致后来运行在CPU1的线程也可以访问到线程A的地址。这个窗口时间比你提到的那个大的多。修改内核页表不刷新TLB的做法肯定是不会被接受的,这只能导致混乱。
即使一切情况都ok,这种方法导致大量的page fault所带来的性能影响肯定是不能接受的,所以LZ应该尝试其它方法。
比较好的解决方案一个是你提到的page table per CPU。此外通过虚拟化的方法是一个很好的途径。抛开硬件的虚拟化支持不说,LZ可以研究一下linux中的lguest和contianer机制,或许可以找到你要的东西(不好意思,这两个东西我都没研究过,你只有自己看了,不能提供更多的意见)。

论坛徽章:
0
6 [报告]
发表于 2008-11-03 14:31 |只看该作者
原帖由 zx_wing 于 2008-11-3 14:19 发表

首先赞一下LZ大胆探索的精神,但你的方法是不可取的,先不说性能问题。我假设一种情况你看如何解决:
首先内核线程A在CPU1上运行,按照你的方法插入了一个TLB项,但没有刷新TLB,页表对应的entry的p位被清掉 ...

哦,我忘了内核线程是per CPU的,不存在迁移问题。
那第一个问题不存在。
你前面那个窗口时间和性能是关键。并且模块本身就是提供公共的内核接口,你如何让模块为每个线程提供的接口都不一样(如果模块内部涉及到内存分配,则当线程调用模块提东的接口时,模块内部都要为该线程单独分配只供它访问的内存,岂不是所有接口都要接收线程的ID作为参数)

[ 本帖最后由 zx_wing 于 2008-11-3 14:37 编辑 ]

论坛徽章:
0
7 [报告]
发表于 2008-11-03 15:22 |只看该作者
发到zh-kernel上让大家review一下吧,题目加个RFC

论坛徽章:
0
8 [报告]
发表于 2008-11-03 16:01 |只看该作者

回复 #1 bjhpf 的帖子

vxWorks6.0之后是加上了rtp(real time process)来进行内存保护,rtp类似于linux下面的用户进程,是通过系统调用来访问kernel例程的。
而vxWorks的kernel task依然是没有进行内存保护的,各个内核进程之间依然可以互相访问。
不知道搂主是在哪里看到的资料?

论坛徽章:
0
9 [报告]
发表于 2008-11-06 23:12 |只看该作者
原帖由 onlyflyer 于 2008-11-3 16:01 发表
vxWorks6.0之后是加上了rtp(real time process)来进行内存保护,rtp类似于linux下面的用户进程,是通过系统调用来访问kernel例程的。
而vxWorks的kernel task依然是没有进行内存保护的,各个内核进程之间依然 ...

vxworks的rtp细节我也不清楚,但我估计不是用户进程,那样也太没技术含量了,嵌入式使用用户进程几乎是不可能的,因为嵌入式进程一般都要直接访问硬件,用户态每次访问硬件都系统调用可太慢了。而且我看到rtp的一个介绍,就是地址空间不重叠,好处是进程切换时不用刷新TLB,我现在估计它可能用的是多页表吧,每个rtp进程有自己的页表,分配内存时通过系统调用,知道那些地址空间是空闲的,可以不重叠的分配。内存保护只与页表相关,可以是intel的硬件页表,也可以是mips的软页表,与用户态和内核态无关。

论坛徽章:
0
10 [报告]
发表于 2008-11-06 23:13 |只看该作者
原帖由 zhzhl555 于 2008-11-3 14:18 发表
我想请问一下lz, 是在公司的项目作的还是在自己家的电脑上做的。

如果在自己家作的话,那么怎么进行内核调试的, 环境是怎么个搭法阿?

自家电脑,就是用QEMU测试的,调试很方便,但现在遇到问题是多核调试有问题。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP