tyrone的专栏

开源组件与复用

用户操作
[即时聊天] [发私信] [加为好友]
赵磊ID:tyrone1979
129091次访问,排名653好友0人,关注者4
tyrone1979的文章
原创 93 篇
翻译 1 篇
转载 2 篇
评论 89 篇
tyrone的公告

支持开源与组件重用

It's time to reuse!

请使用贝宝付款,这是快捷、免费和安全的付款方式!
最近评论
super04:能否实现diff命令?
zhangpeng09876:好呀!
ztyls:可否发一份security-policy.xml,邮箱ZTYLS@126.com,谢谢
HT_Steven_Gerrard:确实,我同意楼上的想法
现在很少搞桌面操作系统开发,前一段时间redhat停止了它的桌面操作系统的开发,更让我觉得挑战微软在这个市场的权威的必要性,或许大家觉得这是很傻的想法,但没有不可能,不求一蹴而就,脚踏实地做好每一布。
而且现在在网络上有在做操作系统开发的,像博主这样的也有一些,但仅仅做了个简单模型就停手了,其实还可以进一步,一小步一小步的前进,慢慢的就会发觉这个小……
jxqdxm:关注中,希望你尽快进入C语言编写阶段,并且最终完成它。
文章分类
收藏
相册
Blog
King_play(RSS)
杜汪洋的专栏(RSS)
技术网站
IBM开发者(中文)(RSS)
IT之源
matrix-与Java共舞(RSS)
中国Java实验室
中国开发者网络(RSS)
微软开发者网络(RSS)
开源网站
Apache组织(RSS)
Eclipse开源IDE(RSS)
GNU开源鼻祖(RSS)
Java技术发源地
Linux组织
MySQL开源数据库
ObjectWeb
SourceForge开源项目平台
存档
软件项目交易
订阅我的博客
XML聚合  FeedSky
订阅到鲜果
订阅到Google
订阅到抓虾
订阅到BlogLines
订阅到Yahoo
订阅到GouGou
订阅到飞鸽
订阅到Rojo
订阅到newsgator
订阅到netvibes

原创 1个人开发操作系统之内存容量检测收藏

新一篇: Earned Value Management(挣值管理) | 旧一篇: JVM调优

内存管理的第一步是要知道内存的容量大小,也就是内存终了地址。检测内存容量的方法之一是从BIOS获取数据,但是使用BIOS的版本不同,获取的方式也大不相同。因此操作系统开发时采用另一种方法,就是检测内存地址是否有效。

 

首先,如果是486CPU,要先把缓存(Cache)屏蔽。为了提高CPU和内存之间数据交换的速度,CPU内的缓存会保留内存中刚被访问的数据。例如在CPU第一次访问0x18地址的数据54时,先会将54拷贝到缓存中,第二次访问0x18地址的数据时,就可以直接得到缓存中的54了。再例如for(i=0;i<100;i++)语句里的i的值被更新了100次,其实内存中的i值更新了1次,也就是第100次更新时,i才被写入内存,而前99i的值只是在缓存里更新。

386时代,CPU内没有缓存,486时代,有8-16KB的缓存,性能就提高了6倍以上。缓存虽然可以提高性能,但给内存容量的检测带来了不便,内存容量检测可以用一下的方式:先在一个地址中写入一个数值,然后再读取,如果读取的数值和写入的相等,则表示有个地址是内存中的有效地址。但是如果CPU里有缓存,这个方法就无效了,因此我们事先要把CPU的缓存屏蔽。

屏蔽CPU缓存的程序如下:

#define EFLAGS_AC_BIT      0x00040000

#define CR0_CACHE_DISABLE 0x60000000

 

unsigned int memtest(unsigned int start,unsigned int end)

{

              char flg486=0;

              unsigned int eflg,cr0,i;

             

              /*386 or 486*/

              eflg=io_load_eflags();

              eflg |=   EFLAGS_AC_BIT; /*AC-bit=1,区分386486*/

              io_store_eflags(eflg);

             

              eflg=io_load_eflags();

              if((eflg & EFLAGS_AC_BIT)!=0){

                            flg486=1;

              }

              eflg&=~EFLAGS_AC_BIT; /*AC-bit=0*/

              io_store_eflags(eflg);

             

              if(flg486!=0){

                            cr0=load_cr0();/*486,需要屏蔽缓存*/

                            cr0!=CR0_CACHE_DISABLE; /*ban cache*/

                            store_cr0(cr0);

              }

             

              i=memtest_sub(start,end);

             

              if(flg486!=0){

                            cr0=load_cr0();

                            cr0&=~CR0_CACHE_DISABLE; /*cache permit*/

                            store_cr0(cr0);

              }

             

              return i;

             

}

其中

_load_cr0: ;int load_cr0(void)

                mov eax,cr0

                ret

 

_store_cr0:           ;void store_cr0(int cr0);

                            mov eax,[esp+4]

                            mov cr0,eax

                            ret

函数unsigned int memtest_sub(unsigned int start,unsigned int end)完成内存容量的检测。startend是要检测的初始地址和结束地址。循环检测该范围内的每个地址是否有效。检测的方式是:

1.把地址的值保存;

2.向该地址写入一个值;

3.取该地址值得异或(XOR);

4.如果取得的异或值与正确的不一致,则表示该地址无效,结束测试,返回循环次数;

如果一致,则去5

5.再次取该值得异或,结果如果和原值不等,则去4

如果值相等,则表示该地址有效,去6

6.恢复该地址的值,继续检测下一个地址,去1

注意,以上的测试方法如果用C语言实现,编译时,不能使用优化参数。因为GCC编译器会认为12345步都是冗余操作,自作主张的把它删掉。最后会变成只循环,不做任何处理。为了避免GCC的优化处理,本文使用汇编来实现。每次检测0x10004KB)个地址。

_memtest_sub: ;unsigned int memtest_sub(unsigned int start,unsigned int end)

                            push edi              ;

                            push esi

                            push ebx

                            mov  esi,0xaa55aa55     ;pat0=0xaa55aa55;

                            mov  edi,0x55aa55aa      ;pat1=0x55aa55aa;

                            mov  eax,[esp+12+4]     ;i=start;

mts_loop:

                            mov       ebx,eax

                            add        ebx,0xffc        ;p=i+0xffc,检测末尾4Bytes的地址。

                            mov  edx,[ebx]  ;old=*p;

                            mov  [ebx],esi  ;*p=pat0;

                            xor         dword [ebx],0xffffffff ;*p^=0xffffffff; 异或

                            cmp        edi,[ebx]            ;if(*p!=pat1) goto fin; 不等则是无效

                            jne         mts_fin

                            xor         dword [ebx],0xffffffff; *p^=0xffffffff; 异或

                            cmp  esi,[ebx]     ;if(*p!=pat0) goto fin; 不等则是无效

                            jne         mts_fin

                            mov  [ebx],edx  ;*p=old; 有效,继续下4KB地址的检测

                            add        eax,0x1000        ;i+=0x1000;

                            cmp        eax,[esp+12+8]

                            jbe         mts_loop

                            pop ebx

                            pop esi

                            pop edi

                            ret

mts_fin:

                mov    [ebx],edx             ;*p=old;

                pop     ebx

                pop     esi

                pop edi

                ret

检测结果显示:

bootpack.c中加入如下语句:

              i=memtest(0x00400000,0xbfffffff)/(1024*1024); /*检测范围为3GB,结果以兆为单位*/

              sprintf(s,"memory %dmb",i);

              drawstring(binfo->vram, binfo->scrnx,10, binfo->scrny-50, COL8_FFFFFF, s);             

如图:

为什么只有32MB

因为虚拟机QEMU设定了内存的大小

qemu.exe -L . -m 32 -localtime -std-vga -fda boot.bin

32改为64后,运行结果则为:

 

发表于 @ 2006年09月25日 08:24:00|评论(loading...)|编辑

新一篇: Earned Value Management(挣值管理) | 旧一篇: JVM调优

评论:没有评论。

发表评论  


当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
Csdn Blog version 3.1a
Copyright © tyrone