1/* 2 * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) 3 * Licensed under the GPL 4 */ 5 6#include "linux/mm.h" 7#include "linux/rbtree.h" 8#include "linux/slab.h" 9#include "linux/vmalloc.h" 10#include "linux/bootmem.h" 11#include "linux/module.h" 12#include "linux/pfn.h" 13#include "asm/types.h" 14#include "asm/pgtable.h" 15#include "kern_util.h" 16#include "as-layout.h" 17#include "mode_kern.h" 18#include "mem.h" 19#include "mem_user.h" 20#include "os.h" 21#include "kern.h" 22#include "init.h" 23 24static int physmem_fd = -1; 25 26/* Changed during early boot */ 27unsigned long high_physmem; 28 29extern unsigned long long physmem_size; 30 31int init_maps(unsigned long physmem, unsigned long iomem, unsigned long highmem) 32{ 33 struct page *p, *map; 34 unsigned long phys_len, phys_pages, highmem_len, highmem_pages; 35 unsigned long iomem_len, iomem_pages, total_len, total_pages; 36 int i; 37 38 phys_pages = physmem >> PAGE_SHIFT; 39 phys_len = phys_pages * sizeof(struct page); 40 41 iomem_pages = iomem >> PAGE_SHIFT; 42 iomem_len = iomem_pages * sizeof(struct page); 43 44 highmem_pages = highmem >> PAGE_SHIFT; 45 highmem_len = highmem_pages * sizeof(struct page); 46 47 total_pages = phys_pages + iomem_pages + highmem_pages; 48 total_len = phys_len + iomem_len + highmem_len; 49 50 if(kmalloc_ok){ 51 map = kmalloc(total_len, GFP_KERNEL); 52 if(map == NULL) 53 map = vmalloc(total_len); 54 } 55 else map = alloc_bootmem_low_pages(total_len); 56 57 if(map == NULL) 58 return -ENOMEM; 59 60 for(i = 0; i < total_pages; i++){ 61 p = &map[i]; 62 memset(p, 0, sizeof(struct page)); 63 SetPageReserved(p); 64 INIT_LIST_HEAD(&p->lru); 65 } 66 67 max_mapnr = total_pages; 68 return 0; 69} 70 71/* Changed during early boot */ 72static unsigned long kmem_top = 0; 73 74unsigned long get_kmem_end(void) 75{ 76 if(kmem_top == 0) 77 kmem_top = CHOOSE_MODE(kmem_end_tt, kmem_end_skas); 78 return kmem_top; 79} 80 81void map_memory(unsigned long virt, unsigned long phys, unsigned long len, 82 int r, int w, int x) 83{ 84 __u64 offset; 85 int fd, err; 86 87 fd = phys_mapping(phys, &offset); 88 err = os_map_memory((void *) virt, fd, offset, len, r, w, x); 89 if(err) { 90 if(err == -ENOMEM) 91 printk("try increasing the host's " 92 "/proc/sys/vm/max_map_count to <physical " 93 "memory size>/4096\n"); 94 panic("map_memory(0x%lx, %d, 0x%llx, %ld, %d, %d, %d) failed, " 95 "err = %d\n", virt, fd, offset, len, r, w, x, err); 96 } 97} 98 99extern int __syscall_stub_start; 100 101void setup_physmem(unsigned long start, unsigned long reserve_end, 102 unsigned long len, unsigned long long highmem) 103{ 104 unsigned long reserve = reserve_end - start; 105 int pfn = PFN_UP(__pa(reserve_end)); 106 int delta = (len - reserve) >> PAGE_SHIFT; 107 int err, offset, bootmap_size; 108 109 physmem_fd = create_mem_file(len + highmem); 110 111 offset = uml_reserved - uml_physmem; 112 err = os_map_memory((void *) uml_reserved, physmem_fd, offset, 113 len - offset, 1, 1, 0); 114 if(err < 0){ 115 os_print_error(err, "Mapping memory"); 116 exit(1); 117 } 118 119 /* Special kludge - This page will be mapped in to userspace processes 120 * from physmem_fd, so it needs to be written out there. 121 */ 122 os_seek_file(physmem_fd, __pa(&__syscall_stub_start)); 123 os_write_file(physmem_fd, &__syscall_stub_start, PAGE_SIZE); 124 125 bootmap_size = init_bootmem(pfn, pfn + delta); 126 free_bootmem(__pa(reserve_end) + bootmap_size, 127 len - bootmap_size - reserve); 128} 129 130int phys_mapping(unsigned long phys, __u64 *offset_out) 131{ 132 int fd = -1; 133 134 if(phys < physmem_size){ 135 fd = physmem_fd; 136 *offset_out = phys; 137 } 138 else if(phys < __pa(end_iomem)){ 139 struct iomem_region *region = iomem_regions; 140 141 while(region != NULL){ 142 if((phys >= region->phys) && 143 (phys < region->phys + region->size)){ 144 fd = region->fd; 145 *offset_out = phys - region->phys; 146 break; 147 } 148 region = region->next; 149 } 150 } 151 else if(phys < __pa(end_iomem) + highmem){ 152 fd = physmem_fd; 153 *offset_out = phys - iomem_size; 154 } 155 156 return fd; 157} 158 159static int __init uml_mem_setup(char *line, int *add) 160{ 161 char *retptr; 162 physmem_size = memparse(line,&retptr); 163 return 0; 164} 165__uml_setup("mem=", uml_mem_setup, 166"mem=<Amount of desired ram>\n" 167" This controls how much \"physical\" memory the kernel allocates\n" 168" for the system. The size is specified as a number followed by\n" 169" one of 'k', 'K', 'm', 'M', which have the obvious meanings.\n" 170" This is not related to the amount of memory in the host. It can\n" 171" be more, and the excess, if it's ever used, will just be swapped out.\n" 172" Example: mem=64M\n\n" 173); 174 175extern int __init parse_iomem(char *str, int *add); 176 177__uml_setup("iomem=", parse_iomem, 178"iomem=<name>,<file>\n" 179" Configure <file> as an IO memory region named <name>.\n\n" 180); 181 182/* 183 * This list is constructed in parse_iomem and addresses filled in in 184 * setup_iomem, both of which run during early boot. Afterwards, it's 185 * unchanged. 186 */ 187struct iomem_region *iomem_regions = NULL; 188 189/* Initialized in parse_iomem */ 190int iomem_size = 0; 191 192unsigned long find_iomem(char *driver, unsigned long *len_out) 193{ 194 struct iomem_region *region = iomem_regions; 195 196 while(region != NULL){ 197 if(!strcmp(region->driver, driver)){ 198 *len_out = region->size; 199 return region->virt; 200 } 201 202 region = region->next; 203 } 204 205 return 0; 206} 207 208int setup_iomem(void) 209{ 210 struct iomem_region *region = iomem_regions; 211 unsigned long iomem_start = high_physmem + PAGE_SIZE; 212 int err; 213 214 while(region != NULL){ 215 err = os_map_memory((void *) iomem_start, region->fd, 0, 216 region->size, 1, 1, 0); 217 if(err) 218 printk("Mapping iomem region for driver '%s' failed, " 219 "errno = %d\n", region->driver, -err); 220 else { 221 region->virt = iomem_start; 222 region->phys = __pa(region->virt); 223 } 224 225 iomem_start += region->size + PAGE_SIZE; 226 region = region->next; 227 } 228 229 return 0; 230} 231 232__initcall(setup_iomem); 233