9、内存管理

内存容量检查
bootpack.c节选

//内存检查
    i = memtest(0x00400000, 0xbfffffff) / (1024 * 1024);
    sprintf(s, "memory %dMB", i);
    putfonts8_asc(binfo->vram, binfo->scrnx, 0, 32, COL8_FFFFFF, s);

///////////////////////////////////////////////////////

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

    /* 确认CPU是386还是486以上的,如果是486以上,EFLAGS寄存器的第18位应该是AC标志位 */
    eflg = io_load_eflags();
    eflg |= EFLAGS_AC_BIT; /* 将AC置为1 */
    io_store_eflags(eflg);  
    eflg = io_load_eflags(); //然后再读出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;
}

nasfunc.nas节选

 GLOBAL _load_cr0, _store_cr0
 GLOBAL _memtest_sub

 _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

_memtest_sub:   ; unsigned int memtest_sub(unsigned int start, unsigned int end)
        PUSH    EDI             ; 由于还要使用EDI,ESI,EBX
        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;
        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

这里写图片描述

内存管理
bootpack.c节选

unsigned int memtotal;
struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;

memtotal = memtest(0x00400000, 0xbfffffff);
memman_init(memman);
memman_free(memman, 0x00001000, 0x0009e000); /* 0x00001000 - 0x0009efff */
memman_free(memman, 0x00400000, memtotal - 0x00400000);

sprintf(s, "memory %dMB   free : %dKB",memtotal / (1024 * 1024), memman_total(memman) / 1024);
putfonts8_asc(binfo->vram, binfo->scrnx, 0, 32,COL8_FFFFFF, s);

///

#define MEMMAN_FREES    4090        /* 大约是32KB */
#define MEMMAN_ADDR 0x003c0000  

struct FREEINFO  /* 可用信息 */
{   
    unsigned int addr, size;  //内存起始地址,大小
};

struct MEMMAN  /* 内存管理 */
{       
    int frees, maxfrees;  //可用内存数,最大可用内存数
    int lostsize, losts;  //释放失败的内存总容量,释放失败的次数
    struct FREEINFO free[MEMMAN_FREES];  
};

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) 
            {
                /* 如果free[i]变成了0,就剪掉一条可用信息 */
                man->frees--;
                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;
    /* 为便于归纳内存,将free[]按照addr的顺序排练 */
    /* 所以,先觉得应该放在哪里 */
    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]之后的,向后移动,腾出一点可用空间 */
        for (j = man->frees; j > i; j--) 
            man->free[j] = man->free[j - 1];
        man->frees++;
        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; /* 失败 */
}

改善内存管理
之前是以字节为单位进行管理,容易出现很多不连续的小段未使用空间,现在以0x1000字节为单位进行内存分配和释放
memery.c节选

unsigned int memman_alloc_4k(struct MEMMAN *man, unsigned int size)
{
    unsigned int a;
    size = (size + 0xfff) & 0xfffff000;  //按0x1000向上取整
    a = memman_alloc(man, size);
    return a;
}

int memman_free_4k(struct MEMMAN *man, unsigned int addr, unsigned int size)
{
    int i;
    size = (size + 0xfff) & 0xfffff000;  
    i = memman_free(man, addr, size);
    return i;
}

这里写图片描述

总结一下内存容量检查:
1、确认CPU是386还是486以上,如果是486以上的话,禁止缓存,386的话不用,因为386没有缓存。
2、进行内存检查。先保存内存中的值,然后往内存中写入一个值,接着反转,检查反转后的结果是否正确,然后再反转,检查是否恢复,最后恢复内存之前的值。如果在某个环节出错,则终止,返回出错处的地址。
3、允许缓存。

总结一下内容管理:
1、设置4096条内存管理信息,每一条管理信息中包括内存起始地址,内存大小。
2、对内存管理进行初始化,主要是将frees(可用管理信息数)设为0。
3、memman_total计算可用内存的合计大小,并返回。
4、memman_alloc进行内存分配。从编号为0管理信息表中开始找,找到足够大的内存,然后进行分配,修改该条管理信息,如果该条管理信息所管理的区域没有剩余的内存,则可用信息数frees减1,并将后面的管理信息位置向前移动,覆盖掉当前管理信息的位置。
5、memman_free进行内存释放。首先所释放内存的合适位置,然后查看它是否可与前面的可用内存合并,如果能则合并,再查看它是否能与后面的可用内存合并,如果能则合并。如果都不能合并,则后面的内存后移,空出一个空间存放该释放后的内存的管理信息,并且可用用信息数加1,如果需要更新最大可用信息数。如果后移失败,即内存管理信息数超出了设定的最大值,报告释放失败。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值