赞
踩
6 内存管理
大家在日常开发的时候经常用到malloc和free函数。但是,在内核中,我们并没有malloc和free这两个函数。这该怎么办呢?
答案是自己规划。我们先建立kernel/memory/memory.c,然后把cstart中的内存处理相关程序移动到memory.c。
为了保持内存使用的对齐,我们将所有可用的内存分组,最少为8字节一组,然后16字节……以此类推,最大可达2GB一组。内存中,我们用链表的形式,链表节点存放在空闲内存的前4字节的位置上。
知道原理以后,代码其实很好写。
另外,笔者观赏了一下GCC生成的代码,感觉非常狗屎,memory_free函数笔者用汇编可以21行写出的代码,GCC用了38行,而且还是手工对C代码优化过后的。这38行中包含大量的内存操作。而笔者的代码完全没有进行过内存操作。设想这是一段核心代码(还真的是核心代码),这点小小的时间差距会累积成多大!malloc函数笔者用了16行,而GCC用了39行。这就体现了为什么大型工程中的核心代码都是汇编写的。在用汇编改写之后,最后的二进制文件减小了1.5KB。在NorlitOS最初的开发阶段中,我们会尽少使用汇编,但是之后的优化工程中,汇编是必不可少的。
u_addr* memoryBlocks[30]={EMPTY,EMPTY,EMPTY,EMPTY,EMPTY,EMPTY,EMPTY,EMPTY,//0-7 Bytes
EMPTY,EMPTY,EMPTY,EMPTY,EMPTY,EMPTY,EMPTY,EMPTY,EMPTY,EMPTY,//8-17 KBs
EMPTY,EMPTY,EMPTY,EMPTY,EMPTY,EMPTY,EMPTY,EMPTY,EMPTY,EMPTY,//18-27 MBs
EMPTY,EMPTY};// 28-29 GBs
代码6.1.1数据结构(chapter6/a/kernel/memory/memory.c)
我们不管理4Bytes以下的内存,因为管理这些内存会给系统额外的开销。对于这些内存,我们简单地丢弃它们。不过,使用malloc和free功能永远也不会产生这些多余项。EMPTY被定义成了0xFFFFFFFF,但其实0xFFFFFFD和0xFFFFFFFE也是可以的。超过4KB的内存实际上应该让分页机制管理了,但是在分页机制实现之前,我们先把实现容许的最大范围变成2^31次,也就是2GB。
笔者修改了loader.asm,将cpuid.inc与之合并,并且加入了检测分页机制支持的功能。
CPUInit:
pushfd ;储存EFLAGS
mov eax,[esp] ;保存老的EFLAGS
bts dword[esp],21 ;更改EFLAGS.ID
popfd ;设置EFLAGS
pushfd ;保存新EFLAGS
pop ebx ;EBX=EFLAGS
cmp eax,ebx ;检查EFLAGS.ID有没有被成功更改
je .nocpuid
mov eax,0x80000000 ; CPU扩展信息
cpuid
cmp eax,0x80000001
xor eax,eax
jb .nonx ;不支持CPU扩展信息
mov eax,0x80000001
cpuid
xor eax,eax
bt edx,20 ;Check NX
adc al,0
shl al,1
.nonx:
push eax
mov eax,0x7
xor ecx,ecx
cpuid
pop eax
bt ebx,7 ;Check SMEP
adc al,0
shl al,1
push eax ;Reserved NX SMEP PSE-36 PAT PGE PAE PSE
mov eax,0x1
cpuid
pop eax
bt edx,17 ;Check PSE-36
adc al,0
shl al,1
bt edx,16 ;Check PAT
adc al,0
shl ax,1
bt edx,13 ;Check PAT
adc ax,0
shl ax,1
bt edx,6 ;Check PAE
adc ax,0
shl ax,1
bt edx,3 ; CheckPSE
adc ax,0
mov [BootParamPhyAddr+ PGInfo],eax
bt eax,1
jc PagingOnPAE
jmp PagingOn
.nocpuid:
mov esi, STR_FAIL
call DispStrPM
cli
hlt
代码6.1.2检测机能(chapter6/a/boot/loader.asm)
当然了,由于我们修改了0x500处的结构,别忘记同时修改loader.inc和struct。
FASTCALLstaticvoidmemory_block_free(u_addraddress, u_addr sizep, u8 bit){
u_addr* ll=(u_addr*)address;
u_addr** head=&memoryBlocks[bit-2];
u_addr*entry=*head;
u_addr**prev=head;
for(;entry!=EMPTY;prev=(u_addr**)entry,entry=*prev){
if(entry>ll){
if(!(address&sizep
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。