mm.c

来自「xen虚拟机源代码安装包」· C语言 代码 · 共 618 行 · 第 1/2 页

C
618
字号
/*  **************************************************************************** * (C) 2003 - Rolf Neugebauer - Intel Research Cambridge * (C) 2005 - Grzegorz Milos - Intel Research Cambridge **************************************************************************** * *        File: mm.c *      Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk) *     Changes: Grzegorz Milos *               *        Date: Aug 2003, chages Aug 2005 *  * Environment: Xen Minimal OS * Description: memory management related functions *              contains buddy page allocator from Xen. * **************************************************************************** * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: *  * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. *  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER  * DEALINGS IN THE SOFTWARE. */#include <os.h>#include <hypervisor.h>#include <mm.h>#include <types.h>#include <lib.h>#include <xmalloc.h>#include <xen/memory.h>#ifdef MM_DEBUG#define DEBUG(_f, _a...) \    printk("MINI_OS(file=mm.c, line=%d) " _f "\n", __LINE__, ## _a)#else#define DEBUG(_f, _a...)    ((void)0)#endifunsigned long *phys_to_machine_mapping;unsigned long mfn_zero;extern char stack[];extern void page_walk(unsigned long virt_addr);void new_pt_frame(unsigned long *pt_pfn, unsigned long prev_l_mfn,                                 unsigned long offset, unsigned long level){       pgentry_t *tab = (pgentry_t *)start_info.pt_base;    unsigned long pt_page = (unsigned long)pfn_to_virt(*pt_pfn);     pgentry_t prot_e, prot_t;    mmu_update_t mmu_updates[1];        prot_e = prot_t = 0;    DEBUG("Allocating new L%d pt frame for pt_pfn=%lx, "           "prev_l_mfn=%lx, offset=%lx",            level, *pt_pfn, prev_l_mfn, offset);    /* We need to clear the page, otherwise we might fail to map it       as a page table page */    memset((void*) pt_page, 0, PAGE_SIZE);       switch ( level )    {    case L1_FRAME:         prot_e = L1_PROT;         prot_t = L2_PROT;         break;    case L2_FRAME:         prot_e = L2_PROT;         prot_t = L3_PROT;         break;#if defined(__x86_64__)    case L3_FRAME:         prot_e = L3_PROT;         prot_t = L4_PROT;         break;#endif    default:         printk("new_pt_frame() called with invalid level number %d\n", level);         do_exit();         break;    }    /* Update the entry */#if defined(__x86_64__)    tab = pte_to_virt(tab[l4_table_offset(pt_page)]);#endif    tab = pte_to_virt(tab[l3_table_offset(pt_page)]);    mmu_updates[0].ptr = (tab[l2_table_offset(pt_page)] & PAGE_MASK) +                          sizeof(pgentry_t) * l1_table_offset(pt_page);    mmu_updates[0].val = (pgentry_t)pfn_to_mfn(*pt_pfn) << PAGE_SHIFT |                          (prot_e & ~_PAGE_RW);    if(HYPERVISOR_mmu_update(mmu_updates, 1, NULL, DOMID_SELF) < 0)    {         printk("PTE for new page table page could not be updated\n");         do_exit();    }                            /* Now fill the new page table page with entries.       Update the page directory as well. */    mmu_updates[0].ptr = ((pgentry_t)prev_l_mfn << PAGE_SHIFT) + sizeof(pgentry_t) * offset;    mmu_updates[0].val = (pgentry_t)pfn_to_mfn(*pt_pfn) << PAGE_SHIFT | prot_t;    if(HYPERVISOR_mmu_update(mmu_updates, 1, NULL, DOMID_SELF) < 0)     {       printk("ERROR: mmu_update failed\n");       do_exit();    }    *pt_pfn += 1;}/* Checks if a pagetable frame is needed (if weren't allocated by Xen) */static int need_pt_frame(unsigned long virt_address, int level){    unsigned long hyp_virt_start = HYPERVISOR_VIRT_START;#if defined(__x86_64__)    unsigned long hyp_virt_end = HYPERVISOR_VIRT_END;#else    unsigned long hyp_virt_end = 0xffffffff;#endif    /* In general frames will _not_ be needed if they were already       allocated to map the hypervisor into our VA space */#if defined(__x86_64__)    if(level == L3_FRAME)    {        if(l4_table_offset(virt_address) >=            l4_table_offset(hyp_virt_start) &&           l4_table_offset(virt_address) <=            l4_table_offset(hyp_virt_end))            return 0;        return 1;    } else#endif    if(level == L2_FRAME)    {#if defined(__x86_64__)        if(l4_table_offset(virt_address) >=            l4_table_offset(hyp_virt_start) &&           l4_table_offset(virt_address) <=            l4_table_offset(hyp_virt_end))#endif            if(l3_table_offset(virt_address) >=                l3_table_offset(hyp_virt_start) &&               l3_table_offset(virt_address) <=                l3_table_offset(hyp_virt_end))                return 0;        return 1;    } else     /* Always need l1 frames */    if(level == L1_FRAME)        return 1;    printk("ERROR: Unknown frame level %d, hypervisor %llx,%llx\n",         level, hyp_virt_start, hyp_virt_end);    return -1;}void build_pagetable(unsigned long *start_pfn, unsigned long *max_pfn){    unsigned long start_address, end_address;    unsigned long pfn_to_map, pt_pfn = *start_pfn;    static mmu_update_t mmu_updates[L1_PAGETABLE_ENTRIES + 1];    pgentry_t *tab = (pgentry_t *)start_info.pt_base, page;    unsigned long mfn = pfn_to_mfn(virt_to_pfn(start_info.pt_base));    unsigned long offset;    int count = 0;    pfn_to_map = (start_info.nr_pt_frames - NOT_L1_FRAMES) * L1_PAGETABLE_ENTRIES;    if (*max_pfn >= virt_to_pfn(HYPERVISOR_VIRT_START))    {        printk("WARNING: Mini-OS trying to use Xen virtual space. "               "Truncating memory from %dMB to ",               ((unsigned long)pfn_to_virt(*max_pfn) - (unsigned long)&_text)>>20);        *max_pfn = virt_to_pfn(HYPERVISOR_VIRT_START - PAGE_SIZE);        printk("%dMB\n",               ((unsigned long)pfn_to_virt(*max_pfn) - (unsigned long)&_text)>>20);    }    start_address = (unsigned long)pfn_to_virt(pfn_to_map);    end_address = (unsigned long)pfn_to_virt(*max_pfn);    /* We worked out the virtual memory range to map, now mapping loop */    printk("Mapping memory range 0x%lx - 0x%lx\n", start_address, end_address);    while(start_address < end_address)    {        tab = (pgentry_t *)start_info.pt_base;        mfn = pfn_to_mfn(virt_to_pfn(start_info.pt_base));#if defined(__x86_64__)        offset = l4_table_offset(start_address);        /* Need new L3 pt frame */        if(!(start_address & L3_MASK))             if(need_pt_frame(start_address, L3_FRAME))                 new_pt_frame(&pt_pfn, mfn, offset, L3_FRAME);        page = tab[offset];        mfn = pte_to_mfn(page);        tab = to_virt(mfn_to_pfn(mfn) << PAGE_SHIFT);#endif        offset = l3_table_offset(start_address);        /* Need new L2 pt frame */        if(!(start_address & L2_MASK))            if(need_pt_frame(start_address, L2_FRAME))                new_pt_frame(&pt_pfn, mfn, offset, L2_FRAME);        page = tab[offset];        mfn = pte_to_mfn(page);        tab = to_virt(mfn_to_pfn(mfn) << PAGE_SHIFT);        offset = l2_table_offset(start_address);                /* Need new L1 pt frame */        if(!(start_address & L1_MASK))            if(need_pt_frame(start_address, L1_FRAME))                 new_pt_frame(&pt_pfn, mfn, offset, L1_FRAME);        page = tab[offset];        mfn = pte_to_mfn(page);        offset = l1_table_offset(start_address);        mmu_updates[count].ptr = ((pgentry_t)mfn << PAGE_SHIFT) + sizeof(pgentry_t) * offset;        mmu_updates[count].val = (pgentry_t)pfn_to_mfn(pfn_to_map++) << PAGE_SHIFT | L1_PROT;        count++;        if (count == L1_PAGETABLE_ENTRIES || pfn_to_map == *max_pfn)        {            if(HYPERVISOR_mmu_update(mmu_updates, count, NULL, DOMID_SELF) < 0)            {                printk("PTE could not be updated\n");                do_exit();            }            count = 0;        }        start_address += PAGE_SIZE;    }    *start_pfn = pt_pfn;}extern void shared_info;static void set_readonly(void *text, void *etext){    unsigned long start_address = ((unsigned long) text + PAGE_SIZE - 1) & PAGE_MASK;    unsigned long end_address = (unsigned long) etext;    static mmu_update_t mmu_updates[L1_PAGETABLE_ENTRIES + 1];    pgentry_t *tab = (pgentry_t *)start_info.pt_base, page;    unsigned long mfn = pfn_to_mfn(virt_to_pfn(start_info.pt_base));    unsigned long offset;    int count = 0;    printk("setting %p-%p readonly\n", text, etext);    while (start_address + PAGE_SIZE <= end_address) {        tab = (pgentry_t *)start_info.pt_base;        mfn = pfn_to_mfn(virt_to_pfn(start_info.pt_base));#if defined(__x86_64__)        offset = l4_table_offset(start_address);        page = tab[offset];        mfn = pte_to_mfn(page);        tab = to_virt(mfn_to_pfn(mfn) << PAGE_SHIFT);#endif        offset = l3_table_offset(start_address);        page = tab[offset];        mfn = pte_to_mfn(page);        tab = to_virt(mfn_to_pfn(mfn) << PAGE_SHIFT);        offset = l2_table_offset(start_address);                page = tab[offset];        mfn = pte_to_mfn(page);        tab = to_virt(mfn_to_pfn(mfn) << PAGE_SHIFT);        offset = l1_table_offset(start_address);	if (start_address != (unsigned long)&shared_info) {	    mmu_updates[count].ptr = ((pgentry_t)mfn << PAGE_SHIFT) + sizeof(pgentry_t) * offset;	    mmu_updates[count].val = tab[offset] & ~_PAGE_RW;	    count++;	} else	    printk("skipped %p\n", start_address);        start_address += PAGE_SIZE;        if (count == L1_PAGETABLE_ENTRIES || start_address + PAGE_SIZE > end_address)        {            if(HYPERVISOR_mmu_update(mmu_updates, count, NULL, DOMID_SELF) < 0)            {                printk("PTE could not be updated\n");                do_exit();            }            count = 0;        }    }

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?