|
|
|
|
# 17 | 划分土地(中):如何实现内存页面初始化?
|
|
|
|
|
|
|
|
|
|
你好,我是LMOS。
|
|
|
|
|
|
|
|
|
|
上节课,我们确定了用分页方式管理内存,并且一起动手设计了表示内存页、内存区相关的内存管理数据结构。不过,虽然内存管理相关的数据结构已经定义好了,但是我们还没有在内存中建立对应的**实例变量**。
|
|
|
|
|
|
|
|
|
|
我们都知道,在代码中实际操作的数据结构必须在内存中有相应的变量,这节课我们就去建立对应的实例变量,并初始化它们。
|
|
|
|
|
|
|
|
|
|
## 初始化
|
|
|
|
|
|
|
|
|
|
前面的课里,我们在hal层初始化中,初始化了从二级引导器中获取的内存布局信息,也就是那个**e820map\_t数组**,并把这个数组转换成了phymmarge\_t结构数组,还对它做了排序。
|
|
|
|
|
|
|
|
|
|
但是,我们Cosmos物理内存管理器剩下的部分还没有完成初始化,下面我们就去实现它。
|
|
|
|
|
|
|
|
|
|
Cosmos的物理内存管理器,我们依然要放在Cosmos的hal层。
|
|
|
|
|
|
|
|
|
|
因为物理内存还和硬件平台相关,所以我们要在cosmos/hal/x86/目录下建立一个memmgrinit.c文件,在这个文件中写入一个Cosmos物理内存管理器初始化的大总管——init\_memmgr函数,并在init\_halmm函数中调用它,代码如下所示。
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
//cosmos/hal/x86/halmm.c中
|
|
|
|
|
//hal层的内存初始化函数
|
|
|
|
|
void init_halmm()
|
|
|
|
|
{
|
|
|
|
|
init_phymmarge();
|
|
|
|
|
init_memmgr();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
//Cosmos物理内存管理器初始化
|
|
|
|
|
void init_memmgr()
|
|
|
|
|
{
|
|
|
|
|
//初始化内存页结构msadsc_t
|
|
|
|
|
//初始化内存区结构memarea_t
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
根据前面我们对内存管理相关数据结构的设计,你应该不难想到,在init\_memmgr函数中应该要完成**内存页结构msadsc\_t和内存区结构memarea\_t的初始化**,下面就分别搞定这两件事。
|
|
|
|
|
|
|
|
|
|
### 内存页结构初始化
|
|
|
|
|
|
|
|
|
|
内存页结构的初始化,其实就是初始化msadsc\_t结构对应的变量。因为一个msadsc\_t结构体变量代表一个物理内存页,而物理内存由多个页组成,所以最终会形成一个msadsc\_t结构体数组。
|
|
|
|
|
|
|
|
|
|
这会让我们的工作变得简单,我们只需要找一个内存地址,作为msadsc\_t结构体数组的开始地址,当然这个内存地址必须是可用的,而且之后内存空间足以存放msadsc\_t结构体数组。
|
|
|
|
|
|
|
|
|
|
然后,我们要扫描phymmarge\_t结构体数组中的信息,只要它的类型是可用内存,就建立一个msadsc\_t结构体,并把其中的开始地址作为第一个页面地址。
|
|
|
|
|
|
|
|
|
|
接着,要给这个开始地址加上0x1000,如此循环,直到其结束地址。
|
|
|
|
|
|
|
|
|
|
当这个phymmarge\_t结构体的地址区间,它对应的所有msadsc\_t结构体都建立完成之后,就开始下一个phymmarge\_t结构体。依次类推,最后,我们就能建好所有可用物理内存页面对应的msadsc\_t结构体。
|
|
|
|
|
|
|
|
|
|
下面,我们去cosmos/hal/x86/目录下建立一个msadsc.c文件。在这里写下完成这些功能的代码,如下所示。
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
void write_one_msadsc(msadsc_t *msap, u64_t phyadr)
|
|
|
|
|
{
|
|
|
|
|
//对msadsc_t结构做基本的初始化,比如链表、锁、标志位
|
|
|
|
|
msadsc_t_init(msap);
|
|
|
|
|
//这是把一个64位的变量地址转换成phyadrflgs_t*类型方便取得其中的地址位段
|
|
|
|
|
phyadrflgs_t *tmp = (phyadrflgs_t *)(&phyadr);
|
|
|
|
|
//把页的物理地址写入到msadsc_t结构中
|
|
|
|
|
msap->md_phyadrs.paf_padrs = tmp->paf_padrs;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u64_t init_msadsc_core(machbstart_t *mbsp, msadsc_t *msavstart, u64_t msanr)
|
|
|
|
|
{
|
|
|
|
|
//获取phymmarge_t结构数组开始地址
|
|
|
|
|
phymmarge_t *pmagep = (phymmarge_t *)phyadr_to_viradr((adr_t)mbsp->mb_e820expadr);
|
|
|
|
|
u64_t mdindx = 0;
|
|
|
|
|
//扫描phymmarge_t结构数组
|
|
|
|
|
for (u64_t i = 0; i < mbsp->mb_e820exnr; i++)
|
|
|
|
|
{
|
|
|
|
|
//判断phymmarge_t结构的类型是不是可用内存
|
|
|
|
|
if (PMR_T_OSAPUSERRAM == pmagep[i].pmr_type)
|
|
|
|
|
{
|
|
|
|
|
//遍历phymmarge_t结构的地址区间
|
|
|
|
|
for (u64_t start = pmagep[i].pmr_saddr; start < pmagep[i].pmr_end; start += 4096)
|
|
|
|
|
{
|
|
|
|
|
//每次加上4KB-1比较是否小于等于phymmarge_t结构的结束地址
|
|
|
|
|
if ((start + 4096 - 1) <= pmagep[i].pmr_end)
|
|
|
|
|
{
|
|
|
|
|
//与当前地址为参数写入第mdindx个msadsc结构
|
|
|
|
|
write_one_msadsc(&msavstart[mdindx], start);
|
|
|
|
|
mdindx++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return mdindx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void init_msadsc()
|
|
|
|
|
{
|
|
|
|
|
u64_t coremdnr = 0, msadscnr = 0;
|
|
|
|
|
msadsc_t *msadscvp = NULL;
|
|
|
|
|
machbstart_t *mbsp = &kmachbsp;
|
|
|
|
|
//计算msadsc_t结构数组的开始地址和数组元素个数
|
|
|
|
|
if (ret_msadsc_vadrandsz(mbsp, &msadscvp, &msadscnr) == FALSE)
|
|
|
|
|
{
|
|
|
|
|
system_error("init_msadsc ret_msadsc_vadrandsz err\n");
|
|
|
|
|
}
|
|
|
|
|
//开始真正初始化msadsc_t结构数组
|
|
|
|
|
coremdnr = init_msadsc_core(mbsp, msadscvp, msadscnr);
|
|
|
|
|
if (coremdnr != msadscnr)
|
|
|
|
|
{
|
|
|
|
|
system_error("init_msadsc init_msadsc_core err\n");
|
|
|
|
|
}
|
|
|
|
|
//将msadsc_t结构数组的开始的物理地址写入kmachbsp结构中
|
|
|
|
|
mbsp->mb_memmappadr = viradr_to_phyadr((adr_t)msadscvp);
|
|
|
|
|
//将msadsc_t结构数组的元素个数写入kmachbsp结构中
|
|
|
|
|
mbsp->mb_memmapnr = coremdnr;
|
|
|
|
|
//将msadsc_t结构数组的大小写入kmachbsp结构中
|
|
|
|
|
mbsp->mb_memmapsz = coremdnr * sizeof(msadsc_t);
|
|
|
|
|
//计算下一个空闲内存的开始地址
|
|
|
|
|
mbsp->mb_nextwtpadr = PAGE_ALIGN(mbsp->mb_memmappadr + mbsp->mb_memmapsz);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
上面的代码量很少,逻辑也很简单,再配合注释,相信你看得懂。其中的ret\_msadsc\_vadrandsz函数也是遍历phymmarge\_t结构数组,计算出有多大的可用内存空间,可以分成多少个页面,需要多少个msadsc\_t结构。
|
|
|
|
|
|
|
|
|
|
### 内存区结构初始化
|
|
|
|
|
|
|
|
|
|
前面我们将整个物理地址空间在逻辑上分成了三个区,分别是**:硬件区、内核区、用户区**,这就要求我们要在内存中建立三个memarea\_t结构体的实例变量。
|
|
|
|
|
|
|
|
|
|
就像建立msadsc\_t结构数组一样,我们只需要在内存中找个空闲空间,存放这三个memarea\_t结构体就行。相比建立msadsc\_t结构数组这更为简单,因为memarea\_t结构体是顶层结构,并不依赖其它数据结构,只是对其本身进行初始化就好了。
|
|
|
|
|
|
|
|
|
|
但是由于它自身包含了其它数据结构,在初始化它时,要对其中的其它数据结构进行初始化,所以要小心一些。
|
|
|
|
|
|
|
|
|
|
下面我们去cosmos/hal/x86/目录下建立一个memarea.c文件,写下完成这些功能的代码,如下所示。
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
void bafhlst_t_init(bafhlst_t *initp, u32_t stus, uint_t oder, uint_t oderpnr)
|
|
|
|
|
{
|
|
|
|
|
//初始化bafhlst_t结构体的基本数据
|
|
|
|
|
knl_spinlock_init(&initp->af_lock);
|
|
|
|
|
initp->af_stus = stus;
|
|
|
|
|
initp->af_oder = oder;
|
|
|
|
|
initp->af_oderpnr = oderpnr;
|
|
|
|
|
initp->af_fobjnr = 0;
|
|
|
|
|
initp->af_mobjnr = 0;
|
|
|
|
|
initp->af_alcindx = 0;
|
|
|
|
|
initp->af_freindx = 0;
|
|
|
|
|
list_init(&initp->af_frelst);
|
|
|
|
|
list_init(&initp->af_alclst);
|
|
|
|
|
list_init(&initp->af_ovelst);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void memdivmer_t_init(memdivmer_t *initp)
|
|
|
|
|
{
|
|
|
|
|
//初始化medivmer_t结构体的基本数据
|
|
|
|
|
knl_spinlock_init(&initp->dm_lock);
|
|
|
|
|
initp->dm_stus = 0;
|
|
|
|
|
initp->dm_divnr = 0;
|
|
|
|
|
initp->dm_mernr = 0;
|
|
|
|
|
//循环初始化memdivmer_t结构体中dm_mdmlielst数组中的每个bafhlst_t结构的基本数据
|
|
|
|
|
for (uint_t li = 0; li < MDIVMER_ARR_LMAX; li++)
|
|
|
|
|
{
|
|
|
|
|
bafhlst_t_init(&initp->dm_mdmlielst[li], BAFH_STUS_DIVM, li, (1UL << li));
|
|
|
|
|
}
|
|
|
|
|
bafhlst_t_init(&initp->dm_onemsalst, BAFH_STUS_ONEM, 0, 1UL);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void memarea_t_init(memarea_t *initp)
|
|
|
|
|
{
|
|
|
|
|
//初始化memarea_t结构体的基本数据
|
|
|
|
|
list_init(&initp->ma_list);
|
|
|
|
|
knl_spinlock_init(&initp->ma_lock);
|
|
|
|
|
initp->ma_stus = 0;
|
|
|
|
|
initp->ma_flgs = 0;
|
|
|
|
|
initp->ma_type = MA_TYPE_INIT;
|
|
|
|
|
initp->ma_maxpages = 0;
|
|
|
|
|
initp->ma_allocpages = 0;
|
|
|
|
|
initp->ma_freepages = 0;
|
|
|
|
|
initp->ma_resvpages = 0;
|
|
|
|
|
initp->ma_horizline = 0;
|
|
|
|
|
initp->ma_logicstart = 0;
|
|
|
|
|
initp->ma_logicend = 0;
|
|
|
|
|
initp->ma_logicsz = 0;
|
|
|
|
|
//初始化memarea_t结构体中的memdivmer_t结构体
|
|
|
|
|
memdivmer_t_init(&initp->ma_mdmdata);
|
|
|
|
|
initp->ma_privp = NULL;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool_t init_memarea_core(machbstart_t *mbsp)
|
|
|
|
|
{
|
|
|
|
|
//获取memarea_t结构开始地址
|
|
|
|
|
u64_t phymarea = mbsp->mb_nextwtpadr;
|
|
|
|
|
//检查内存空间够不够放下MEMAREA_MAX个memarea_t结构实例变量
|
|
|
|
|
if (initchkadr_is_ok(mbsp, phymarea, (sizeof(memarea_t) * MEMAREA_MAX)) != 0)
|
|
|
|
|
{
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
memarea_t *virmarea = (memarea_t *)phyadr_to_viradr((adr_t)phymarea);
|
|
|
|
|
for (uint_t mai = 0; mai < MEMAREA_MAX; mai++)
|
|
|
|
|
{ //循环初始化每个memarea_t结构实例变量
|
|
|
|
|
memarea_t_init(&virmarea[mai]);
|
|
|
|
|
}
|
|
|
|
|
//设置硬件区的类型和空间大小
|
|
|
|
|
virmarea[0].ma_type = MA_TYPE_HWAD;
|
|
|
|
|
virmarea[0].ma_logicstart = MA_HWAD_LSTART;
|
|
|
|
|
virmarea[0].ma_logicend = MA_HWAD_LEND;
|
|
|
|
|
virmarea[0].ma_logicsz = MA_HWAD_LSZ;
|
|
|
|
|
//设置内核区的类型和空间大小
|
|
|
|
|
virmarea[1].ma_type = MA_TYPE_KRNL;
|
|
|
|
|
virmarea[1].ma_logicstart = MA_KRNL_LSTART;
|
|
|
|
|
virmarea[1].ma_logicend = MA_KRNL_LEND;
|
|
|
|
|
virmarea[1].ma_logicsz = MA_KRNL_LSZ;
|
|
|
|
|
//设置应用区的类型和空间大小
|
|
|
|
|
virmarea[2].ma_type = MA_TYPE_PROC;
|
|
|
|
|
virmarea[2].ma_logicstart = MA_PROC_LSTART;
|
|
|
|
|
virmarea[2].ma_logicend = MA_PROC_LEND;
|
|
|
|
|
virmarea[2].ma_logicsz = MA_PROC_LSZ;
|
|
|
|
|
//将memarea_t结构的开始的物理地址写入kmachbsp结构中
|
|
|
|
|
mbsp->mb_memznpadr = phymarea;
|
|
|
|
|
//将memarea_t结构的个数写入kmachbsp结构中
|
|
|
|
|
mbsp->mb_memznnr = MEMAREA_MAX;
|
|
|
|
|
//将所有memarea_t结构的大小写入kmachbsp结构中
|
|
|
|
|
mbsp->mb_memznsz = sizeof(memarea_t) * MEMAREA_MAX;
|
|
|
|
|
//计算下一个空闲内存的开始地址
|
|
|
|
|
mbsp->mb_nextwtpadr = PAGE_ALIGN(phymarea + sizeof(memarea_t) * MEMAREA_MAX);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
//初始化内存区
|
|
|
|
|
void init_memarea()
|
|
|
|
|
{
|
|
|
|
|
//真正初始化内存区
|
|
|
|
|
if (init_memarea_core(&kmachbsp) == FALSE)
|
|
|
|
|
{
|
|
|
|
|
system_error("init_memarea_core fail");
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
由于这些数据结构很大,所以代码有点长,但是重要的代码我都做了详细注释。
|
|
|
|
|
|
|
|
|
|
在init\_memarea\_core函数的开始,我们调用了memarea\_t\_init函数,对MEMAREA\_MAX个memarea\_t结构进行了基本的初始化。
|
|
|
|
|
|
|
|
|
|
然后,在memarea\_t\_init函数中又调用了memdivmer\_t\_init函数,而在memdivmer\_t\_init函数中又调用了bafhlst\_t\_init函数,这保证了那些被包含的数据结构得到了初始化。
|
|
|
|
|
|
|
|
|
|
最后,我们给三个区分别设置了类型和地址空间。
|
|
|
|
|
|
|
|
|
|
### 处理初始内存占用问题
|
|
|
|
|
|
|
|
|
|
我们初始化了内存页和内存区对应的数据结构,已经可以组织好内存页面了。现在看似已经万事俱备了,其实这有个重大的问题,你知道是什么吗?我给你分析一下。
|
|
|
|
|
|
|
|
|
|
目前我们的内存中已经有很多数据了,有Cosmos内核本身的执行文件,有字体文件,有MMU页表,有打包的内核映像文件,还有刚刚建立的内存页和内存区的数据结构,这些数据都要占用实际的物理内存。
|
|
|
|
|
|
|
|
|
|
再回头看看我们建立内存页结构msadsc\_t,所有的都是空闲状态,而它们每一个都表示一个实际的物理内存页。
|
|
|
|
|
|
|
|
|
|
假如在这种情况下,对调用内存分配接口进行内存分配,**它按既定的分配算法查找空闲的msadsc\_t结构,那它一定会找到内核占用的内存页所对应的msadsc\_t结构,并把这个内存页分配出去,然后得到这个页面的程序对其进行改写。这样内核数据就会被覆盖,这种情况是我们绝对不能允许的。**
|
|
|
|
|
|
|
|
|
|
所以,我们要把这些已经占用的内存页面所对应的msadsc\_t结构标记出来,标记成**已分配**,这样内存分配算法就不会找到它们了。
|
|
|
|
|
|
|
|
|
|
要解决这个问题,我们只要给出被占用内存的起始地址和结束地址,然后从起始地址开始查找对应的msadsc\_t结构,再把它标记为已经分配,最后直到查找到结束地址为止。
|
|
|
|
|
|
|
|
|
|
下面我们在msadsc.c文件中来实现这个方案,代码如下。
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
//搜索一段内存地址空间所对应的msadsc_t结构
|
|
|
|
|
u64_t search_segment_occupymsadsc(msadsc_t *msastart, u64_t msanr, u64_t ocpystat, u64_t ocpyend)
|
|
|
|
|
{
|
|
|
|
|
u64_t mphyadr = 0, fsmsnr = 0;
|
|
|
|
|
msadsc_t *fstatmp = NULL;
|
|
|
|
|
for (u64_t mnr = 0; mnr < msanr; mnr++)
|
|
|
|
|
{
|
|
|
|
|
if ((msastart[mnr].md_phyadrs.paf_padrs << PSHRSIZE) == ocpystat)
|
|
|
|
|
{
|
|
|
|
|
//找出开始地址对应的第一个msadsc_t结构,就跳转到step1
|
|
|
|
|
fstatmp = &msastart[mnr];
|
|
|
|
|
goto step1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
step1:
|
|
|
|
|
fsmsnr = 0;
|
|
|
|
|
if (NULL == fstatmp)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
for (u64_t tmpadr = ocpystat; tmpadr < ocpyend; tmpadr += PAGESIZE, fsmsnr++)
|
|
|
|
|
{
|
|
|
|
|
//从开始地址对应的第一个msadsc_t结构开始设置,直到结束地址对应的最后一个masdsc_t结构
|
|
|
|
|
mphyadr = fstatmp[fsmsnr].md_phyadrs.paf_padrs << PSHRSIZE;
|
|
|
|
|
if (mphyadr != tmpadr)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (MF_MOCTY_FREE != fstatmp[fsmsnr].md_indxflgs.mf_mocty ||
|
|
|
|
|
0 != fstatmp[fsmsnr].md_indxflgs.mf_uindx ||
|
|
|
|
|
PAF_NO_ALLOC != fstatmp[fsmsnr].md_phyadrs.paf_alloc)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
//设置msadsc_t结构为已经分配,已经分配给内核
|
|
|
|
|
fstatmp[fsmsnr].md_indxflgs.mf_mocty = MF_MOCTY_KRNL;
|
|
|
|
|
fstatmp[fsmsnr].md_indxflgs.mf_uindx++;
|
|
|
|
|
fstatmp[fsmsnr].md_phyadrs.paf_alloc = PAF_ALLOC;
|
|
|
|
|
}
|
|
|
|
|
//进行一些数据的正确性检查
|
|
|
|
|
u64_t ocpysz = ocpyend - ocpystat;
|
|
|
|
|
if ((ocpysz & 0xfff) != 0)
|
|
|
|
|
{
|
|
|
|
|
if (((ocpysz >> PSHRSIZE) + 1) != fsmsnr)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return fsmsnr;
|
|
|
|
|
}
|
|
|
|
|
if ((ocpysz >> PSHRSIZE) != fsmsnr)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return fsmsnr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool_t search_krloccupymsadsc_core(machbstart_t *mbsp)
|
|
|
|
|
{
|
|
|
|
|
u64_t retschmnr = 0;
|
|
|
|
|
msadsc_t *msadstat = (msadsc_t *)phyadr_to_viradr((adr_t)mbsp->mb_memmappadr);
|
|
|
|
|
u64_t msanr = mbsp->mb_memmapnr;
|
|
|
|
|
//搜索BIOS中断表占用的内存页所对应msadsc_t结构
|
|
|
|
|
retschmnr = search_segment_occupymsadsc(msadstat, msanr, 0, 0x1000);
|
|
|
|
|
if (0 == retschmnr)
|
|
|
|
|
{
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
//搜索内核栈占用的内存页所对应msadsc_t结构
|
|
|
|
|
retschmnr = search_segment_occupymsadsc(msadstat, msanr, mbsp->mb_krlinitstack & (~(0xfffUL)), mbsp->mb_krlinitstack);
|
|
|
|
|
if (0 == retschmnr)
|
|
|
|
|
{
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
//搜索内核占用的内存页所对应msadsc_t结构
|
|
|
|
|
retschmnr = search_segment_occupymsadsc(msadstat, msanr, mbsp->mb_krlimgpadr, mbsp->mb_nextwtpadr);
|
|
|
|
|
if (0 == retschmnr)
|
|
|
|
|
{
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
//搜索内核映像文件占用的内存页所对应msadsc_t结构
|
|
|
|
|
retschmnr = search_segment_occupymsadsc(msadstat, msanr, mbsp->mb_imgpadr, mbsp->mb_imgpadr + mbsp->mb_imgsz);
|
|
|
|
|
if (0 == retschmnr)
|
|
|
|
|
{
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
//初始化搜索内核占用的内存页面
|
|
|
|
|
void init_search_krloccupymm(machbstart_t *mbsp)
|
|
|
|
|
{
|
|
|
|
|
//实际初始化搜索内核占用的内存页面
|
|
|
|
|
if (search_krloccupymsadsc_core(mbsp) == FALSE)
|
|
|
|
|
{
|
|
|
|
|
system_error("search_krloccupymsadsc_core fail\n");
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
这三个函数逻辑很简单,由init\_search\_krloccupymm函数入口,search\_krloccupymsadsc\_core函数驱动,由search\_segment\_occupymsadsc函数完成实际的工作。
|
|
|
|
|
|
|
|
|
|
由于初始化阶段各种数据占用的开始、结束地址和大小,这些信息都保存在machbstart\_t类型的kmachbsp变量中,所以函数与machbstart\_t类型的指针为参数。
|
|
|
|
|
|
|
|
|
|
其实phymmarge\_t、msadsc\_t、memarea\_t这些结构的实例变量和MMU页表,它们所占用的内存空间已经涵盖在了内核自身占用的内存空间。
|
|
|
|
|
|
|
|
|
|
好了,这个问题我们已经完美解决,只要在初始化内存页结构和内存区结构之后调用init\_search\_krloccupymm函数即可。
|
|
|
|
|
|
|
|
|
|
### 合并内存页到内存区
|
|
|
|
|
|
|
|
|
|
我们做了这么多前期工作,依然没有让内存页和内存区联系起来,即让msadsc\_t结构挂载到内存区对应的数组中。只有这样,我们才能提高内存管理器的分配速度。
|
|
|
|
|
|
|
|
|
|
让我们来着手干这件事情,这件事情有点复杂,但是我给你梳理以后就会清晰很多。整体上可以分成两步。
|
|
|
|
|
|
|
|
|
|
1.**确定内存页属于哪个区**,即标定一系列msadsc\_t结构是属于哪个memarea\_t结构的。
|
|
|
|
|
2.**把特定的内存页合并**,然后挂载到特定的内存区下的memdivmer\_t结构中的dm\_mdmlielst数组中。
|
|
|
|
|
|
|
|
|
|
我们先来做第一件事,这件事比较简单,我们只要遍历每个memarea\_t结构,遍历过程中根据特定的memarea\_t结构,然后去扫描整个msadsc\_t结构数组,最后依次对比msadsc\_t的物理地址,看它是否落在memarea\_t结构的地址区间中。
|
|
|
|
|
|
|
|
|
|
如果是,就把这个memarea\_t结构的类型值写入msadsc\_t结构中,这样就一个一个打上了标签,遍历memarea\_t结构结束之后,每个msadsc\_t结构就只归属于某一个memarea\_t结构了。
|
|
|
|
|
|
|
|
|
|
我们在memarea.c文件中写几个函数,来实现前面这个步骤,代码如下所示。
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
//给msadsc_t结构打上标签
|
|
|
|
|
uint_t merlove_setallmarflgs_onmemarea(memarea_t *mareap, msadsc_t *mstat, uint_t msanr)
|
|
|
|
|
{
|
|
|
|
|
u32_t muindx = 0;
|
|
|
|
|
msadflgs_t *mdfp = NULL;
|
|
|
|
|
//获取内存区类型
|
|
|
|
|
switch (mareap->ma_type){
|
|
|
|
|
case MA_TYPE_HWAD:
|
|
|
|
|
muindx = MF_MARTY_HWD << 5;//硬件区标签
|
|
|
|
|
mdfp = (msadflgs_t *)(&muindx);
|
|
|
|
|
break;
|
|
|
|
|
case MA_TYPE_KRNL:
|
|
|
|
|
muindx = MF_MARTY_KRL << 5;//内核区标签
|
|
|
|
|
mdfp = (msadflgs_t *)(&muindx);
|
|
|
|
|
break;
|
|
|
|
|
case MA_TYPE_PROC:
|
|
|
|
|
muindx = MF_MARTY_PRC << 5;//应用区标签
|
|
|
|
|
mdfp = (msadflgs_t *)(&muindx);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
u64_t phyadr = 0;
|
|
|
|
|
uint_t retnr = 0;
|
|
|
|
|
//扫描所有的msadsc_t结构
|
|
|
|
|
for (uint_t mix = 0; mix < msanr; mix++)
|
|
|
|
|
{
|
|
|
|
|
if (MF_MARTY_INIT == mstat[mix].md_indxflgs.mf_marty)
|
|
|
|
|
{ //获取msadsc_t结构对应的地址
|
|
|
|
|
phyadr = mstat[mix].md_phyadrs.paf_padrs << PSHRSIZE;
|
|
|
|
|
//和内存区的地址区间比较
|
|
|
|
|
if (phyadr >= mareap->ma_logicstart && ((phyadr + PAGESIZE) - 1) <= mareap->ma_logicend)
|
|
|
|
|
{
|
|
|
|
|
//设置msadsc_t结构的标签
|
|
|
|
|
mstat[mix].md_indxflgs.mf_marty = mdfp->mf_marty;
|
|
|
|
|
retnr++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return retnr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool_t merlove_mem_core(machbstart_t *mbsp)
|
|
|
|
|
{
|
|
|
|
|
//获取msadsc_t结构的首地址
|
|
|
|
|
msadsc_t *mstatp = (msadsc_t *)phyadr_to_viradr((adr_t)mbsp->mb_memmappadr);
|
|
|
|
|
//获取msadsc_t结构的个数
|
|
|
|
|
uint_t msanr = (uint_t)mbsp->mb_memmapnr, maxp = 0;
|
|
|
|
|
//获取memarea_t结构的首地址
|
|
|
|
|
memarea_t *marea = (memarea_t *)phyadr_to_viradr((adr_t)mbsp->mb_memznpadr);
|
|
|
|
|
uint_t sretf = ~0UL, tretf = ~0UL;
|
|
|
|
|
//遍历每个memarea_t结构
|
|
|
|
|
for (uint_t mi = 0; mi < (uint_t)mbsp->mb_memznnr; mi++)
|
|
|
|
|
{
|
|
|
|
|
//针对其中一个memarea_t结构给msadsc_t结构打上标签
|
|
|
|
|
sretf = merlove_setallmarflgs_onmemarea(&marea[mi], mstatp, msanr);
|
|
|
|
|
if ((~0UL) == sretf)
|
|
|
|
|
{
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//遍历每个memarea_t结构
|
|
|
|
|
for (uint_t maidx = 0; maidx < (uint_t)mbsp->mb_memznnr; maidx++)
|
|
|
|
|
{
|
|
|
|
|
//针对其中一个memarea_t结构对msadsc_t结构进行合并
|
|
|
|
|
if (merlove_mem_onmemarea(&marea[maidx], mstatp, msanr) == FALSE)
|
|
|
|
|
{
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
maxp += marea[maidx].ma_maxpages;
|
|
|
|
|
}
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
//初始化页面合并
|
|
|
|
|
void init_merlove_mem()
|
|
|
|
|
{
|
|
|
|
|
if (merlove_mem_core(&kmachbsp) == FALSE)
|
|
|
|
|
{
|
|
|
|
|
system_error("merlove_mem_core fail\n");
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
我们一下子写了三个函数,它们的作用且听我一一道来。从init\_merlove\_mem函数开始,但是它并不实际干活,作为入口函数,它调用的merlove\_mem\_core函数才是真正干活的。
|
|
|
|
|
|
|
|
|
|
这个merlove\_mem\_core函数有两个遍历内存区,第一次遍历是为了完成上述第一步:确定内存页属于哪个区。
|
|
|
|
|
|
|
|
|
|
当确定内存页属于哪个区之后,就来到了第二次遍历memarea\_t结构,合并其中的msadsc\_t结构,并把它们挂载到其中的memdivmer\_t结构下的dm\_mdmlielst数组中。
|
|
|
|
|
|
|
|
|
|
这个操作就稍微有点复杂了。**第一,它要保证其中所有的msadsc\_t结构挂载到dm\_mdmlielst数组中合适的bafhlst\_t结构中。**
|
|
|
|
|
|
|
|
|
|
**第二,它要保证多个msadsc\_t结构有最大的连续性。**
|
|
|
|
|
|
|
|
|
|
举个例子,比如一个内存区中有12个页面,其中10个页面是连续的地址为0~0x9000,还有两个页面其中一个地址为0xb000,另一个地址为0xe000。
|
|
|
|
|
|
|
|
|
|
这样的情况下,需要多个页面保持最大的连续性,还有在m\_mdmlielst数组中找到合适的bafhlst\_t结构。
|
|
|
|
|
|
|
|
|
|
那么:0~0x7000这8个页面就要挂载到m\_mdmlielst数组中第3个bafhlst\_t结构中;0x8000~0x9000这2个页面要挂载到m\_mdmlielst数组中第1个bafhlst\_t结构中,而0xb000和0xe000这2个页面都要挂载到m\_mdmlielst数组中第0个bafhlst\_t结构中。
|
|
|
|
|
|
|
|
|
|
从上述代码可以看出,遍历每个内存区,然后针对其中每一个内存区进行msadsc\_t结构的合并操作,完成这个操作的是**merlove\_mem\_onmemarea**,我们这就去写好这个函数,代码如下所示。
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
bool_t continumsadsc_add_bafhlst(memarea_t *mareap, bafhlst_t *bafhp, msadsc_t *fstat, msadsc_t *fend, uint_t fmnr)
|
|
|
|
|
{
|
|
|
|
|
fstat->md_indxflgs.mf_olkty = MF_OLKTY_ODER;
|
|
|
|
|
//开始的msadsc_t结构指向最后的msadsc_t结构
|
|
|
|
|
fstat->md_odlink = fend;
|
|
|
|
|
fend->md_indxflgs.mf_olkty = MF_OLKTY_BAFH;
|
|
|
|
|
//最后的msadsc_t结构指向它属于的bafhlst_t结构
|
|
|
|
|
fend->md_odlink = bafhp;
|
|
|
|
|
//把多个地址连续的msadsc_t结构的的开始的那个msadsc_t结构挂载到bafhlst_t结构的af_frelst中
|
|
|
|
|
list_add(&fstat->md_list, &bafhp->af_frelst);
|
|
|
|
|
//更新bafhlst_t的统计数据
|
|
|
|
|
bafhp->af_fobjnr++;
|
|
|
|
|
bafhp->af_mobjnr++;
|
|
|
|
|
//更新内存区的统计数据
|
|
|
|
|
mareap->ma_maxpages += fmnr;
|
|
|
|
|
mareap->ma_freepages += fmnr;
|
|
|
|
|
mareap->ma_allmsadscnr += fmnr;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool_t continumsadsc_mareabafh_core(memarea_t *mareap, msadsc_t **rfstat, msadsc_t **rfend, uint_t *rfmnr)
|
|
|
|
|
{
|
|
|
|
|
uint_t retval = *rfmnr, tmpmnr = 0;
|
|
|
|
|
msadsc_t *mstat = *rfstat, *mend = *rfend;
|
|
|
|
|
//根据地址连续的msadsc_t结构的数量查找合适bafhlst_t结构
|
|
|
|
|
bafhlst_t *bafhp = find_continumsa_inbafhlst(mareap, retval);
|
|
|
|
|
//判断bafhlst_t结构状态和类型对不对
|
|
|
|
|
if ((BAFH_STUS_DIVP == bafhp->af_stus || BAFH_STUS_DIVM == bafhp->af_stus) && MA_TYPE_PROC != mareap->ma_type)
|
|
|
|
|
{
|
|
|
|
|
//看地址连续的msadsc_t结构的数量是不是正好是bafhp->af_oderpnr
|
|
|
|
|
tmpmnr = retval - bafhp->af_oderpnr;
|
|
|
|
|
//根据地址连续的msadsc_t结构挂载到bafhlst_t结构中
|
|
|
|
|
if (continumsadsc_add_bafhlst(mareap, bafhp, mstat, &mstat[bafhp->af_oderpnr - 1], bafhp->af_oderpnr) == FALSE)
|
|
|
|
|
{
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
//如果地址连续的msadsc_t结构的数量正好是bafhp->af_oderpnr则完成,否则返回再次进入此函数
|
|
|
|
|
if (tmpmnr == 0)
|
|
|
|
|
{
|
|
|
|
|
*rfmnr = tmpmnr;
|
|
|
|
|
*rfend = NULL;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
//挂载bafhp->af_oderpnr地址连续的msadsc_t结构到bafhlst_t中
|
|
|
|
|
*rfstat = &mstat[bafhp->af_oderpnr];
|
|
|
|
|
//还剩多少个地址连续的msadsc_t结构
|
|
|
|
|
*rfmnr = tmpmnr;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool_t merlove_continumsadsc_mareabafh(memarea_t *mareap, msadsc_t *mstat, msadsc_t *mend, uint_t mnr)
|
|
|
|
|
{
|
|
|
|
|
uint_t mnridx = mnr;
|
|
|
|
|
msadsc_t *fstat = mstat, *fend = mend;
|
|
|
|
|
//如果mnridx > 0并且NULL != fend就循环调用continumsadsc_mareabafh_core函数,而mnridx和fend由这个函数控制
|
|
|
|
|
for (; (mnridx > 0 && NULL != fend);)
|
|
|
|
|
{
|
|
|
|
|
//为一段地址连续的msadsc_t结构寻找合适m_mdmlielst数组中的bafhlst_t结构
|
|
|
|
|
continumsadsc_mareabafh_core(mareap, &fstat, &fend, &mnridx)
|
|
|
|
|
}
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool_t merlove_scan_continumsadsc(memarea_t *mareap, msadsc_t *fmstat, uint_t *fntmsanr, uint_t fmsanr,
|
|
|
|
|
msadsc_t **retmsastatp, msadsc_t **retmsaendp, uint_t *retfmnr)
|
|
|
|
|
{
|
|
|
|
|
u32_t muindx = 0;
|
|
|
|
|
msadflgs_t *mdfp = NULL;
|
|
|
|
|
|
|
|
|
|
msadsc_t *msastat = fmstat;
|
|
|
|
|
uint_t retfindmnr = 0;
|
|
|
|
|
bool_t rets = FALSE;
|
|
|
|
|
uint_t tmidx = *fntmsanr;
|
|
|
|
|
//从外层函数的fntmnr变量开始遍历所有msadsc_t结构
|
|
|
|
|
for (; tmidx < fmsanr; tmidx++)
|
|
|
|
|
{
|
|
|
|
|
//一个msadsc_t结构是否属于这个内存区,是否空闲
|
|
|
|
|
if (msastat[tmidx].md_indxflgs.mf_marty == mdfp->mf_marty &&
|
|
|
|
|
0 == msastat[tmidx].md_indxflgs.mf_uindx &&
|
|
|
|
|
MF_MOCTY_FREE == msastat[tmidx].md_indxflgs.mf_mocty &&
|
|
|
|
|
PAF_NO_ALLOC == msastat[tmidx].md_phyadrs.paf_alloc)
|
|
|
|
|
{
|
|
|
|
|
//返回从这个msadsc_t结构开始到下一个非空闲、地址非连续的msadsc_t结构对应的msadsc_t结构索引号到retfindmnr变量中
|
|
|
|
|
rets = scan_len_msadsc(&msastat[tmidx], mdfp, fmsanr, &retfindmnr);
|
|
|
|
|
//下一轮开始的msadsc_t结构索引
|
|
|
|
|
*fntmsanr = tmidx + retfindmnr + 1;
|
|
|
|
|
//当前地址连续msadsc_t结构的开始地址
|
|
|
|
|
*retmsastatp = &msastat[tmidx];
|
|
|
|
|
//当前地址连续msadsc_t结构的结束地址
|
|
|
|
|
*retmsaendp = &msastat[tmidx + retfindmnr];
|
|
|
|
|
//当前有多少个地址连续msadsc_t结构
|
|
|
|
|
*retfmnr = retfindmnr + 1;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool_t merlove_mem_onmemarea(memarea_t *mareap, msadsc_t *mstat, uint_t msanr)
|
|
|
|
|
{
|
|
|
|
|
msadsc_t *retstatmsap = NULL, *retendmsap = NULL, *fntmsap = mstat;
|
|
|
|
|
uint_t retfindmnr = 0;
|
|
|
|
|
uint_t fntmnr = 0;
|
|
|
|
|
bool_t retscan = FALSE;
|
|
|
|
|
|
|
|
|
|
for (; fntmnr < msanr;)
|
|
|
|
|
{
|
|
|
|
|
//获取最多且地址连续的msadsc_t结构体的开始、结束地址、一共多少个msadsc_t结构体,下一次循环的fntmnr
|
|
|
|
|
retscan = merlove_scan_continumsadsc(mareap, fntmsap, &fntmnr, msanr, &retstatmsap, &retendmsap, &retfindmnr);
|
|
|
|
|
if (NULL != retstatmsap && NULL != retendmsap)
|
|
|
|
|
{
|
|
|
|
|
//把一组连续的msadsc_t结构体挂载到合适的m_mdmlielst数组中的bafhlst_t结构中
|
|
|
|
|
merlove_continumsadsc_mareabafh(mareap, retstatmsap, retendmsap, retfindmnr)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
为了节约篇幅,我删除了大量检查错误的代码,你可以在我提供的[源代码](https://gitee.com/lmos/cosmos/blob/master/lesson16~18/Cosmos/hal/x86/memarea.c#L694)里自行查看。
|
|
|
|
|
|
|
|
|
|
上述代码中,整体上分为两步。
|
|
|
|
|
|
|
|
|
|
第一步,通过merlove\_scan\_continumsadsc函数,返回最多且地址连续的msadsc\_t结构体的开始、结束地址、一共多少个msadsc\_t结构体,下一轮开始的msadsc\_t结构体的索引号。
|
|
|
|
|
|
|
|
|
|
第二步,根据第一步获取的信息调用merlove\_continumsadsc\_mareabafh函数,把第一步返回那一组连续的msadsc\_t结构体,挂载到合适的m\_mdmlielst数组中的bafhlst\_t结构中。详细的逻辑已经在注释中说明。
|
|
|
|
|
|
|
|
|
|
好,内存页已经按照规定的方式组织起来了,这表示物理内存管理器的初始化工作已经进入尾声。
|
|
|
|
|
|
|
|
|
|
### 初始化汇总
|
|
|
|
|
|
|
|
|
|
别急!先别急着写内存分配相关的代码。到目前为止,我们一起写了这么多的内存初始化相关的代码,但是我们没有调用它们。
|
|
|
|
|
|
|
|
|
|
根据前面内存管理数据结构的关系,很显然,**它们的调用次序很重要,谁先谁后都有严格的规定,这关乎内存管理初始化的成败。**所以,现在我们就在先前的init\_memmgr函数中去调用它们,代码如下所示。
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
void init_memmgr()
|
|
|
|
|
{
|
|
|
|
|
//初始化内存页结构
|
|
|
|
|
init_msadsc();
|
|
|
|
|
//初始化内存区结构
|
|
|
|
|
init_memarea();
|
|
|
|
|
//处理内存占用
|
|
|
|
|
init_search_krloccupymm(&kmachbsp);
|
|
|
|
|
//合并内存页到内存区中
|
|
|
|
|
init_merlove_mem();
|
|
|
|
|
init_memmgrob();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
上述代码中,init\_msadsc、init\_memarea函数是可以交换次序的,它们俩互不影响,但它们俩必须最先开始调用,而后面的函数要依赖它们生成的数据结构。
|
|
|
|
|
|
|
|
|
|
但是init\_search\_krloccupymm函数必须要在init\_merlove\_mem函数之前被调用,因为init\_merlove\_mem函数在合并页面时,必须先知道哪些页面被占用了。
|
|
|
|
|
|
|
|
|
|
等一等,init\_memmgrob是什么函数,这个我们还没写呢。下面我们就来现实它。
|
|
|
|
|
|
|
|
|
|
不知道你发现没有,我们的phymmarge\_t结构体的地址和数量、msadsc\_t结构体的地址和数据、memarea\_t结构体的地址和数量都保存在了kmachbsp变量中,这个变量其实不是用来管理内存的,而且它里面放的是**物理地址**。
|
|
|
|
|
|
|
|
|
|
但内核使用的是虚拟地址,每次都要转换极不方便,所以我们要设计一个专用的数据结构,用于内存管理。我们来定义一下这个结构,代码如下。
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
//cosmos/include/halinc/halglobal.c
|
|
|
|
|
HAL_DEFGLOB_VARIABLE(memmgrob_t,memmgrob);
|
|
|
|
|
|
|
|
|
|
typedef struct s_MEMMGROB
|
|
|
|
|
{
|
|
|
|
|
list_h_t mo_list;
|
|
|
|
|
spinlock_t mo_lock; //保护自身自旋锁
|
|
|
|
|
uint_t mo_stus; //状态
|
|
|
|
|
uint_t mo_flgs; //标志
|
|
|
|
|
u64_t mo_memsz; //内存大小
|
|
|
|
|
u64_t mo_maxpages; //内存最大页面数
|
|
|
|
|
u64_t mo_freepages; //内存最大空闲页面数
|
|
|
|
|
u64_t mo_alocpages; //内存最大分配页面数
|
|
|
|
|
u64_t mo_resvpages; //内存保留页面数
|
|
|
|
|
u64_t mo_horizline; //内存分配水位线
|
|
|
|
|
phymmarge_t* mo_pmagestat; //内存空间布局结构指针
|
|
|
|
|
u64_t mo_pmagenr;
|
|
|
|
|
msadsc_t* mo_msadscstat; //内存页面结构指针
|
|
|
|
|
u64_t mo_msanr;
|
|
|
|
|
memarea_t* mo_mareastat; //内存区结构指针
|
|
|
|
|
u64_t mo_mareanr;
|
|
|
|
|
}memmgrob_t;
|
|
|
|
|
|
|
|
|
|
//cosmos/hal/x86/memmgrinit.c
|
|
|
|
|
|
|
|
|
|
void memmgrob_t_init(memmgrob_t *initp)
|
|
|
|
|
{
|
|
|
|
|
list_init(&initp->mo_list);
|
|
|
|
|
knl_spinlock_init(&initp->mo_lock);
|
|
|
|
|
initp->mo_stus = 0;
|
|
|
|
|
initp->mo_flgs = 0;
|
|
|
|
|
initp->mo_memsz = 0;
|
|
|
|
|
initp->mo_maxpages = 0;
|
|
|
|
|
initp->mo_freepages = 0;
|
|
|
|
|
initp->mo_alocpages = 0;
|
|
|
|
|
initp->mo_resvpages = 0;
|
|
|
|
|
initp->mo_horizline = 0;
|
|
|
|
|
initp->mo_pmagestat = NULL;
|
|
|
|
|
initp->mo_pmagenr = 0;
|
|
|
|
|
initp->mo_msadscstat = NULL;
|
|
|
|
|
initp->mo_msanr = 0;
|
|
|
|
|
initp->mo_mareastat = NULL;
|
|
|
|
|
initp->mo_mareanr = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void init_memmgrob()
|
|
|
|
|
{
|
|
|
|
|
machbstart_t *mbsp = &kmachbsp;
|
|
|
|
|
memmgrob_t *mobp = &memmgrob;
|
|
|
|
|
memmgrob_t_init(mobp);
|
|
|
|
|
mobp->mo_pmagestat = (phymmarge_t *)phyadr_to_viradr((adr_t)mbsp->mb_e820expadr);
|
|
|
|
|
mobp->mo_pmagenr = mbsp->mb_e820exnr;
|
|
|
|
|
mobp->mo_msadscstat = (msadsc_t *)phyadr_to_viradr((adr_t)mbsp->mb_memmappadr);
|
|
|
|
|
mobp->mo_msanr = mbsp->mb_memmapnr;
|
|
|
|
|
mobp->mo_mareastat = (memarea_t *)phyadr_to_viradr((adr_t)mbsp->mb_memznpadr);
|
|
|
|
|
mobp->mo_mareanr = mbsp->mb_memznnr;
|
|
|
|
|
mobp->mo_memsz = mbsp->mb_memmapnr << PSHRSIZE;
|
|
|
|
|
mobp->mo_maxpages = mbsp->mb_memmapnr;
|
|
|
|
|
uint_t aidx = 0;
|
|
|
|
|
for (uint_t i = 0; i < mobp->mo_msanr; i++)
|
|
|
|
|
{
|
|
|
|
|
if (1 == mobp->mo_msadscstat[i].md_indxflgs.mf_uindx &&
|
|
|
|
|
MF_MOCTY_KRNL == mobp->mo_msadscstat[i].md_indxflgs.mf_mocty &&
|
|
|
|
|
PAF_ALLOC == mobp->mo_msadscstat[i].md_phyadrs.paf_alloc)
|
|
|
|
|
{
|
|
|
|
|
aidx++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
mobp->mo_alocpages = aidx;
|
|
|
|
|
mobp->mo_freepages = mobp->mo_maxpages - mobp->mo_alocpages;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
这些代码非常容易理解,我们就不再讨论了,无非是将内存管理核心数据结构的地址和数量放在其中,并计算了一些统计信息,这没有任何难度,相信你会轻松理解。
|
|
|
|
|
|
|
|
|
|
## 重点回顾
|
|
|
|
|
|
|
|
|
|
今天课程的重点工作是初始化我们设计的内存管理数据结构,在内存中建立它们的实例变量,我来为你梳理一下重点。
|
|
|
|
|
|
|
|
|
|
首先,我们从初始化msadsc\_t结构开始,在内存中建立msadsc\_t结构的实例变量,每个物理内存页面一个msadsc\_t结构的实例变量。
|
|
|
|
|
|
|
|
|
|
然后是初始化memarea\_t结构,在msadsc\_t结构的实例变量之后,每个内存区一个memarea\_t结构实例变量。
|
|
|
|
|
|
|
|
|
|
接着标记哪些msadsc\_t结构对应的物理内存被内核占用了,这些被标记msadsc\_t结构是不能纳入内存管理结构中去的。
|
|
|
|
|
|
|
|
|
|
最后,把所有的空闲msadsc\_t结构按最大地址连续的形式组织起来,挂载到memarea\_t结构下的memdivmer\_t结构中,对应的dm\_mdmlielst数组中。
|
|
|
|
|
|
|
|
|
|
不知道你是否想过,随着物理内存不断增加,msadsc\_t结构实例变量本身占用的内存空间就会增加,那你有办法降低msadsc\_t结构实例变量占用的内存空间吗?期待你的实现。
|
|
|
|
|
|
|
|
|
|
## 思考题
|
|
|
|
|
|
|
|
|
|
请问在4GB的物理内存的情况下,msadsc\_t结构实例变量本身占用多大的内存空间?
|
|
|
|
|
|
|
|
|
|
欢迎你在留言区跟我交流互动,也希望你能把这节课分享给你的同事、朋友。
|
|
|
|
|
|
|
|
|
|
好,我是LMOS,我们下节课见!
|
|
|
|
|
|