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 24 static int physmem_fd = -1; 25 26 /* Changed during early boot */ 27 unsigned long high_physmem; 28 29 extern unsigned long long physmem_size; 30 31 int 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 */ 72 static unsigned long kmem_top = 0; 73 74 unsigned 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 81 void 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 99 extern int __syscall_stub_start; 100 101 void 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 130 int 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 159 static 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 175 extern 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 */ 187 struct iomem_region *iomem_regions = NULL; 188 189 /* Initialized in parse_iomem */ 190 int iomem_size = 0; 191 192 unsigned 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 208 int 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