关注分享主机优惠活动
国内外VPS云服务器

在 30 天内创建您自己的操作系统第 9 天(在 30 天内编写您自己的操作系统)

总结:检查内存容量 要管理内存,首先需要了解内存容量。 我怎样才能知道内存大小?请告诉我答案。 不过使用起来有点麻烦,所以作者决定自己写一个程序来检查内存容量。 状态寄存器位、对齐检查即使设置为 时也是如此,但设置为 时则不会发生。

第 9 天内存管理 1. 组织源文件

在本节中,您将仅组织代码并将鼠标和键盘相关内容传输到特定文件。

2、检查内存容量(一)

要管理内存,首先需要了解内存容量。 我如何知道我有多少内存?BIOS 会告诉你答案。 不过,由于使用BIOS有点麻烦,所以我决定编写一个程序来检查内存容量。

内存检查程序主要有以下步骤:

检查CPU是386芯片还是486芯片。 对于 486 芯片,缓存被禁用。 (386没有缓存)

不断向内存写入和读取数据。 如果写入的内容与读取的内容相同,则内存连接正常。

如何确定我的 CPU 是 386 还是 486?这就是状态寄存器的作用。 即使在 386 上设置为 1,状态寄存器的 AC18 位(对齐检查)也会变为 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(); |= EFLAGS_AC_BIT; /* 对于 AC 位置 1 */ io_store_eflags(eflg); eflg = io_load_eflags(); if ((eflg & EFLAGS_AC_BIT) != 0) /* 对于 386,设置 AC=1 值不会返回 0 * /{flg486 = 1;} EFLG & = ~ EFLAGS_AC_BIT; / *AC位置0 */iO_STORE_EFLAGS (EFLG); if (FLG486 != 0) {cr0 =load_cr0(); /* 无效缓存*/ store_cr0(cr0); ' ' s ' s ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' -- 彻底清理 --- 一起清理清理,直到她 CR0_CACHE_DISABLE 请。 /* 启用缓存* /Store_cr0 (CR0);} Return I;}

其中,控制寄存器0(CR0)的加载和保存函数定义如下。 _load_cr0: ; intload_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 scrnx, 0, 32, COL8_FFFFFF, s ); while (1)

执行时显示如下。

说是有3G内存,但系统内存实际上只有32M。 这显然是错误的。 出了什么问题?

3. 检查内存内容(2)

为什么上一节出错了?

在C语言到汇编的翻译过程中,编译器检测到内存检查过程没有真正的变化,因此对这一部分进行了优化。 例如,首先将0xaa55aa55存储在一个地址中,将其翻转为0x55aa55aa,然后将其翻转回0xaa55aa55。 结果没有变化。

为了防止代码优化,使用汇编代码来编写内存检查函数。

_memtest_sub: ; unsigned int memtest_sub(unsigned int start, unsigned int end) PUSH EDI ; (保存数据到 EBX, ESI, EDI) PUSH ESI PUSH EBX MOV ESI, 0xaa55aa55 ; Pat 0 = 0xaa55aa55;帕特 1 = 0x55aa55aa; MOV EAX, [ESP + 12 + 4] ; i = start;(栈中添加了3个元素,所以地址必须增加12) mts_loop: MOV EBX, EAX ADD EBX, 0xffc; 0xffc) ; MOV EDX, [EBX]; MOV [EBX], ESI ; *p = pat1) JNE mts_fin XOR DWORD [EBX], * p ^= 0xffffffff; CMP ESI,[EBX] EBX],*p = 旧; i += 0x1000; CMP EAX, [ESP + 12 + 8] ; if (i frees = 0; /* 用于观察可用状态:frees 的最大值 */ man->lostsize = 0; /* 总大小未能释放的内存 */ man[k4 ]>losts = 0 /* 释放失败。失败次数*/ } unsigned int memman_total(struct MEMMAN *man) /* 报告总剩余内存大小*/ { unsigned int i, t = 0; for (i = 0; i frees ; i++ ) { t += man->free[i].size; }

memman_init 初始化 MEMMAN 结构的成员,memman_total 计算总剩余内存大小。 这些都比较简单。

unsigned int memman_alloc(struct MEMMAN *man, unsigned int size) /* 分配*/ { unsigned int i, a; for (i = 0; i frees; i++) { if (man ->free[i].size >= size) /* 找到足够的内存*/ { a = man- ]>free[i].addr; man->free [i].addr + = size; 只删除一个可用的信息*/e[i] = man->free[i + 1]; /*向前移动下一条信息*/}} 返回 0. /* 无可用空间 */ }

顾名思义,memman_alloc 是一个内存分配函数,使用了相对简单的第一自适应算法。

int memman_free(struct MEMMAN *man, unsigned int addr, unsigned int size) /* Release*/ { int i, j; /* 为了方便内存归纳,free[]按照addr的顺序放置*/ /* 那么仙居鼎该放在哪里呢? */ for (i = 0; i frees; i++) { if (man->free[i].addr > addr) { Break; free[i - 1].addr < addr 0) /* 如果之前有可用内存 */ { if (man->free[ i [ k4 ] 1].addr + man->free[i - 1].size == addr) /* 如果与之前可用的内存相邻,则会被分组 */ [i - 1 ].size +=如果(i frees) /* 如果后面有内存可用*/,就汇总到一起*/ for (; i frees; i++) /* free [i i ] */ Back ; == man->free[i].addr) /* 如果它们与可用内存相邻,则将它们组合在一起 */ >free[i].size += size; 返回 0。 /*成就已完成*/}}/*无法通过之前的记忆进行总结或通过之前的记忆进行总结*/if (man -> frees frees ); --) /* 恢复信息到 free[i] */ 1]; ].addr = addr; man->free[i].size = 大小; /* 成功完成*/ } /* 消息数量达到上限*/ man->losts++; man[ k4]>lostsize += size; /* 失败*/ return -1; > 看上图就可以了解内存释放的算法逻辑。 应该不会太难理解。

最后,HariMain 还需要修改。 我不会在这里展示它,只是结果的照片。

本书到此结束。 我想在这里提出一个小小的建议。 您也可以尝试自己实现内存管理算法。 本书中描述的内存管理算法在使用较少的内存块时并不慢,但随着内存块数量的增加(1-2000的数量级)所需的时间迅速增加(最终时间复杂度为0) 。 (n2))。 请尝试使用它双向链表或其他数据结构将时间复杂度降低到 O(n) 级别。

实际上,我不会写关于“30天内创建你自己的操作系统”的博客,因为这本书中的代码不是很系统,但是有人告诉我类似我问他们是否有这样的事情任何事物。 我觉得内存管理比较方便。 ,我写了这个博客。 接下来还有一些有趣的事情,例如任务切换和异常处理,但我可能不会再写它们了。 您当前正在阅读《64 位操作系统的设计与实现》。 我也推荐阅读这本书。 该代码是从Linux借用的,以后阅读Linux源码或者其他操作系统源码时会有用。

未经允许不得转载:主机频道 » 在 30 天内创建您自己的操作系统第 9 天(在 30 天内编写您自己的操作系统)

评论 抢沙发

评论前必须登录!