Appearance
内存管理
整理文件
mkefile
OBJS_BOOTPACK = bootpack.obj naskfunc.obj hankaku.obj graphic.obj dsctbl.obj \
int.obj fifo.obj keyboard.obj mouse.obj
TOOLPATH = ../z_tools/
INCPATH = ../z_tools/haribote/
MAKE = $(TOOLPATH)make.exe -r
NASK = $(TOOLPATH)nask.exe
CC1 = $(TOOLPATH)cc1.exe -I$(INCPATH) -Os -Wall -quiet
GAS2NASK = $(TOOLPATH)gas2nask.exe -a
OBJ2BIM = $(TOOLPATH)obj2bim.exe
MAKEFONT = $(TOOLPATH)makefont.exe
BIN2OBJ = $(TOOLPATH)bin2obj.exe
BIM2HRB = $(TOOLPATH)bim2hrb.exe
RULEFILE = $(TOOLPATH)haribote/haribote.rul
EDIMG = $(TOOLPATH)edimg.exe
IMGTOL = $(TOOLPATH)imgtol.com
COPY = copy
DEL = del
# デフォルト動作
default :
$(MAKE) img
# ファイル生成規則
ipl10.bin : ipl10.nas Makefile
$(NASK) ipl10.nas ipl10.bin ipl10.lst
asmhead.bin : asmhead.nas Makefile
$(NASK) asmhead.nas asmhead.bin asmhead.lst
hankaku.bin : hankaku.txt Makefile
$(MAKEFONT) hankaku.txt hankaku.bin
hankaku.obj : hankaku.bin Makefile
$(BIN2OBJ) hankaku.bin hankaku.obj _hankaku
bootpack.bim : $(OBJS_BOOTPACK) Makefile
$(OBJ2BIM) @$(RULEFILE) out:bootpack.bim stack:3136k map:bootpack.map \
$(OBJS_BOOTPACK)
# 3MB+64KB=3136KB
bootpack.hrb : bootpack.bim Makefile
$(BIM2HRB) bootpack.bim bootpack.hrb 0
haribote.sys : asmhead.bin bootpack.hrb Makefile
copy /B asmhead.bin+bootpack.hrb haribote.sys
haribote.img : ipl10.bin haribote.sys Makefile
$(EDIMG) imgin:../z_tools/fdimg0at.tek \
wbinimg src:ipl10.bin len:512 from:0 to:0 \
copy from:haribote.sys to:@: \
imgout:haribote.img
# 一般規則
%.gas : %.c bootpack.h Makefile
$(CC1) -o $*.gas $*.c
%.nas : %.gas Makefile
$(GAS2NASK) $*.gas $*.nas
%.obj : %.nas Makefile
$(NASK) $*.nas $*.obj $*.lst
# コマンド
img :
$(MAKE) haribote.img
run :
$(MAKE) img
$(COPY) haribote.img ..\z_tools\qemu\fdimage0.bin
$(MAKE) -C ../z_tools/qemu
install :
$(MAKE) img
$(IMGTOL) w a: haribote.img
clean :
-$(DEL) *.bin
-$(DEL) *.lst
-$(DEL) *.obj
-$(DEL) bootpack.map
-$(DEL) bootpack.bim
-$(DEL) bootpack.hrb
-$(DEL) haribote.sys
src_only :
$(MAKE) clean
-$(DEL) haribote.img
内存容量检查
在进行检测之前需要首先关闭高速缓存
内存检测的时候需要向内存写入数据之后读取回来, 检测是否相等, 有缓存的话会导致结果不正确, 386之前的CPU没有使用缓存
c
#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的版本 */
eflg = io_load_eflags(); /* 获取标志位 */
eflg |= EFLAGS_AC_BIT; /* AC-bit = 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-bit = 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;
}
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, 为了加快检测的速度
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;
}
assembly
_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
c
i = memtest(0x00400000, 0xbfffffff) / (1024 * 1024);
sprintf(s, "memory %dMB", i);
putfonts8_asc(binfo->vram, binfo->scrnx, 0, 32, COL8_FFFFFF, s);
但是这样处理编译器会自动忽略翻转以及填充的动作,所以把程序改为汇编程序
汇编免除优化
assembly
_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;
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
使用的方法
- 使用一个数组, 4KB为一个单位, 使用的话就进行标记, 但是数组的占用内存很大
- 链表管理方法, 把地址的信息记录在链表里面
c
#define MEMMAN_FREES 4090 /* 大约专用32KB */
#define MEMMAN_ADDR 0x003c0000
struct FREEINFO { /* 可以使用的信息 */
unsigned int addr, size;
};
struct MEMMAN { /* 内存管理 */
int frees, maxfrees, lostsize, losts;
struct FREEINFO free[MEMMAN_FREES];
};
void memman_init(struct MEMMAN *man)
{
man->frees = 0; /* 可用的信息为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]全部使用掉饿了 */
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按照地址的顺序进行管理 */
/* 首先确定内存的位置 */
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]变成0归纳道歉卖你 */
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; /* 失敗了 */
}
c
unsigned int memtotal;
struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; //初始化管理的结构体
memtotal = memtest(0x00400000, 0xbfffffff); //获得可以使用的内存的大小
memman_init(memman); //初始化 ?置所有?0
memman_free(memman, 0x00001000, 0x0009e000); /* 0x00001000 - 0x0009efff */
memman_free(memman, 0x00400000, memtotal - 0x00400000);//保存可以使用的内存