# HG changeset patch # User hahn@xxxxxxxxxxxxxxxx # Date 1161004815 -7200 # Node ID 7614ed2fa89bcd7b10be2488d42c890cca3359c0 # Parent 6ed4368b4a9e1924c983774c4b1a2b6baf8e98a6 I separated the parts special to the x86 architecture and moved it to the new files arch/x86/mm.c and include/x86/arch_mm.h. Signed-off-by: Dietmar Hahn diff -r 6ed4368b4a9e -r 7614ed2fa89b extras/mini-os/include/mm.h --- a/extras/mini-os/include/mm.h Sun Oct 15 09:53:20 2006 +0100 +++ b/extras/mini-os/include/mm.h Mon Oct 16 15:20:15 2006 +0200 @@ -29,182 +29,15 @@ #include #elif defined(__x86_64__) #include +#elif defined(__ia64__) +#include #else #error "Unsupported architecture" #endif #include +#include -#define L1_FRAME 1 -#define L2_FRAME 2 -#define L3_FRAME 3 - -#define L1_PAGETABLE_SHIFT 12 - -#if defined(__i386__) - -#if !defined(CONFIG_X86_PAE) - -#define L2_PAGETABLE_SHIFT 22 - -#define L1_PAGETABLE_ENTRIES 1024 -#define L2_PAGETABLE_ENTRIES 1024 - -#define PADDR_BITS 32 -#define PADDR_MASK (~0UL) - -#define NOT_L1_FRAMES 1 -#define PRIpte "08lx" -typedef unsigned long pgentry_t; - -#else /* defined(CONFIG_X86_PAE) */ - -#define L2_PAGETABLE_SHIFT 21 -#define L3_PAGETABLE_SHIFT 30 - -#define L1_PAGETABLE_ENTRIES 512 -#define L2_PAGETABLE_ENTRIES 512 -#define L3_PAGETABLE_ENTRIES 4 - -#define PADDR_BITS 44 -#define PADDR_MASK ((1ULL << PADDR_BITS)-1) - -#define L2_MASK ((1UL << L3_PAGETABLE_SHIFT) - 1) - -/* - * If starting from virtual address greater than 0xc0000000, - * this value will be 2 to account for final mid-level page - * directory which is always mapped in at this location. - */ -#define NOT_L1_FRAMES 3 -#define PRIpte "016llx" -typedef uint64_t pgentry_t; - -#endif /* !defined(CONFIG_X86_PAE) */ - -#elif defined(__x86_64__) - -#define L2_PAGETABLE_SHIFT 21 -#define L3_PAGETABLE_SHIFT 30 -#define L4_PAGETABLE_SHIFT 39 - -#define L1_PAGETABLE_ENTRIES 512 -#define L2_PAGETABLE_ENTRIES 512 -#define L3_PAGETABLE_ENTRIES 512 -#define L4_PAGETABLE_ENTRIES 512 - -/* These are page-table limitations. Current CPUs support only 40-bit phys. */ -#define PADDR_BITS 52 -#define VADDR_BITS 48 -#define PADDR_MASK ((1UL << PADDR_BITS)-1) -#define VADDR_MASK ((1UL << VADDR_BITS)-1) - -#define L2_MASK ((1UL << L3_PAGETABLE_SHIFT) - 1) -#define L3_MASK ((1UL << L4_PAGETABLE_SHIFT) - 1) - -#define NOT_L1_FRAMES 3 -#define PRIpte "016lx" -typedef unsigned long pgentry_t; - -#endif - -#define L1_MASK ((1UL << L2_PAGETABLE_SHIFT) - 1) - -/* Given a virtual address, get an entry offset into a page table. */ -#define l1_table_offset(_a) \ - (((_a) >> L1_PAGETABLE_SHIFT) & (L1_PAGETABLE_ENTRIES - 1)) -#define l2_table_offset(_a) \ - (((_a) >> L2_PAGETABLE_SHIFT) & (L2_PAGETABLE_ENTRIES - 1)) -#if defined(__x86_64__) || defined(CONFIG_X86_PAE) -#define l3_table_offset(_a) \ - (((_a) >> L3_PAGETABLE_SHIFT) & (L3_PAGETABLE_ENTRIES - 1)) -#endif -#if defined(__x86_64__) -#define l4_table_offset(_a) \ - (((_a) >> L4_PAGETABLE_SHIFT) & (L4_PAGETABLE_ENTRIES - 1)) -#endif - -#define _PAGE_PRESENT 0x001UL -#define _PAGE_RW 0x002UL -#define _PAGE_USER 0x004UL -#define _PAGE_PWT 0x008UL -#define _PAGE_PCD 0x010UL -#define _PAGE_ACCESSED 0x020UL -#define _PAGE_DIRTY 0x040UL -#define _PAGE_PAT 0x080UL -#define _PAGE_PSE 0x080UL -#define _PAGE_GLOBAL 0x100UL - -#if defined(__i386__) -#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED) -#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY |_PAGE_USER) -#if defined(CONFIG_X86_PAE) -#define L3_PROT (_PAGE_PRESENT) -#endif /* CONFIG_X86_PAE */ -#elif defined(__x86_64__) -#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_USER) -#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER) -#define L3_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER) -#define L4_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER) -#endif /* __i386__ || __x86_64__ */ - -#ifndef CONFIG_X86_PAE -#define PAGE_SIZE (1UL << L1_PAGETABLE_SHIFT) -#else -#define PAGE_SIZE (1ULL << L1_PAGETABLE_SHIFT) -#endif -#define PAGE_SHIFT L1_PAGETABLE_SHIFT -#define PAGE_MASK (~(PAGE_SIZE-1)) - -#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> L1_PAGETABLE_SHIFT) -#define PFN_DOWN(x) ((x) >> L1_PAGETABLE_SHIFT) -#define PFN_PHYS(x) ((x) << L1_PAGETABLE_SHIFT) - -/* to align the pointer to the (next) page boundary */ -#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) - -/* Definitions for machine and pseudophysical addresses. */ -#ifdef CONFIG_X86_PAE -typedef unsigned long long paddr_t; -typedef unsigned long long maddr_t; -#else -typedef unsigned long paddr_t; -typedef unsigned long maddr_t; -#endif - -extern unsigned long *phys_to_machine_mapping; -extern char _text, _etext, _edata, _end; -#define pfn_to_mfn(_pfn) (phys_to_machine_mapping[(_pfn)]) -static __inline__ maddr_t phys_to_machine(paddr_t phys) -{ - maddr_t machine = pfn_to_mfn(phys >> PAGE_SHIFT); - machine = (machine << PAGE_SHIFT) | (phys & ~PAGE_MASK); - return machine; -} - -#define mfn_to_pfn(_mfn) (machine_to_phys_mapping[(_mfn)]) -static __inline__ paddr_t machine_to_phys(maddr_t machine) -{ - paddr_t phys = mfn_to_pfn(machine >> PAGE_SHIFT); - phys = (phys << PAGE_SHIFT) | (machine & ~PAGE_MASK); - return phys; -} - -#define VIRT_START ((unsigned long)&_text) - -#define to_phys(x) ((unsigned long)(x)-VIRT_START) -#define to_virt(x) ((void *)((unsigned long)(x)+VIRT_START)) - -#define virt_to_pfn(_virt) (PFN_DOWN(to_phys(_virt))) -#define virt_to_mfn(_virt) (pfn_to_mfn(virt_to_pfn(_virt))) -#define mach_to_virt(_mach) (to_virt(machine_to_phys(_mach))) -#define virt_to_mach(_virt) (phys_to_machine(to_phys(_virt))) -#define mfn_to_virt(_mfn) (to_virt(mfn_to_pfn(_mfn) << PAGE_SHIFT)) -#define pfn_to_virt(_pfn) (to_virt((_pfn) << PAGE_SHIFT)) - -/* Pagetable walking. */ -#define pte_to_mfn(_pte) (((_pte) & (PADDR_MASK&PAGE_MASK)) >> L1_PAGETABLE_SHIFT) -#define pte_to_virt(_pte) to_virt(mfn_to_pfn(pte_to_mfn(_pte)) << PAGE_SHIFT) void init_mm(void); unsigned long alloc_pages(int order); @@ -220,7 +53,10 @@ static __inline__ int get_order(unsigned return order; } +void arch_init_demand_mapping_area(unsigned long max_pfn); +void arch_init_mm(unsigned long* start_pfn_p, unsigned long* max_pfn_p); -void *map_frames(unsigned long *f, unsigned long n); +void* map_frames(unsigned long *f, unsigned long n); + #endif /* _MM_H_ */ diff -r 6ed4368b4a9e -r 7614ed2fa89b extras/mini-os/mm.c --- a/extras/mini-os/mm.c Sun Oct 15 09:53:20 2006 +0100 +++ b/extras/mini-os/mm.c Mon Oct 16 15:20:15 2006 +0200 @@ -48,10 +48,6 @@ #define DEBUG(_f, _a...) ((void)0) #endif -unsigned long *phys_to_machine_mapping; -extern char *stack; -extern void page_walk(unsigned long virt_addr); - /********************* * ALLOCATION BITMAP * One bit per page of memory. Bit set => page is allocated. @@ -226,11 +222,11 @@ static void init_page_allocator(unsigned /* All allocated by default. */ memset(alloc_bitmap, ~0, bitmap_size); /* Free up the memory we've been given to play with. */ - map_free(min>>PAGE_SHIFT, range>>PAGE_SHIFT); + map_free(PHYS_PFN(min), range>>PAGE_SHIFT); /* The buddy lists are addressed in high memory. */ - min += VIRT_START; - max += VIRT_START; + min = (unsigned long) to_virt(min); + max = (unsigned long) to_virt(max); while ( range != 0 ) { @@ -297,7 +293,7 @@ unsigned long alloc_pages(int order) free_head[i] = spare_ch; } - map_alloc(to_phys(alloc_ch)>>PAGE_SHIFT, 1<= - l4_table_offset(hyp_virt_start) && - l4_table_offset(virt_address) <= - l4_table_offset(hyp_virt_end)) - return 0; - return 1; - } else -#endif - -#if defined(__x86_64__) || defined(CONFIG_X86_PAE) - 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 -#endif /* defined(__x86_64__) || defined(CONFIG_X86_PAE) */ - - /* 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 -#if defined(__x86_64__) || defined(CONFIG_X86_PAE) - 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); -#endif - 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; -} - - -void mem_test(unsigned long *start_add, unsigned long *end_add) -{ - unsigned long mask = 0x10000; - unsigned long *pointer; - - for(pointer = start_add; pointer < end_add; pointer++) - { - if(!(((unsigned long)pointer) & 0xfffff)) - { - printk("Writing to %lx\n", pointer); - page_walk((unsigned long)pointer); - } - *pointer = (unsigned long)pointer & ~mask; - } - - for(pointer = start_add; pointer < end_add; pointer++) - { - if(((unsigned long)pointer & ~mask) != *pointer) - printk("Read error at 0x%lx. Read: 0x%lx, should read 0x%lx\n", - (unsigned long)pointer, - *pointer, - ((unsigned long)pointer & ~mask)); - } - -} - -static pgentry_t *demand_map_pgt; -static void *demand_map_area_start; - -static void init_demand_mapping_area(unsigned long max_pfn) -{ - unsigned long mfn; - pgentry_t *tab; - unsigned long start_addr; - unsigned long pt_pfn; - unsigned offset; - - /* Round up to four megs. + 1024 rather than + 1023 since we want - to be sure we don't end up in the same place we started. */ - max_pfn = (max_pfn + L1_PAGETABLE_ENTRIES) & ~(L1_PAGETABLE_ENTRIES - 1); - if (max_pfn == 0 || - (unsigned long)pfn_to_virt(max_pfn + L1_PAGETABLE_ENTRIES) >= - HYPERVISOR_VIRT_START) { - printk("Too much memory; no room for demand map hole.\n"); - do_exit(); - } - - demand_map_area_start = pfn_to_virt(max_pfn); - printk("Demand map pfns start at %lx (%p).\n", max_pfn, - demand_map_area_start); - start_addr = (unsigned long)demand_map_area_start; - - tab = (pgentry_t *)start_info.pt_base; - mfn = virt_to_mfn(start_info.pt_base); - pt_pfn = virt_to_pfn(alloc_page()); - -#if defined(__x86_64__) - offset = l4_table_offset(start_addr); - if (!(tab[offset] & _PAGE_PRESENT)) { - new_pt_frame(&pt_pfn, mfn, offset, L3_FRAME); - pt_pfn = virt_to_pfn(alloc_page()); - } - ASSERT(tab[offset] & _PAGE_PRESENT); - mfn = pte_to_mfn(tab[offset]); - tab = to_virt(mfn_to_pfn(mfn) << PAGE_SHIFT); -#endif -#if defined(__x86_64__) || defined(CONFIG_X86_PAE) - offset = l3_table_offset(start_addr); - if (!(tab[offset] & _PAGE_PRESENT)) { - new_pt_frame(&pt_pfn, mfn, offset, L2_FRAME); - pt_pfn = virt_to_pfn(alloc_page()); - } - ASSERT(tab[offset] & _PAGE_PRESENT); - mfn = pte_to_mfn(tab[offset]); - tab = to_virt(mfn_to_pfn(mfn) << PAGE_SHIFT); -#endif - offset = l2_table_offset(start_addr); - if (tab[offset] & _PAGE_PRESENT) { - printk("Demand map area already has a page table covering it?\n"); - BUG(); - } - demand_map_pgt = pfn_to_virt(pt_pfn); - new_pt_frame(&pt_pfn, mfn, offset, L1_FRAME); - ASSERT(tab[offset] & _PAGE_PRESENT); -} - -void *map_frames(unsigned long *f, unsigned long n) -{ - unsigned long x; - unsigned long y = 0; - mmu_update_t mmu_updates[16]; - int rc; - - if (n > 16) { - printk("Tried to map too many (%ld) frames at once.\n", n); - return NULL; - } - - /* Find a run of n contiguous frames */ - for (x = 0; x <= 1024 - n; x += y + 1) { - for (y = 0; y < n; y++) - if (demand_map_pgt[x+y] & _PAGE_PRESENT) - break; - if (y == n) - break; - } - if (y != n) { - printk("Failed to map %ld frames!\n", n); - return NULL; - } - - /* Found it at x. Map it in. */ - for (y = 0; y < n; y++) { - mmu_updates[y].ptr = virt_to_mach(&demand_map_pgt[x + y]); - mmu_updates[y].val = (f[y] << PAGE_SHIFT) | L1_PROT; - } - - rc = HYPERVISOR_mmu_update(mmu_updates, n, NULL, DOMID_SELF); - if (rc < 0) { - printk("Map %ld failed: %d.\n", n, rc); - return NULL; - } else { - return (void *)(unsigned long)((unsigned long)demand_map_area_start + - x * PAGE_SIZE); - } -} - void init_mm(void) { - unsigned long start_pfn, max_pfn; - printk("MM: Init\n"); - - printk(" _text: %p\n", &_text); - printk(" _etext: %p\n", &_etext); - printk(" _edata: %p\n", &_edata); - printk(" stack start: %p\n", &stack); - printk(" _end: %p\n", &_end); - - /* First page follows page table pages and 3 more pages (store page etc) */ - start_pfn = PFN_UP(to_phys(start_info.pt_base)) + - start_info.nr_pt_frames + 3; - max_pfn = start_info.nr_pages; - - printk(" start_pfn: %lx\n", start_pfn); - printk(" max_pfn: %lx\n", max_pfn); - - build_pagetable(&start_pfn, &max_pfn); - + arch_init_mm(&start_pfn, &max_pfn); /* * now we can initialise the page allocator */ @@ -745,9 +374,9 @@ void init_mm(void) init_page_allocator(PFN_PHYS(start_pfn), PFN_PHYS(max_pfn)); printk("MM: done\n"); - init_demand_mapping_area(max_pfn); - printk("Initialised demand area.\n"); -} + arch_init_demand_mapping_area(max_pfn); +} + void sanity_check(void) { diff -r 6ed4368b4a9e -r 7614ed2fa89b extras/mini-os/arch/x86/mm.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extras/mini-os/arch/x86/mm.c Mon Oct 16 15:20:15 2006 +0200 @@ -0,0 +1,429 @@ +/* + **************************************************************************** + * (C) 2003 - Rolf Neugebauer - Intel Research Cambridge + * (C) 2005 - Grzegorz Milos - Intel Research Cambridge + **************************************************************************** + * + * File: mm.c + * Author: Rolf Neugebauer (neugebar@xxxxxxxxxxxxx) + * 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 +#include +#include +#include +#include +#include + +#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) +#endif + +unsigned long *phys_to_machine_mapping; +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); + unsigned long prot_e, prot_t, pincmd; + mmu_update_t mmu_updates[1]; + struct mmuext_op pin_request; + + 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((unsigned long*)pfn_to_virt(*pt_pfn), 0, PAGE_SIZE); + + switch ( level ) + { + case L1_FRAME: + prot_e = L1_PROT; + prot_t = L2_PROT; + pincmd = MMUEXT_PIN_L1_TABLE; + break; +#if defined(__x86_64__) || defined(CONFIG_X86_PAE) + case L2_FRAME: + prot_e = L2_PROT; + prot_t = L3_PROT; + pincmd = MMUEXT_PIN_L2_TABLE; + break; +#endif +#if defined(__x86_64__) + case L3_FRAME: + prot_e = L3_PROT; + prot_t = L4_PROT; + pincmd = MMUEXT_PIN_L3_TABLE; + 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)]); + tab = pte_to_virt(tab[l3_table_offset(pt_page)]); +#endif +#if defined(CONFIG_X86_PAE) + tab = pte_to_virt(tab[l3_table_offset(pt_page)]); +#endif + + mmu_updates[0].ptr = ((pgentry_t)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(); + } + + /* Pin the page to provide correct protection */ + pin_request.cmd = pincmd; + pin_request.arg1.mfn = pfn_to_mfn(*pt_pfn); + if(HYPERVISOR_mmuext_op(&pin_request, 1, NULL, DOMID_SELF) < 0) + { + printk("ERROR: pinning failed\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 defined(__x86_64__) || defined(CONFIG_X86_PAE) + 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 +#endif /* defined(__x86_64__) || defined(CONFIG_X86_PAE) */ + + /* 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 +#if defined(__x86_64__) || defined(CONFIG_X86_PAE) + 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); +#endif + 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; +} + + +void mem_test(unsigned long *start_add, unsigned long *end_add) +{ + unsigned long mask = 0x10000; + unsigned long *pointer; + + for(pointer = start_add; pointer < end_add; pointer++) + { + if(!(((unsigned long)pointer) & 0xfffff)) + { + printk("Writing to %lx\n", pointer); + page_walk((unsigned long)pointer); + } + *pointer = (unsigned long)pointer & ~mask; + } + + for(pointer = start_add; pointer < end_add; pointer++) + { + if(((unsigned long)pointer & ~mask) != *pointer) + printk("Read error at 0x%lx. Read: 0x%lx, should read 0x%lx\n", + (unsigned long)pointer, + *pointer, + ((unsigned long)pointer & ~mask)); + } + +} + +static pgentry_t *demand_map_pgt; +static void *demand_map_area_start; + +void arch_init_demand_mapping_area(unsigned long max_pfn) +{ + unsigned long mfn; + pgentry_t *tab; + unsigned long start_addr; + unsigned long pt_pfn; + unsigned offset; + + /* Round up to four megs. + 1024 rather than + 1023 since we want + to be sure we don't end up in the same place we started. */ + max_pfn = (max_pfn + L1_PAGETABLE_ENTRIES) & ~(L1_PAGETABLE_ENTRIES - 1); + if (max_pfn == 0 || + (unsigned long)pfn_to_virt(max_pfn + L1_PAGETABLE_ENTRIES) >= + HYPERVISOR_VIRT_START) { + printk("Too much memory; no room for demand map hole.\n"); + do_exit(); + } + + demand_map_area_start = pfn_to_virt(max_pfn); + printk("Demand map pfns start at %lx (%p).\n", max_pfn, + demand_map_area_start); + start_addr = (unsigned long)demand_map_area_start; + + tab = (pgentry_t *)start_info.pt_base; + mfn = virt_to_mfn(start_info.pt_base); + pt_pfn = virt_to_pfn(alloc_page()); + +#if defined(__x86_64__) + offset = l4_table_offset(start_addr); + if (!(tab[offset] & _PAGE_PRESENT)) { + new_pt_frame(&pt_pfn, mfn, offset, L3_FRAME); + pt_pfn = virt_to_pfn(alloc_page()); + } + ASSERT(tab[offset] & _PAGE_PRESENT); + mfn = pte_to_mfn(tab[offset]); + tab = to_virt(mfn_to_pfn(mfn) << PAGE_SHIFT); +#endif +#if defined(__x86_64__) || defined(CONFIG_X86_PAE) + offset = l3_table_offset(start_addr); + if (!(tab[offset] & _PAGE_PRESENT)) { + new_pt_frame(&pt_pfn, mfn, offset, L2_FRAME); + pt_pfn = virt_to_pfn(alloc_page()); + } + ASSERT(tab[offset] & _PAGE_PRESENT); + mfn = pte_to_mfn(tab[offset]); + tab = to_virt(mfn_to_pfn(mfn) << PAGE_SHIFT); +#endif + offset = l2_table_offset(start_addr); + if (tab[offset] & _PAGE_PRESENT) { + printk("Demand map area already has a page table covering it?\n"); + BUG(); + } + demand_map_pgt = pfn_to_virt(pt_pfn); + new_pt_frame(&pt_pfn, mfn, offset, L1_FRAME); + ASSERT(tab[offset] & _PAGE_PRESENT); + printk("Initialised demand area.\n"); +} + +void *map_frames(unsigned long *f, unsigned long n) +{ + unsigned long x; + unsigned long y = 0; + mmu_update_t mmu_updates[16]; + int rc; + + if (n > 16) { + printk("Tried to map too many (%ld) frames at once.\n", n); + return NULL; + } + + /* Find a run of n contiguous frames */ + for (x = 0; x <= 1024 - n; x += y + 1) { + for (y = 0; y < n; y++) + if (demand_map_pgt[x+y] & _PAGE_PRESENT) + break; + if (y == n) + break; + } + if (y != n) { + printk("Failed to map %ld frames!\n", n); + return NULL; + } + + /* Found it at x. Map it in. */ + for (y = 0; y < n; y++) { + mmu_updates[y].ptr = virt_to_mach(&demand_map_pgt[x + y]); + mmu_updates[y].val = (f[y] << PAGE_SHIFT) | L1_PROT; + } + + rc = HYPERVISOR_mmu_update(mmu_updates, n, NULL, DOMID_SELF); + if (rc < 0) { + printk("Map %ld failed: %d.\n", n, rc); + return NULL; + } else { + return (void *)(unsigned long)((unsigned long)demand_map_area_start + + x * PAGE_SIZE); + } +} + +void arch_init_mm(unsigned long* start_pfn_p, unsigned long* max_pfn_p) +{ + unsigned long start_pfn, max_pfn; + + printk("MM: Init\n"); + + printk(" _text: %p\n", &_text); + printk(" _etext: %p\n", &_etext); + printk(" _edata: %p\n", &_edata); + printk(" stack start: %p\n", &stack); + printk(" _end: %p\n", &_end); + + /* First page follows page table pages and 3 more pages (store page etc) */ + start_pfn = PFN_UP(to_phys(start_info.pt_base)) + + start_info.nr_pt_frames + 3; + max_pfn = start_info.nr_pages; + + printk(" start_pfn: %lx\n", start_pfn); + printk(" max_pfn: %lx\n", max_pfn); + + build_pagetable(&start_pfn, &max_pfn); + + *start_pfn_p = start_pfn; + *max_pfn_p = max_pfn; +} diff -r 6ed4368b4a9e -r 7614ed2fa89b extras/mini-os/include/x86/arch_mm.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extras/mini-os/include/x86/arch_mm.h Mon Oct 16 15:20:15 2006 +0200 @@ -0,0 +1,212 @@ +/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*- + * + * (C) 2003 - Rolf Neugebauer - Intel Research Cambridge + * Copyright (c) 2005, Keir A Fraser + * + * 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. + */ + +#ifndef _ARCH_MM_H_ +#define _ARCH_MM_H_ + +#if defined(__i386__) +#include +#elif defined(__x86_64__) +#include +#else +#error "Unsupported architecture" +#endif + +#include + + +#define L1_FRAME 1 +#define L2_FRAME 2 +#define L3_FRAME 3 + +#define L1_PAGETABLE_SHIFT 12 + +#if defined(__i386__) + +#if !defined(CONFIG_X86_PAE) + +#define L2_PAGETABLE_SHIFT 22 + +#define L1_PAGETABLE_ENTRIES 1024 +#define L2_PAGETABLE_ENTRIES 1024 + +#define PADDR_BITS 32 +#define PADDR_MASK (~0UL) + +#define NOT_L1_FRAMES 1 +#define PRIpte "08lx" +typedef unsigned long pgentry_t; + +#else /* defined(CONFIG_X86_PAE) */ + +#define L2_PAGETABLE_SHIFT 21 +#define L3_PAGETABLE_SHIFT 30 + +#define L1_PAGETABLE_ENTRIES 512 +#define L2_PAGETABLE_ENTRIES 512 +#define L3_PAGETABLE_ENTRIES 4 + +#define PADDR_BITS 44 +#define PADDR_MASK ((1ULL << PADDR_BITS)-1) + +#define L2_MASK ((1UL << L3_PAGETABLE_SHIFT) - 1) + +/* + * If starting from virtual address greater than 0xc0000000, + * this value will be 2 to account for final mid-level page + * directory which is always mapped in at this location. + */ +#define NOT_L1_FRAMES 3 +#define PRIpte "016llx" +typedef uint64_t pgentry_t; + +#endif /* !defined(CONFIG_X86_PAE) */ + +#elif defined(__x86_64__) + +#define L2_PAGETABLE_SHIFT 21 +#define L3_PAGETABLE_SHIFT 30 +#define L4_PAGETABLE_SHIFT 39 + +#define L1_PAGETABLE_ENTRIES 512 +#define L2_PAGETABLE_ENTRIES 512 +#define L3_PAGETABLE_ENTRIES 512 +#define L4_PAGETABLE_ENTRIES 512 + +/* These are page-table limitations. Current CPUs support only 40-bit phys. */ +#define PADDR_BITS 52 +#define VADDR_BITS 48 +#define PADDR_MASK ((1UL << PADDR_BITS)-1) +#define VADDR_MASK ((1UL << VADDR_BITS)-1) + +#define L2_MASK ((1UL << L3_PAGETABLE_SHIFT) - 1) +#define L3_MASK ((1UL << L4_PAGETABLE_SHIFT) - 1) + +#define NOT_L1_FRAMES 3 +#define PRIpte "016lx" +typedef unsigned long pgentry_t; + +#endif + +#define L1_MASK ((1UL << L2_PAGETABLE_SHIFT) - 1) + +/* Given a virtual address, get an entry offset into a page table. */ +#define l1_table_offset(_a) \ + (((_a) >> L1_PAGETABLE_SHIFT) & (L1_PAGETABLE_ENTRIES - 1)) +#define l2_table_offset(_a) \ + (((_a) >> L2_PAGETABLE_SHIFT) & (L2_PAGETABLE_ENTRIES - 1)) +#if defined(__x86_64__) || defined(CONFIG_X86_PAE) +#define l3_table_offset(_a) \ + (((_a) >> L3_PAGETABLE_SHIFT) & (L3_PAGETABLE_ENTRIES - 1)) +#endif +#if defined(__x86_64__) +#define l4_table_offset(_a) \ + (((_a) >> L4_PAGETABLE_SHIFT) & (L4_PAGETABLE_ENTRIES - 1)) +#endif + +#define _PAGE_PRESENT 0x001UL +#define _PAGE_RW 0x002UL +#define _PAGE_USER 0x004UL +#define _PAGE_PWT 0x008UL +#define _PAGE_PCD 0x010UL +#define _PAGE_ACCESSED 0x020UL +#define _PAGE_DIRTY 0x040UL +#define _PAGE_PAT 0x080UL +#define _PAGE_PSE 0x080UL +#define _PAGE_GLOBAL 0x100UL + +#if defined(__i386__) +#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED) +#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY |_PAGE_USER) +#if defined(CONFIG_X86_PAE) +#define L3_PROT (_PAGE_PRESENT) +#endif /* CONFIG_X86_PAE */ +#elif defined(__x86_64__) +#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_USER) +#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER) +#define L3_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER) +#define L4_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER) +#endif /* __i386__ || __x86_64__ */ + +#ifndef CONFIG_X86_PAE +#define PAGE_SIZE (1UL << L1_PAGETABLE_SHIFT) +#else +#define PAGE_SIZE (1ULL << L1_PAGETABLE_SHIFT) +#endif +#define PAGE_SHIFT L1_PAGETABLE_SHIFT +#define PAGE_MASK (~(PAGE_SIZE-1)) + +#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> L1_PAGETABLE_SHIFT) +#define PFN_DOWN(x) ((x) >> L1_PAGETABLE_SHIFT) +#define PFN_PHYS(x) ((x) << L1_PAGETABLE_SHIFT) +#define PHYS_PFN(x) ((x) >> L1_PAGETABLE_SHIFT) + +/* to align the pointer to the (next) page boundary */ +#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) + +/* Definitions for machine and pseudophysical addresses. */ +#ifdef CONFIG_X86_PAE +typedef unsigned long long paddr_t; +typedef unsigned long long maddr_t; +#else +typedef unsigned long paddr_t; +typedef unsigned long maddr_t; +#endif + +extern unsigned long *phys_to_machine_mapping; +extern char _text, _etext, _edata, _end; +#define pfn_to_mfn(_pfn) (phys_to_machine_mapping[(_pfn)]) +static __inline__ maddr_t phys_to_machine(paddr_t phys) +{ + maddr_t machine = pfn_to_mfn(phys >> PAGE_SHIFT); + machine = (machine << PAGE_SHIFT) | (phys & ~PAGE_MASK); + return machine; +} + +#define mfn_to_pfn(_mfn) (machine_to_phys_mapping[(_mfn)]) +static __inline__ paddr_t machine_to_phys(maddr_t machine) +{ + paddr_t phys = mfn_to_pfn(machine >> PAGE_SHIFT); + phys = (phys << PAGE_SHIFT) | (machine & ~PAGE_MASK); + return phys; +} + +#define VIRT_START ((unsigned long)&_text) + +#define to_phys(x) ((unsigned long)(x)-VIRT_START) +#define to_virt(x) ((void *)((unsigned long)(x)+VIRT_START)) + +#define virt_to_pfn(_virt) (PFN_DOWN(to_phys(_virt))) +#define virt_to_mfn(_virt) (pfn_to_mfn(virt_to_pfn(_virt))) +#define mach_to_virt(_mach) (to_virt(machine_to_phys(_mach))) +#define virt_to_mach(_virt) (phys_to_machine(to_phys(_virt))) +#define mfn_to_virt(_mfn) (to_virt(mfn_to_pfn(_mfn) << PAGE_SHIFT)) +#define pfn_to_virt(_pfn) (to_virt((_pfn) << PAGE_SHIFT)) + +/* Pagetable walking. */ +#define pte_to_mfn(_pte) (((_pte) & (PADDR_MASK&PAGE_MASK)) >> L1_PAGETABLE_SHIFT) +#define pte_to_virt(_pte) to_virt(mfn_to_pfn(pte_to_mfn(_pte)) << PAGE_SHIFT) + + +#endif /* _ARCH_MM_H_ */