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 + -
显示快捷键?