美文网首页
FreeNOS源代码-Kernel模块-Memory类的阅读

FreeNOS源代码-Kernel模块-Memory类的阅读

作者: 小胖妞爱吃肉 | 来源:发表于2017-07-24 14:31 被阅读0次
    FreeNos Memory类的继承关系表(x86Memory继承自Memory)

    1.成员变量

    Memory类的成员变量memoryAvail和memoryMapEnd的访问权限是protected的,成员变量memoryAvail和memoryMapEnd是全局变量;
    分别表示的是:
    memorySize 所有的可用的物理内存;
    memoryAvail 可用的物理内存;
    memoryMap 映射所有可用的物理内存;

    2.构造方法和析构方法

    Memory::Memory()
    {
        /* 标记Kernel使用的内存地址 */
        allocatePhysical(0x00400000, 0);
        
        /* 标记boot模块使用的内存地址 */
        for (Size i = 0; i < multibootInfo.modsCount; i++)
        {
            MultibootModule *mod  = &((MultibootModule *) multibootInfo.modsAddress)[i];
            Size modSize = mod->modEnd - mod->modStart;
    
            /* 标记使用的物理内存地址*/
            allocatePhysical(modSize, mod->modStart);
        }
    }
    

    Memory还提供了一个初始化memoryMap和kernel heap的方法:initialize()

    void Memory::initialize()
    {
        Address page = 0x00300000;
        Size meta = sizeof(BubbleAllocator) + sizeof(PoolAllocator);
        Allocator *bubble, *pool;
    
        /* 保存内存大小到MemoryAvail变量中*/
        memorySize  = (multibootInfo.memLower + multibootInfo.memUpper) * 1024;
        memoryAvail = memorySize;
        
        /* 分配memoryMap */
        memoryMap    = (u8 *)(&kernelEnd);
        memoryMapEnd = memoryMap + (memorySize / PAGESIZE / 8);
    
        /* 清空memoryMap*/
        for (u8 *p = memoryMap; p < memoryMapEnd; p++)
        {
        *p = 0;
        }
        /* 设置动态内存堆*/
        bubble = new (page) BubbleAllocator();
        pool   = new (page + sizeof(BubbleAllocator)) PoolAllocator();
        pool->setParent(bubble);
        
        /* 设置堆的大小*/
        bubble->region(page + meta, (1024 * 1024) - meta);
    
        /* 设置默认分配器*/
        Allocator::setDefault(pool);
    }
    

    析构函数: ~Memory 是虚函数,可在其他地方实现;

    3.其他对象方法

        Size getTotalMemory()
        {
                /*对memorySize的引用*/
            return memorySize;
        }
        
        Size getAvailableMemory()
        {
                /*对memoryAvail的引用*/
            return memoryAvail;
        }
    

    从源代码可知Memory类主要是对物理内存的分配和内存映射的操作:

          /*分配物理和标记使用的内存到memoryMap中*/
        Address allocatePhysical(Size sz, Address addr = 4194304);
          /*取消参数在memoryMap中的标记*/
        void releasePhysical(Address paddr);
            Address allocateVirtual(Address vaddr, ulong prot);
            Address allocateVirtual(ArchProcess *p, Address vaddr, ulong prot);
          /*将物理内存映射到进程的虚拟地址空间中*/
        virtual Address mapVirtual(Address paddr, Address vaddr, ulong prot) = 0;
          /*将物理内存映射到进程的虚拟地址空间中*/
        virtual Address mapVirtual(ArchProcess *p, Address paddr, Address vaddr, ulong prot) = 0;
          /*把参数进程中的所有的物理页标记为释放*/
        virtual void releaseAll(ArchProcess *p) = 0;
    

    在以上方法实现之前,先看一下对内存映射的操作:

    bool Memory::isMarked(Address addr)
    {
        Size index = (addr >> PAGESHIFT) / 8;
        Size bit   = (addr >> PAGESHIFT) % 8;
        
        return memoryMap[index] & (1 << bit);
    }
    
    void Memory::setMark(Address addr, bool marked)
    {
        Size index = (addr >> PAGESHIFT) / 8;
        Size bit   = (addr >> PAGESHIFT) % 8;
    
        if (marked)
        memoryMap[index] |=  (1 << bit);
        else
        memoryMap[index] &= ~(1 << bit);
    }
    
    

    接下来的是上面方法的详细实现:

    Address Memory::allocatePhysical(Size sz, Address paddr)
    {
        Address start = paddr & PAGEMASK, end = memorySize;
        Address from  = 0, count = 0;
    
        /* Loop the memoryMap for a free block. */
        for (Address i = start; i < end; i += PAGESIZE)
        {
        if (!isMarked(i))
        {
            /* Remember this page. */
            if (!count)
            {
            from  = i;
            count = 1;
            }
            else
            count++;
    
            /* Are there enough contigious pages? */
            if (count * PAGESIZE >= sz)
            {
            for (Address j = from; j < from + (count * PAGESIZE); j += PAGESIZE)
            {
                setMark(j, true);
            }
            memoryAvail -= count * PAGESIZE;
            return from;
            }
        }
        else
        {
            from = count = 0;
        }
        }
        /* Out of memory! */
        return (Address) ZERO;
    }
    
    void Memory::releasePhysical(Address addr)
    {
        setMark(addr & PAGEMASK, false);
        memoryAvail += PAGESIZE;
    }
    
    Address Memory::allocateVirtual(Address vaddr, ulong prot)
    {
        Address newPage = allocatePhysical(PAGESIZE);
        return mapVirtual(newPage, vaddr, prot);
    }
    
    Address Memory::allocateVirtual(ArchProcess *p, Address vaddr, ulong prot)
    {
        Address newPage = allocatePhysical(PAGESIZE);
        return mapVirtual(p, newPage, vaddr, prot);
    }
    

    virtual Address mapVirtual(Address paddr, Address vaddr, ulong prot) = 0
    virtual Address mapVirtual(ArchProcess *p, Address paddr, Address vaddr, ulong prot) = 0
    这两个方法可以在/x86/x86Memory类中找到实现。

    Address X86Memory::mapVirtual(Address paddr, Address vaddr, ulong prot)
    {
        /* Virtual address specified? */
        if (vaddr == ZERO)
        {
        vaddr = findFree(PAGETABFROM, PAGEDIRADDR);
        }
        /* Point to the correct page table. */
        myPageTab = PAGETABADDR(vaddr);
        
        /* Do we have the page table in memory? */
        if (!(myPageDir[DIRENTRY(vaddr)] & PAGE_PRESENT))
        {
        /* Then first allocate new page table. */
            Address newPageTab  = memory->allocatePhysical(PAGESIZE);
        newPageTab |= PAGE_PRESENT | PAGE_RW | prot;
    
        /* Map the new page table into memory. */
        myPageDir[DIRENTRY(vaddr)] = newPageTab;
        tlb_flush(myPageTab);
    
        /* Zero the new page table. */
        memset(myPageTab, 0, PAGESIZE);
        }
        /* Map physical to virtual address. */
        myPageTab[TABENTRY(vaddr)] = (paddr & PAGEMASK) | prot;
        tlb_flush(vaddr);
    
        /* Success. */
        return vaddr;
    }
    
    Address X86Memory::mapVirtual(X86Process *p, Address paddr,
                      Address vaddr, ulong prot)
    {
        /* Map remote pages. */
        mapRemote(p, vaddr);
    
        /* Virtual address specified? */
        if (vaddr == ZERO)
        {
        vaddr = findFree(PAGETABFROM_REMOTE, remPageDir);
        }
        /* Repoint to the correct (remote) page table. */
        remPageTab = PAGETABADDR_FROM(vaddr, PAGETABFROM_REMOTE);
        
        /* Does the remote process have the page table in memory? */
        if (!(remPageDir[DIRENTRY(vaddr)] & PAGE_PRESENT))
        {
        /* Nope, allocate a page table first. */
        Address newPageTab  = memory->allocatePhysical(PAGESIZE);
        newPageTab |= PAGE_PRESENT | PAGE_RW | prot;
        
        /* Map the new page table into remote memory. */
        remPageDir[DIRENTRY(vaddr)] = newPageTab;
        
        /* Update caches. */
        tlb_flush(remPageTab);
        
        /* Zero the new page. */
        memset(remPageTab, 0, PAGESIZE);
        }
        /* Map physical address to remote virtual address. */
        remPageTab[TABENTRY(vaddr)] = (paddr & PAGEMASK) | prot;
        tlb_flush(vaddr);
    
        /* Success. */
        return (Address) vaddr;
    }
    Address X86Memory::lookupVirtual(X86Process *p, Address vaddr)
    {
        Address ret = ZERO;
    
        /* Map remote page tables. */
        mapRemote(p, vaddr);
        
        /* Lookup the address, if mapped. */
        if (remPageDir[DIRENTRY(vaddr)] & PAGE_PRESENT &&
            remPageTab[TABENTRY(vaddr)] & PAGE_PRESENT)
        {
        ret = remPageTab[TABENTRY(vaddr)];
        }
        return ret;
    }
    void X86Memory::releaseAll(X86Process *p)
    {
        /* Map page tables. */
        mapRemote(p, 0x0);
    
        /* Mark all our physical pages free. */
        for (Size i = 0; i < 1024; i++)
        {
        /* May we release these physical pages? */
            if ((remPageDir[i] & PAGE_PRESENT) && !(remPageDir[i] & PAGE_PINNED))
            {
            /* Repoint page table. */
                remPageTab = PAGETABADDR_FROM(i * PAGESIZE * 1024,
                          PAGETABFROM_REMOTE);
    
            /* Scan page table. */
                for (Size j = 0; j < 1024; j++)
                {
                    if (remPageTab[j] & PAGE_PRESENT && !(remPageTab[j] & PAGE_PINNED))
                    {
                        memory->releasePhysical(remPageTab[j]);
                    }
                }
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:FreeNOS源代码-Kernel模块-Memory类的阅读

          本文链接:https://www.haomeiwen.com/subject/vaxbkxtx.html