diff options
author | jdike <jdike> | 2003-12-16 16:21:54 +0000 |
---|---|---|
committer | jdike <jdike> | 2003-12-16 16:21:54 +0000 |
commit | 7d462f7850e534d789a6b4d1c1f58d99a95d64a7 (patch) | |
tree | 40771a1f8aafdf3cca95b8b8d14ba99077af8db8 | |
parent | 3c0c3e7adf61899a435bb58bb332875cda5c2750 (diff) | |
download | uml-history-7d462f7850e534d789a6b4d1c1f58d99a95d64a7.tar.gz |
Fixed highmem support.
-rw-r--r-- | arch/um/include/mem_user.h | 10 | ||||
-rw-r--r-- | arch/um/kernel/mem.c | 74 | ||||
-rw-r--r-- | arch/um/kernel/physmem.c | 67 | ||||
-rw-r--r-- | arch/um/kernel/um_arch.c | 24 | ||||
-rw-r--r-- | include/asm-um/pgtable.h | 1 |
5 files changed, 134 insertions, 42 deletions
diff --git a/arch/um/include/mem_user.h b/arch/um/include/mem_user.h index b0e01a9..fe0c298 100644 --- a/arch/um/include/mem_user.h +++ b/arch/um/include/mem_user.h @@ -49,19 +49,21 @@ extern int iomem_size; extern unsigned long host_task_size; extern unsigned long task_size; +extern void check_devanon(void); extern int init_mem_user(void); extern int create_mem_file(unsigned long len); extern void setup_memory(void *entry); extern unsigned long find_iomem(char *driver, unsigned long *len_out); -extern int init_maps(unsigned long len); +extern int init_maps(unsigned long physmem, unsigned long iomem, + unsigned long highmem); extern unsigned long get_vm(unsigned long len); extern void setup_physmem(unsigned long start, unsigned long usable, - unsigned long len); + unsigned long len, unsigned long highmem); extern void add_iomem(char *name, int fd, unsigned long size); extern unsigned long phys_offset(unsigned long phys); extern void unmap_physmem(void); -extern int map_memory(unsigned long virt, unsigned long phys, - unsigned long len, int r, int w, int x); +extern void map_memory(unsigned long virt, unsigned long phys, + unsigned long len, int r, int w, int x); extern int protect_memory(unsigned long addr, unsigned long len, int r, int w, int x, int must_succeed); extern unsigned long get_kmem_end(void); diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c index aba6258..8dd6327 100644 --- a/arch/um/kernel/mem.c +++ b/arch/um/kernel/mem.c @@ -40,14 +40,31 @@ static void map_cb(void *unused) map_memory(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0); } -void mem_init(void) +#ifdef CONFIG_HIGHMEM +static void setup_highmem(unsigned long highmem_start, + unsigned long highmem_len) { - unsigned long start; + struct page *page; + unsigned long highmem_pfn; + int i; -#ifdef CONFIG_HIGHMEM - highmem_start_page = phys_page(__pa(high_physmem)); + highmem_start_page = virt_to_page(highmem_start); + + highmem_pfn = __pa(highmem_start) >> PAGE_SHIFT; + for(i = 0; i < highmem_len >> PAGE_SHIFT; i++){ + page = &mem_map[highmem_pfn + i]; + ClearPageReserved(page); + set_bit(PG_highmem, &page->flags); + atomic_set(&page->count, 1); + __free_page(page); + } +} #endif +void mem_init(void) +{ + unsigned long start; + /* clear the zero-page */ memset((void *) empty_zero_page, 0, PAGE_SIZE); @@ -74,6 +91,10 @@ void mem_init(void) printk(KERN_INFO "Memory: %luk available\n", (unsigned long) nr_free_pages() << (PAGE_SHIFT-10)); kmalloc_ok = 1; + +#ifdef CONFIG_HIGHMEM + setup_highmem(end_iomem, highmem); +#endif } static void __init fixrange_init(unsigned long start, unsigned long end, @@ -106,6 +127,47 @@ static void __init fixrange_init(unsigned long start, unsigned long end, } } +#if CONFIG_HIGHMEM +pte_t *kmap_pte; +pgprot_t kmap_prot; + +#define kmap_get_fixmap_pte(vaddr) \ + pte_offset(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr)) + +void __init kmap_init(void) +{ + unsigned long kmap_vstart; + + /* cache the first kmap pte */ + kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN); + kmap_pte = kmap_get_fixmap_pte(kmap_vstart); + + kmap_prot = PAGE_KERNEL; +} + +static void init_highmem(void) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + unsigned long vaddr; + + /* + * Permanent kmaps: + */ + vaddr = PKMAP_BASE; + fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, swapper_pg_dir); + + pgd = swapper_pg_dir + __pgd_offset(vaddr); + pmd = pmd_offset(pgd, vaddr); + pte = pte_offset(pmd, vaddr); + pkmap_page_table = pte; + + kmap_init(); +} + +#endif /* CONFIG_HIGHMEM */ + void paging_init(void) { unsigned long zones_size[MAX_NR_ZONES], vaddr; @@ -115,8 +177,7 @@ void paging_init(void) empty_bad_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE); for(i=0;i<sizeof(zones_size)/sizeof(zones_size[0]);i++) zones_size[i] = 0; - zones_size[0] = (high_physmem >> PAGE_SHIFT) - - (uml_physmem >> PAGE_SHIFT); + zones_size[0] = (end_iomem >> PAGE_SHIFT) - (uml_physmem >> PAGE_SHIFT); zones_size[2] = highmem >> PAGE_SHIFT; free_area_init(zones_size); @@ -129,7 +190,6 @@ void paging_init(void) #if CONFIG_HIGHMEM init_highmem(); - setup_highmem(highmem); #endif } diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c index 0ccab50..787c59c 100644 --- a/arch/um/kernel/physmem.c +++ b/arch/um/kernel/physmem.c @@ -133,24 +133,36 @@ unsigned long to_phys(void *virt) return(((unsigned long) virt) - uml_physmem); } -int init_maps(unsigned long len) +int init_maps(unsigned long physmem, unsigned long iomem, unsigned long highmem) { struct page *p, *map; - int i, n; + unsigned long phys_len, phys_pages, highmem_len, highmem_pages; + unsigned long iomem_len, iomem_pages, total_len, total_pages; + int i; + + phys_pages = physmem >> PAGE_SHIFT; + phys_len = phys_pages * sizeof(struct page); + + iomem_pages = iomem >> PAGE_SHIFT; + iomem_len = iomem_pages * sizeof(struct page); + + highmem_pages = highmem >> PAGE_SHIFT; + highmem_len = highmem_pages * sizeof(struct page); - n = len >> PAGE_SHIFT; - len = n * sizeof(struct page); + total_pages = phys_pages + iomem_pages + highmem_pages; + total_len = phys_len + iomem_pages + highmem_len; if(kmalloc_ok){ - map = kmalloc(len, GFP_KERNEL); - if(map == NULL) map = vmalloc(len); + map = kmalloc(total_len, GFP_KERNEL); + if(map == NULL) + map = vmalloc(total_len); } - else map = alloc_bootmem_low_pages(len); + else map = alloc_bootmem_low_pages(total_len); if(map == NULL) return(-ENOMEM); - for(i = 0; i < n; i++){ + for(i = 0; i < total_pages; i++){ p = &map[i]; set_page_count(p, 0); SetPageReserved(p); @@ -158,22 +170,23 @@ int init_maps(unsigned long len) } mem_map = map; - max_mapnr = n; + max_mapnr = total_pages; return(0); } -struct page *__virt_to_page(const unsigned long virt) +struct page *phys_to_page(const unsigned long phys) { - int index = (virt - uml_physmem) >> PAGE_SHIFT; + return(&mem_map[phys >> PAGE_SHIFT]); +} - return(&mem_map[index]); +struct page *__virt_to_page(const unsigned long virt) +{ + return(&mem_map[__pa(virt) >> PAGE_SHIFT]); } unsigned long page_to_phys(struct page *page) { - int index = page - mem_map; - - return(virt_to_phys((void *) (uml_physmem + (index << PAGE_SHIFT)))); + return((page - mem_map) << PAGE_SHIFT); } pte_t mk_pte(struct page *page, pgprot_t pgprot) @@ -195,27 +208,30 @@ unsigned long get_kmem_end(void) return(kmem_top); } -int map_memory(unsigned long virt, unsigned long phys, unsigned long len, - int r, int w, int x) +void map_memory(unsigned long virt, unsigned long phys, unsigned long len, + int r, int w, int x) { __u64 offset; - int fd; + int fd, err; fd = phys_mapping(phys, &offset); - return(os_map_memory((void *) virt, fd, offset, len, r, w, x)); + err = os_map_memory((void *) virt, fd, offset, len, r, w, x); + if(err) + panic("map_memory(0x%lx, %d, 0x%llx, %ld, %d, %d, %d) failed, " + "err = %d\n", virt, fd, offset, len, r, w, x, err); } #define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) void setup_physmem(unsigned long start, unsigned long reserve_end, - unsigned long len) + unsigned long len, unsigned long highmem) { unsigned long reserve = reserve_end - start; int pfn = PFN_UP(__pa(reserve_end)); int delta = (len - reserve) >> PAGE_SHIFT; int err, offset, bootmap_size; - physmem_fd = create_mem_file(len); + physmem_fd = create_mem_file(len + highmem); offset = uml_reserved - uml_physmem; err = os_map_memory((void *) uml_reserved, physmem_fd, offset, @@ -240,11 +256,11 @@ int phys_mapping(unsigned long phys, __u64 *offset_out) fd = desc->fd; *offset_out = desc->offset; } - else if((phys >= 0) && (phys < physmem_size)){ + else if(phys < physmem_size){ fd = physmem_fd; *offset_out = phys; } - else { + else if(phys < __pa(end_iomem)){ struct iomem_region *region = iomem_regions; while(region != NULL){ @@ -257,6 +273,11 @@ int phys_mapping(unsigned long phys, __u64 *offset_out) region = region->next; } } + else if(phys < __pa(end_iomem) + highmem){ + fd = physmem_fd; + *offset_out = phys - iomem_size; + } + return(fd); } diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index 57b42ba..e8aeb22 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -336,9 +336,15 @@ int linux_main(int argc, char **argv) #endif highmem = 0; - max_physmem = get_kmem_end() - uml_physmem - MIN_VMALLOC; - if(physmem_size > max_physmem){ - highmem = physmem_size - max_physmem; + iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK; + max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC; + + /* Zones have to begin on a 1 << MAX_ORDER page boundary, + * so this makes sure that's true for highmem + */ + max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1); + if(physmem_size + iomem_size > max_physmem){ + highmem = physmem_size + iomem_size - max_physmem; physmem_size -= highmem; #ifndef CONFIG_HIGHMEM highmem = 0; @@ -348,15 +354,16 @@ int linux_main(int argc, char **argv) } high_physmem = uml_physmem + physmem_size; - high_memory = (void *) high_physmem; - end_iomem = high_physmem + PAGE_SIZE + iomem_size; + end_iomem = high_physmem + iomem_size; + high_memory = (void *) end_iomem; start_vm = VMALLOC_START; - setup_physmem(uml_physmem, uml_reserved, physmem_size); - if(init_maps(physmem_size)){ + setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem); + if(init_maps(physmem_size, iomem_size, highmem)){ printf("Failed to allocate mem_map for %ld bytes of physical " - "memory\n", physmem_size); + "memory and %ld bytes of highmem\n", physmem_size, + highmem); exit(1); } @@ -410,6 +417,7 @@ void __init check_bugs(void) arch_check_bugs(); check_ptrace(); check_sigio(); + check_devanon(); } /* diff --git a/include/asm-um/pgtable.h b/include/asm-um/pgtable.h index a226925..798e47d 100644 --- a/include/asm-um/pgtable.h +++ b/include/asm-um/pgtable.h @@ -206,6 +206,7 @@ static inline void pgd_clear(pgd_t * pgdp) { } #define pte_page(pte) virt_to_page(__va(pte_val(pte))) #define pmd_page(pmd) ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) +extern struct page *phys_to_page(const unsigned long phys); extern struct page *__virt_to_page(const unsigned long virt); #define virt_to_page(addr) __virt_to_page((const unsigned long) addr) |