操作系统实践之路——六、内存(2.如何实现内存页面初始化?)


前言
本章节主要讨论如何实现内存页面的初始化?

1.如何实现内存页结构初始化?

​ 内存页结构的初始化,其实就是初始化 msadsc_t 结构对应的变量。因为一个 msadsc_t 结构体变量代表一个物理内存页,而物理内存由多个页组成,所以最终会形成一个 msadsc_t 结构体数组

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

​ 这会让我们的工作变得简单,我们只需要找一个内存地址,作为 msadsc_t 结构体数组的开始地址,当然这个内存地址必须是可用的,而且之后内存空间足以存放 msadsc_t 结构体数组。

​ 然后,我们要扫描 phymmarge_t 结构体数组中的信息,只要它的类型是可用内存,就建立一个 msadsc_t 结构体,并把其中的开始地址作为第一个页面地址。

​ 接着,要给这个开始地址加上 0x1000,如此循环,直到其结束地址。

​ 当这个 phymmarge_t 结构体的地址区间,它对应的所有 msadsc_t 结构体都建立完成之后,就开始下一个 phymmarge_t 结构体。

​ 依次类推,最后,我们就能建好所有可用物理内存页面对应的 msadsc_t 结构体。

2.处理初始化内存占用问题

​ 我们初始化了内存页和内存区对应的数据结构,已经可以组织好内存页面了。现在看似已经万事俱备了,其实这有个重大的问题,你知道是什么吗?我给你分析一下。

​ 目前我们的内存中已经有很多数据了,有 Cosmos 内核本身的执行文件,有字体文件,有 MMU 页表,有打包的内核映像文件,还有刚刚建立的内存页和内存区的数据结构,这些数据都要占用实际的物理内存。

​ 再回头看看我们建立内存页结构 msadsc_t,所有的都是空闲状态,而它们每一个都表示一个实际的物理内存页。

​ 假如在这种情况下,对调用内存分配接口进行内存分配,它按既定的分配算法查找空闲的 msadsc_t 结构,那它一定会找到内核占用的内存页所对应的 msadsc_t 结构,并把这个内存页分配出去,然后得到这个页面的程序对其进行改写。这样内核数据就会被覆盖,这种情况是我们绝对不能允许的。

​ 所以,我们要把这些已经占用的内存页面所对应的 msadsc_t 结构标记出来,标记成已分配,这样内存分配算法就不会找到它们了。

​ 要解决这个问题,我们只要给出被占用内存的起始地址和结束地址,然后从起始地址开始查找对应的 msadsc_t 结构,再把它标记为已经分配,最后直到查找到结束地址为止

//搜索一段内存地址空间所对应的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;
    
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值