真象还原第八章

用bitmap来进行资源的管理,bitmap的一位可以对应我们想要让它管理的资源的一个单位。这里,我们用bitmap管理内存资源,包括虚拟内存和物理内存,单位为一页。
bitmap

struct bitmap {
    uint_32 map_size;
    uint_8* bits;
};

定义物理内存池,除了需要bitmap来管理外,还需要规定你所能管理的最大范围(起始的地方以及池子的大小)。
虚拟内存大小足足有4GB之多,对于我们来说几乎是无限的。结构体中就没有pool_size这个成员。

struct pool {
    struct bitmap btmp;
    uint_32 paddr_start;
    uint_32 pool_size;
};
struct virt_addr {
    struct bitmap btmp;
    uint_32 vaddr_start;
};

struct pool kernel_pool,user_pool;
struct virt_addr ker_vaddr;

物理内存:减去已经最初1MB,以及使用过的页目录表和页表所占大小。剩下的部分便是可用的物理内存了。
虚拟内存:因为这里管理的是内核的虚拟地址,所以从已经用过的 0~0xc0100000 往上。

void mem_pool_init(uint_32 total_mem)
{
    put_str("  mem pool init start\n");
    uint_32 used_mem = 0x100000 + PAGE_SIZE*256;
    uint_32 free_mem = total_mem - used_mem;

    uint_32 all_free_pages = free_mem / PAGE_SIZE;
    uint_32 ker_free_pages  = all_free_pages / 2;
    uint_32 usr_free_pages  = all_free_pages - ker_free_pages;

    //初始化 kernel_pool 
    uint_32 kbm_len = ker_free_pages / 8; //管理的区域小于实际区域
    kernel_pool.btmp.bits = (uint_8*)BTMP_START;
    kernel_pool.btmp.map_size = kbm_len;
    kernel_pool.paddr_start = used_mem;
    kernel_pool.pool_size = ker_free_pages * PAGE_SIZE;

    //初始化 user_pool
    uint_32 ubm_len = usr_free_pages / 8;
    user_pool.btmp.bits = (uint_8*)(BTMP_START + kbm_len);
    user_pool.btmp.map_size = ubm_len;
    user_pool.paddr_start = used_mem + ker_free_pages*PAGE_SIZE;
    user_pool.pool_size = usr_free_pages * PAGE_SIZE;

    bit_init(&kernel_pool.btmp);
    bit_init(&user_pool.btmp);

    //初始化虚拟内存
    ker_vaddr.btmp.bits = (uint_8*)(BTMP_START + kbm_len + ubm_len);
    ker_vaddr.btmp.map_size = ker_free_pages / 8;
    ker_vaddr.vaddr_start = K_HEAP_START;

    put_str("  mem pool init done\n");
}

申请资源就是将对应bitmap中的bit给置1。

void bitmap_set(struct bitmap* btmp,uint_32 bit_idx,uint_8 value)
{
    ASSERT(value==0 || value==1);
    uint_32 bit_byte = bit_idx / 8;
    uint_32 bit_odd  = bit_idx % 8;
    if (value) {
        btmp->bits[bit_byte] |= (BIT_MASK << bit_odd);
    } else {
        btmp->bits[bit_byte] &= ~(BIT_MASK << bit_odd);
    }
}

申请虚拟内存因为是连续的,所以可以一次申请一大块,然后返回所申请的连续虚拟页的起始地址以供后续使用。

static void* get_vaddr(enum pool_flag pf,uint_32 pcnt)
{
    uint_32 vaddr_get;
    if (pf == PF_KERNEL)
    {
        uint_32 bit_start = bit_scan(&ker_vaddr.btmp,pcnt);
        if (bit_start == -1){
            return NULL;
        }

        uint_32 cnt = 0;
        while (cnt < pcnt){
            bitmap_set(&ker_vaddr.btmp,cnt++,1);
        }
        vaddr_get = ker_vaddr.vaddr_start + bit_start*PAGE_SIZE;
    }
    else
    {
        //用户内存池,以后再实现
    }
    return (void*)vaddr_get;
}

物理地址随着申请虚拟地址时被动分配,每次申请一个页。不一定连续。

void* malloc_page(enum pool_flag pf,uint_32 pcnt)
{
    ASSERT(pcnt>0 && pcnt<64000); //按照用户和内核各250MB来计算
    uint_32 cnt = pcnt;
    struct pool* m_pool = pf==PF_KERNEL? &kernel_pool : &user_pool;
    void* vaddr_start = get_vaddr(pf,pcnt);
    if (vaddr_start == NULL){
        return NULL;
    }

    void* vaddr = vaddr_start;
    while (cnt--)
    {
        void* paddr = palloc(m_pool);
        if (paddr == NULL) {
            return NULL;
        }
        page_table_add(vaddr,paddr);
        vaddr =(void*)((uint_32)vaddr + PAGE_SIZE);
    }

    return vaddr_start;
}

static void* palloc(struct pool* m_pool)
{
    uint_32 bit_off = bit_scan(&m_pool->btmp,1);
    if (bit_off == -1){
        return NULL;
    }
    bitmap_set(&m_pool->btmp,bit_off,1);

    return (void*)(m_pool->paddr_start + bit_off*PAGE_SIZE);
}

我们现在已经进入了分页模式中,要访问某块物理内存必须通过相应的虚拟内存来进行。
取得pte的虚拟地址。从后往前推导,最后12位是在页表中的偏移地址,中间10位是页表在页目录表里的偏移地址。这就够了,所以高10位全填1,页目录表的最后一项指向它自己,因此这会访问到页目录表自身。
取pde的虚拟地址也是如此,最后12位是在页目录表中的偏移量,前面回环就完事了。

uint_32* pte_ptr(uint_32 vaddr)
{
    uint_32 v = (0xffc00000 + (PDE_IDX(vaddr)<<12) + (PTE_IDX(vaddr)<<2));
    return (uint_32*)v;
}

uint_32* pde_ptr(uint_32 vaddr)
{
    uint_32* v = (uint_32*)(0xfffff000 + (PDE_IDX(vaddr)<<2));
    return v;
}

添加虚拟地址与物理地址的映射,主要就是往pte写东西。如果连pde都没有需要把pde及其所指向的页表给补上。
新申请到的页大多数情况下不能直接拿来用,因为有可能是脏的。别忘记事前得先memset清零一下~

static void page_table_add(void* _vaddr,void* _paddr)
{
    uint_32 vaddr=(uint_32)_vaddr,paddr=(uint_32)_paddr;
    uint_32* pde = pde_ptr(vaddr),*pte = pte_ptr(vaddr);

    if ((*pde & PG_P) == 1)
    {
        ASSERT((*pte & PG_P)==0);
        *pte = paddr | PG_P | PG_RW_RW | PG_US_U;
    }
    else
    {
        void* new_phy_page = palloc(&kernel_pool);
        *pde = (uint_32)new_phy_page | PG_P | PG_RW_RW | PG_US_U;
        memset((void*)((uint_32)pte & 0xfffff000),0,PAGE_SIZE);

        ASSERT((*pte & PG_P)==0);
        *pte = paddr | PG_P | PG_RW_RW | PG_US_U;
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,284评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,115评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,614评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,671评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,699评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,562评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,309评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,223评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,668评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,859评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,981评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,705评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,310评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,904评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,023评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,146评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,933评论 2 355

推荐阅读更多精彩内容