《30天自制操作系统》学习笔记(九)

一、内存容量检查
1.如何进行内存检查?
往内存中随便写入一个值,然后马上读取,来检查读取的值与写入的值是否相等
2.为了实现直接写入内存的功能,需要先暂时关闭CPU中的告诉缓存
代码如下:
#define EFLAGS_AC_BIT        0x00040000    
#define CR0_CACHE_DISABLE    0x60000000

unsigned int memtest(unsigned int start, unsigned int end)    //设置内存检查的起始位置
{
    char flg486 = 0;    //486标志位,只有486以后的cpu才有告诉缓存
    unsigned int eflg, cr0, i;

    /* 386か、486以降なのかの確認 */
    eflg = io_load_eflags();    //读取eflags寄存器
    eflg |= EFLAGS_AC_BIT; /* AC-bit = 1 ,将AC位置1*/
    io_store_eflags(eflg);    //重新载入eflags寄存器的值到cpu中
    eflg = io_load_eflags();    //读取eflags的值
    if ((eflg & EFLAGS_AC_BIT) != 0) { /* 如果是386,即使设定AC=1,cpu还是会将AC的值自动回到0 */
        flg486 = 1;    //如果AC位没有回到0,说明是486及以上的cpu
    }
    eflg &= ~EFLAGS_AC_BIT; /* AC-bit = 0,将AC位置0 */
    io_store_eflags(eflg);    //重新载入eflags的值到cpu中

    if (flg486 != 0) {
        cr0 = load_cr0();    //汇编语言编写的函数,读取cr0的值到eax中
        cr0 |= CR0_CACHE_DISABLE; /* 禁止缓存 */
        store_cr0(cr0);    //汇编语言编写的函数,将eax的值存入到cr0中
    }

    i = memtest_sub(start, end);    //内存检查

    if (flg486 != 0) {    //检查完成后开启CPU的高速缓存功能
        cr0 = load_cr0();
        cr0 &= ~CR0_CACHE_DISABLE; /* 开启缓存 */
        store_cr0(cr0);
    }

    return i;
}

//功能:内存检查主函数,将一个数值写入到内存并读取,判断两者是否相等
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) {    //每次增加4kb,相当于一次检查4kb
        p = (unsigned int *) (i + 0xffc);    //只检查末尾4个字节(为什么?)
        old = *p;            /* 先记住修改前的值 */
        *p = pat0;            /* 将一个数值写入内存 */
        *p ^= 0xffffffff;    /* 将数值的结果反转,1变成0,0变成1*/
        if (*p != pat1) {    /* 检查反转结果*/
not_memory:
            *p = old;    //如果不正确,恢复变量
            break;    //跳出循环
        }
        *p ^= 0xffffffff;    /*如果相等就再次反转*/
        if (*p != pat0) {    /*判断和最初写出的值是否相等*/
            goto not_memory;    //不正确后的操作
        }
        *p = old;            /*如果正确,恢复变量*/
    }
    return i;    //如果内存检查过关,返回值应该是最后的地址值
                    //如果检查过程出现错误,返回值是对应的内存地址
}

二、挑战内存管理
1.什么是内存管理?--内存分配、内存释放
要实现上述功能,首先需要准确记录当前内存的状态,书中使用了两个结构体变量
struct FREEINFO {    /* 记录内存信息 */
    unsigned int addr, size;    //从addr开始的地址算起,有多少位是可用的
};

struct MEMMAN {        /* 实现内存管理 */
    int frees, maxfrees, lostsize, losts;    //frees表示可用的内存信息个数
    struct FREEINFO free[MEMMAN_FREES];
};
2.这两个结构体变量如何实现内存管理?
首先由FREEINFO记录可用的内存信息,然后MEMMAN中会记录所用这些可用内存信息
当需要空间时,只要查看MEMMAN中的free的状况,从中找出对应的大小即可,同时进行相应的标注
当空间释放时,增加一条可用信息(需判断能不能与相邻的可用空间连到一起,如果可以就归为一条)
代码如下:
void memman_init(struct MEMMAN *man)
{
    man->frees = 0;            /* 可用信息的数目 */
    man->maxfrees = 0;        /* 用于观察可用状况,frees的最大值*/
    man->lostsize = 0;        /*释放失败的内存的大小总和*/
    man->losts = 0;            /*释放失败次数*/
    return;
}

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;
}

unsigned int memman_alloc(struct MEMMAN *man, unsigned int size)
/* 分配内存 */
{
    unsigned int i, a;
    for (i = 0; i < man->frees; i++) {
        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) {    //如果分配后大小为0了,则删除此项条目
                man->frees--; //条目数减1
                for (; i < man->frees; i++) {
                    man->free[i] = man->free[i + 1]; /* 将之后的记录依次前移 */
                }
            }
            return a;    //返回分配的首地址
        }
    }
    return 0; /* 没有可用空间 */
}

int memman_free(struct MEMMAN *man, unsigned int addr, unsigned int size)
/* 释放内存 */
{
    int i, j;
    //决定收回的内存应该放在那里,按照地址的大小依次排列
    for (i = 0; i < man->frees; i++) {
        if (man->free[i].addr > addr) {
            break;
        }
    }
    /* free[i - 1].addr < addr < free[i].addr */
    if (i > 0) {
        /* 表示前面有可用内存 */
        if (man->free[i - 1].addr + man->free[i - 1].size == addr) {
            /*如果前一个条目的地址和大小符合条件,能够合并 */
            man->free[i - 1].size += size;    //只用对前一个条目的大小进行扩大即可
            if (i < man->frees) {
                /*后面也有可用的内存*/
                if (addr + size == man->free[i].addr) {
                    /* 如果当前的地址加大小符合条件,能够合并 */
                    man->free[i - 1].size += man->free[i].size;    //直接与后一条目合并
                    /* 将man->free[i]条目删除 */
                    /* free[i]がなくなったので前へつめる */
                    man->frees--;
                    for (; i < man->frees; i++) {
                        man->free[i] = man->free[i + 1]; /* 结构体复制 */
                    }
                }
            }
            return 0; /* 成功释放内存 */
        }
    }
    /* 不能与前面的可用空间归纳到一起的情况 */
    if (i < man->frees) {
        /* 后面还有条目 */
        if (addr + size == man->free[i].addr) {
            /* 可以与后面的内容归到一起 */
            man->free[i].addr = addr;
            man->free[i].size += size;
            return 0; /* 成功释放 */
        }
    }
    /* 既不能与前面归纳到一起,也不能与后面归纳到一起 */
    if (man->frees < MEMMAN_FREES) {
        /* 讲free[i]之后的记录向后挪动1位 */
        for (j = man->frees; j > i; j--) {
            man->free[j] = man->free[j - 1];
        }
        man->frees++;    //可用条目加1
        if (man->maxfrees < man->frees) {
            man->maxfrees = man->frees; /* 更新最大值 */
        }
        //添加条目
        man->free[i].addr = addr;
        man->free[i].size = size;
        return 0; /* 成功释放*/
    }
    /* 不能往后移动 */
    man->losts++;
    man->lostsize += size;
    return -1; /* 失敗 */
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值