内存管理分为物理内存管理,线性内存管理。物理内存用Map方式管理,线性内内用分块链接表方式管理。
以bochs为例,其物理内存分段情况:
开始地址 | 大小 | 类型 | 说明 | |
0x00000000 | 0x0009f000 | 1 | 可供操作系统使用 | 中断向量表 |
0x0009f000 | 0x00001000 | 2 | 正在由系统使用或保留 | |
0x000e8000 | 0x00018000 | 2 | 正在由系统使用或保留 | |
0x00100000 | 0x01ef0000 | 1 | 可供操作系统使用 | |
0x01ff0000 | 0x00010000 | 3 | 其他未定义 | |
0xfffc0000 | 0x00040000 | 2 | 正在由系统使用或保留 |
一、物理内存管理
在线性内存空间里建立一个内存块(这个位置固定在系统映像+系统栈之后8K,都是4K对齐),以映像(map)的方式管理,将线性地址按4K一块,映像中每个字节表示一个物理内存块的状态,8KB可以标注32M线性内存,当前块使用一次则增加1,释放则减1,如果该数字为0表示为空闲块。
前1M:物理内存地址=线性内存地址,该空间先不使用,全部置1。从0x100000开始,页目录(4K)、页表(?)、系统映映像(?)、系统栈(16K)、内存map(8K)、空闲(?)、特殊用途(?)。?表示根据实际需要计算大小。
需要申请空内存块时可以遍历map映像找到一个空块或者从大块中分割出小块。
释放时,检查下前块及后块是否是空闲的,如果空闲则合并。
PBYTE lpPhysicsMap; //物理内存管理map
//增加该变量可以节省搜索时间
DWORD lpPhysicsMapSearchPos; //map 初始化时记录第一个未使用的物理内存,在分配时记录搜索过的地址,释放时记录最小地址
DWORD dwPhysicsFreeCount;//空物理内存数
DWORD dwPhysicsCount; //总物理内存
void set_physics_4k(DWORD addr,DWORD size,DWORD type)
{
if(addr<4096*4096*2)
memset(lpPhysicsMap+addr/4096,type,size/4096);
}
void init_Physics()
{//lb 0x080405158
//物理内存按4K一块占1字节,做成一个MAP,32M 需要 8K;
//此处还无法使用mem_virtual_alloc函数,因此让osloader.asm预留8K.
//
//数据在osloader.asm里通过int 15h查询
PE820MAP pm=0x7F00;
//物理内存列表
DWORD size,UsedMem;//x
//0x80400000 为内核加载地址,即文件头
//内核占用内存
size=((PIMAGE_DOS_HEADER)0x80400000)->e_lfanew+0x80400000;
size=((PIMAGE_NT_HEADERS)size)->OptionalHeader.SizeOfImage;
print_farmat_msg("oskrnl. size :%x\n",size);
//已经使用的线性空间,内核+栈(4页)+map(2页)=0x14000+0x4000+0x2000
size+=0x6000;
lpPhysicsMap=size+0x80400000-0x2000;
//全部设置为不可用
dwPhysicsFreeCount=0;
dwPhysicsCount=0;
for (int i=0;i<pm->nr_map;i++)
{
dwPhysicsCount+=pm->map[i].size;
print_farmat_msg("%8x\t,%8x\t,%x\n",pm->map[i].addr,pm->map[i].size,pm->map[i].type);
//type: 1 AddressRangeMemory 此运行是可供操作系统使用的可用 RAM 。
// 2 AddressRangeReserved 该地址段正在由系统使用或保留,并且不得由操作系统使用。
//其他未定义 未定义 - 保留供将来使用。
//可用内存,1M以前的内存暂时保留不用
if(pm->map[i].addr<0x100000)
{
//前1M设置为不可用
continue;
}
if(pm->map[i].type==1)
{
set_physics_4k(pm->map[i].addr,pm->map[i].size,0);
dwPhysicsFreeCount+=pm->map[i].size;
}
else
{
set_physics_4k(pm->map[i].addr,pm->map[i].size,1);
//2 "ARR" is AddressRangeReserved.
//
}
}
//最后一个已经被使用的物理页 1M+页目录+页表+内核+栈+map
UsedMem=*(DWORD *)MiGetPteAddress(size+0x80400000-4)&0xFFFFF000;
UsedMem+=0x1000; //指向第一个可用空闲地址,
print_farmat_msg(" next free Physics mem :%x\n",UsedMem);
//前1M 、已经使用的物理内存全部置1
set_physics_4k(0,UsedMem,1);
//搜索开始位置
lpPhysicsMapSearchPos=UsedMem;
}
//每次一页4K
DWORD get_freed_Physics()
{
DWORD p=0;
//lpPhysicsMapCurrent记录以前查找过的块
DWORD m=lpPhysicsMapSearchPos;
//没有超过边界,遍历map
while(m<dwPhysicsCount)
{
if(lpPhysicsMap[m/4096]==0)
{
//当前位置map置1
lpPhysicsMap[m/4096]=1;
//记录当前位置
lpPhysicsMapSearchPos=m;
//返回实际物理地址;
p=m;
break;
}
m++;
}
return p;
}
void free_Physics(DWORD page)
{
//先
if(--lpPhysicsMap[page/4096]<=0)
{
//当前块减少映射后为空闲块,
lpPhysicsMap[page/4096]=0; //正常情况下,当前傎应当不会小于0
//如果搜索指在前面,则后至当前位置
if(lpPhysicsMapSearchPos>page)
{
lpPhysicsMapSearchPos=page;
}
}
else
{
}
}