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