毕业论文终稿(一个简易操作系统的实现)(8)

2019-03-16 19:19

华北电力大学本科毕业设计(论文)

}

io_store_eflags(eflg);

if (flg486 != 0) { }

i = memtest_sub(start, end);//这个函数使用汇编写的,返回能用的内存的最大地址 if (flg486 != 0) { }

return i;

cr0 = load_cr0();

cr0 &= ~CR0_CACHE_DISABLE; /* 允许缓存 */ store_cr0(cr0); cr0 = load_cr0();

cr0 |= CR0_CACHE_DISABLE; /* 禁止缓存 */ store_cr0(cr0);

4.3.1.2 用于内存管理的数据结构设计

在操作系统的课程上,主要介绍了两种内存管理的方式,一种是位示图法,即用1位来表示一个单位的内存是否正在使用。例如,128M的内存,共有0x08000000个字节,以0x1000(4KB)为单位进行管理,需要创建0x08000000/0x1000 = 32768个单位进行管理。还有一种是空闲分区链管理法,即记录下每一块空闲区域的起始地址和大小,每当有内存分配时,则遍历所有空闲区域的记录,找到一块合适的分配给它,然后再更新内存的空闲区域记录;释放时也一样,更新相应的空闲区域记录,但是有一点要注意,内存释放的空间上面和下面的空间也可能是空闲的,这样就要与上面和下面空闲的空间合并,在空闲区域记录中归纳成一条,要不然系统运行到后面就没有大块的内存可用,全部都被分割成小块的空闲区域。

MyOS中采用的是第二种管理方法,其原因为:首先占用内存少,而且大块内存分配和以下是用于内存管理的数据结构设计。

#define MEMMAN_FREES

4090 /* 最大个数32KB */

#define MEMMAN_ADDR 0x003c0000 /* 约定的存放内存管理信息(结构体信息)的首地址*/

struct FREEINFO { };

struct MEMMAN {

/* 内存管理器 */

32

释放时都特别迅速,如果用位示图法,需要对大量的内存进行读写。

/* 一块空闲区域 */

unsigned int addr, size;

华北电力大学本科毕业设计(论文)

int frees; /* 空闲内存区域的数量 */

int maxfrees; /* 最大的空闲内存区域大小 */ };

struct FREEINFO free[MEMMAN_FREES]; /* 所有的内存区域记录 */

4.3.1.3 内存分配

MyOS的内存分配使用的是最大内存分配法,即从多个内存空闲区域中找到最大的区域,以下是用于内存分配的函数。

unsigned int memman_alloc(struct MEMMAN *man, unsigned int size) /* 分配内存空间 */ { }

unsigned int i, a;

for (i = 0; i < man->frees; i++) { }

return 0; /* 无可用空间 */

if (man->free[i].size >= size) { }

/* 找到足够大的内存 */ a = man->free[i].addr; man->free[i].addr += size; man->free[i].size -= size; if (man->free[i].size == 0) { }

return a;

/* 如果free[0]变成了0,就减少一条可用信息 */ man->frees--;

for (; i < man->frees; i++) { }

man->free[i] = man->free[i + 1]; /* 后面整体后移 */

分配给申请者所申请内存大小之后更新这个空闲内存区域的大小。

4.3.1.4 内存释放

内存释放时要注意的是,每次释放一块内存,必须检查这块内存上面和下面是否同样以下适用于内存释放的函数。

int memman_free(struct MEMMAN *man, unsigned int addr, unsigned int size)

33

是空闲的内存,如果是,则需要合并,更新相应的内存区域信息。

华北电力大学本科毕业设计(论文)

/* 释放内存空间 */ {

int i, j;

/* 为了方便整理释放后的内存空间,将free[]按照地址顺序排列 */ for (i = 0; i < man->frees; i++) { }

/* free[i - 1].addr < addr < free[i].addr */ if (i > 0) { }

/* 不能够与前面的空间结合在一起 */ if (i < man->frees) {

/* 后面也有 */

if (addr + size == man->free[i].addr) {

/* 可以与后面的内容归纳在一起整理 */

34

if (man->free[i].addr > addr) { }

break;

}

if (man->free[i - 1].addr + man->free[i - 1].size == addr) { /* 当前释放的内存前面也有空闲的内存 */ man->free[i - 1].size += size; if (i < man->frees) { }

return 0;

/* 后面也有 */

if (addr + size == man->free[i].addr) { /* 也可以与后面的可用内存归纳在一起 */ }

man->free[i - 1].size += man->free[i].size; /* man->free[i]删除 */

/* free[i]变成0后归纳到前面去 */ man->frees--;

for (; i < man->frees; i++) { }

man->free[i] = man->free[i + 1]; /* 整体挪动一个位置 */

华北电力大学本科毕业设计(论文)

}

}

}

man->free[i].addr = addr; man->free[i].size += size; return 0;/* 成功 */

/* 前面后面都没有空余的空间,单独处理 */ if (man->frees < MEMMAN_FREES) { }

/* 不能往后移动 */ man->losts++;

man->lostsize += size; return -1; /* 失败 */

/* free[i]之后的整体完后挪动一个位置 */ for (j = man->frees; j > i; j--) { }

man->frees++;

if (man->maxfrees < man->frees) { }

man->free[i].addr = addr; man->free[i].size = size; return 0; /* 成功 */

man->maxfrees = man->frees; /* 更新最大值 */ man->free[j] = man->free[j - 1];

4.3.1.5 以4K为单位分配和释放内存

如果总是以1个字节为单位分配内存,会产生很多外部碎片,而内存控制器的空闲区域记录个数是有限的,所以为了防止空闲区域记录个数被耗尽,需要修改分配和释放函数,以4K为单位分配和释放内存。

以下是以4K为单位分配和释放内存的函数。

unsigned int memman_alloc_4k(struct MEMMAN *man, unsigned int size) /*以4K为单位分配内存*/ {

unsigned int a;

size = (size + 0xfff) & 0xfffff000; a = memman_alloc(man, size);

35

华北电力大学本科毕业设计(论文)

}

return a;

int memman_free_4k(struct MEMMAN *man, unsigned int addr, unsigned int size) /*以4K为单位释放内存*/ { }

int i;

size = (size + 0xfff) & 0xfffff000; i = memman_free(man, addr, size); return i;

4.3.1.6 其他与内存操作有关的函数

unsigned int memman_total(struct MEMMAN *man) /* 统计所剩内存的大小 */ { }

unsigned int i, t = 0;

for (i = 0; i < man->frees; i++) {

t += man->free[i].size;}

return t;

4.3.2 定时器设计

定时器对于操作系统有非凡的意义,简单点来说,定时器的工作原理就是:隔一段时间就发送一个中断信号给CPU。而如果有了定时器,CPU就不用亲自去计算时间。

定时器的操作者是和处理器集成在一起的8254芯片,可以通过CPU对8254芯片进行编程(通俗点说就是用户写指令,让CPU去执行,执行内容是对8254芯片的各种寄存器进行写入操作,执行结果8254芯片按我们想要的工作模式来工作)。 4.3.2.1 设置定时器芯片

8254芯片的官方定义是PIT(“Programmable Interval Timer”,可编程的间隔型定时器)。可以通过设置这个PIT,让定时器每隔多少秒就产生一次中断,而产生的中断怎样传输到CPU呢?PIT是和中断控制器(后面的“基本输入输出管理”中会详细介绍)的IRQ的0号相连接,所以,只要设定了PIT就可以设定IRQ0的中断时间,这样,CPU只需要关注IRQ0是否产生中断就可以了

通过对8254芯片的资料可以知道,控制其中断周期变更的命令是:OUT(0x34,AL),其中AL = 0x34;OUT(0x40,AL),其中 AL = 中断周期的低8位 ; OUT(0x40,AL),其中AL = 中断周期的高8位。

36


毕业论文终稿(一个简易操作系统的实现)(8).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:2018两会要点:防止因病致贫、因病返贫

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: