|
<
第九天 内乱存办理
1.收拾整顿源文件
那一节只是停止了代码收拾整顿,把鼠标键盘相关的内乱容转移到了特定的文件里。
2.内乱存容量检查(1)
要做内乱存办理,起首得明白内乱存的容量,怎样明白内乱存的容量呢?BIOS能够报告我们谜底。但利用BIOS略微有面贫穷,因而,做者决议本人写法式检查内乱存容量。
内乱存检查法式次要有以下几步:
- 检查CPU是386芯片仍是486芯片。若为486芯片,则抑制cache。(386出有cache)
- 不竭背内乱存写进然后读与数据。假设写进战读与的内乱容一样,则内乱存毗连一般。
怎样断定CPU是386仍是486呢?那里需求用到形态存放器。形态存放器的第18位AC位(Alignment Check,对齐检查),正在386中即便将它设置为1,它也会酿成0,而486中没有会呈现这类状况。因而,按照那个特性,我们就能够断定出CPU是386仍是486的,然后再肯定需没有需求抑制缓存。相关的代码以下所示。
- unsigned int memtest(unsigned int start, unsigned int end)
- {
- char flg486 = 0;
- unsigned int eflg, cr0, i;
-
- /* 确认CPU是386仍是486以上 */
- eflg = io_load_eflags();
- eflg |= EFLAGS_AC_BIT; /* 对AC地位1 */
- io_store_eflags(eflg);
- eflg = io_load_eflags();
- if ((eflg & EFLAGS_AC_BIT) != 0) /* 假如是386,即便设定AC=1,AC的值借会主动回到0 */
- {
- flg486 = 1;
- }
- eflg &= ~EFLAGS_AC_BIT; /* 将AC地位0 */
- io_store_eflags(eflg);
-
- if (flg486 != 0)
- {
- cr0 = load_cr0();
- cr0 |= CR0_CACHE_DISABLE; /* 制止缓存 */
- store_cr0(cr0);
- }
-
- i = memtest_sub(start, end);
-
- if (flg486 != 0)
- {
- cr0 = load_cr0();
- cr0 &= ~CR0_CACHE_DISABLE; /* 许可缓存 */
- store_cr0(cr0);
- }
-
- return i;
- }
复造代码 其中,减载战保存掌握存放器0(CR0)的函数定义以下。
- _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)
- {
- unsigned int i, *p, old, pat0 = 0xaa55aa55, pat1 = 0x55aa55aa;
- for (i = start; i <= end; i += 4)
- {
- p = (unsigned int *) i;
- old = *p; /* 先记着修正前的值 */
- *p = pat0; /* 试写 */
- *p ^= 0xffffffff; /* 反转 */
- if (*p != pat1) /* 查抄反转成果 */
- {
- not_memory:
- *p = old;
- break;
- }
- *p ^= 0xffffffff; /* 再次反转 */
- if (*p != pat0) /* 查抄值能否规复 */
- {
- goto not_memory;
- }
- *p = old; /* 规复为修正前的值 */
- }
- return i;
- }
复造代码 运转的显现以下。
那里显现内乱存有3G内乱存,而体系内乱存实践只要32M,那较着不合错误,是甚么处所堕落了?
3.内乱存内乱容检查(2)
上一节为何会堕落呢?那齐皆是编译器的锅。
正在从C言语转换成汇编的过程当中,编译器发明内乱存检查过程当中出有甚么实践的改动,便把那段给劣化失落了。好比,起首给一个地点存进0xaa55aa55,翻转后酿成0x55aa55aa,然后再次反改变成0xaa55aa55,从结果而行并出有发作甚么变革。
为了避免代码被劣化,接纳汇编代码编写内乱存检查的函数。
- unsigned int memtest_sub(unsigned int start, unsigned int end)
- {
- unsigned int i, *p, old, pat0 = 0xaa55aa55, pat1 = 0x55aa55aa;
- for (i = start; i <= end; i += 0x1000)
- {
- p = (unsigned int *) (i + 0xffc);
- old = *p; /* 先记着修正前的值 */
- *p = pat0; /* 试写 */
- *p ^= 0xffffffff; /* 反转 */
- if (*p != pat1) /* 查抄反转成果 */
- {
- not_memory:
- *p = old;
- break;
- }
- *p ^= 0xffffffff; /* 再次反转 */
- if (*p != pat0) /* 查抄值能否规复 */
- {
- goto not_memory;
- }
- *p = old; /* 规复为修正前的值 */
- }
- return i;
- }
复造代码 memman_init初初化MEMMAN构造体成员,memman_total计较出盈余内乱存总巨细,那些皆比力简朴。
- i = memtest(0x00400000, 0xbfffffff) / (1024 * 1024); /* 0x400000从前的内乱存已被利用,无需查抄 */
- sprintf(s, "memory %dMB", i);
- putfonts8_asc(binfo->vram, binfo->scrnx, 0, 32, COL8_FFFFFF, s);
-
- while (1)
复造代码 从名字就能够看出memman_alloc是内乱存分派函数,接纳的是初次适应算法,也算简朴。
- _memtest_sub: ; unsigned int memtest_sub(unsigned int start, unsigned int end)
- PUSH EDI ; (保留EBX、ESI、EDI中的数据)
- PUSH ESI
- PUSH EBX
- MOV ESI, 0xaa55aa55 ; pat0 = 0xaa55aa55;
- MOV EDI, 0x55aa55aa ; pat1 = 0x55aa55aa;
- MOV EAX, [ESP + 12 + 4] ; i = start; (因为栈中增长了3个元素,地点要多减12)
-
- mts_loop:
- MOV EBX, EAX
- ADD EBX, 0xffc ; p = (i + 0xffc);
- 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;
- ADD EAX, 0x1000 ; i += 0x1000;
- CMP EAX, [ESP + 12 + 8] ; if (i <= end) goto mts_loop;
- JBE mts_loop
- POP EBX
- POP ESI
- POP EDI
- RET
-
- mts_fin:
- MOV [EBX], EDX ; *p = old;
- POP EBX
- POP ESI
- POP EDI
- RET
复造代码 内乱存开释的算法逻辑能够看看上里的图,了解起去该当没有会太艰难。
最初借需修正一下HariMain,那里没有做展现了,间接上结果图。
书上的内乱容到此结束。正在此,给各人一面小倡议,能够尝试本人完成一个内乱存办理算法,当利用的内乱存块很少时,书中的内乱存办理算法没有算缓,可是一旦多起去(抵达一两千的量级),所需工夫飙降(究竟结果工夫庞大度为O(n2))。尝尝接纳单背链表或其他的数据构造,把工夫庞大度加至O(n)的程度。
实在曾经不准备写闭于《30天便宜操纵体系》的专客了,由于那本书的代码没有是很体系,可是有人问我另有后绝吗,并且我以为内乱存办理比力有效,便写了那一篇专客,前面另有使命切换、非常处置等内乱容也风趣,但我该当没有会再写了。如今正正在看《一个64位操纵体系的设想取完成》,我也很保举看那本书,代码借鉴于Linux,对当前看Linux源码或其他操纵体系的源码也有协助。
免责声明:假如进犯了您的权益,请联络站少,我们会实时删除侵权内乱容,感谢协作! |
1、本网站属于个人的非赢利性网站,转载的文章遵循原作者的版权声明,如果原文没有版权声明,按照目前互联网开放的原则,我们将在不通知作者的情况下,转载文章;如果原文明确注明“禁止转载”,我们一定不会转载。如果我们转载的文章不符合作者的版权声明或者作者不想让我们转载您的文章的话,请您发送邮箱:Cdnjson@163.com提供相关证明,我们将积极配合您!
2、本网站转载文章仅为传播更多信息之目的,凡在本网站出现的信息,均仅供参考。本网站将尽力确保所提供信息的准确性及可靠性,但不保证信息的正确性和完整性,且不对因信息的不正确或遗漏导致的任何损失或损害承担责任。
3、任何透过本网站网页而链接及得到的资讯、产品及服务,本网站概不负责,亦不负任何法律责任。
4、本网站所刊发、转载的文章,其版权均归原作者所有,如其他媒体、网站或个人从本网下载使用,请在转载有关文章时务必尊重该文章的著作权,保留本网注明的“稿件来源”,并自负版权等法律责任。
|