Merge branch 'stable/for-linus-4.1' of git://git.kernel.org/pub/scm/linux/kernel...
[deliverable/linux.git] / arch / um / kernel / physmem.c
CommitLineData
1da177e4 1/*
6d536e4b 2 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
1da177e4
LT
3 * Licensed under the GPL
4 */
5
73395a00
AV
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>
1da177e4 16
1da177e4
LT
17static int physmem_fd = -1;
18
1da177e4
LT
19/* Changed during early boot */
20unsigned long high_physmem;
73395a00 21EXPORT_SYMBOL(high_physmem);
1da177e4 22
ae173816 23extern unsigned long long physmem_size;
1da177e4 24
9e6a57d2 25void __init mem_total_pages(unsigned long physmem, unsigned long iomem,
97a1fcbb 26 unsigned long highmem)
1da177e4 27{
9e6a57d2
HL
28 unsigned long phys_pages, highmem_pages;
29 unsigned long iomem_pages, total_pages;
1da177e4 30
9e6a57d2
HL
31 phys_pages = physmem >> PAGE_SHIFT;
32 iomem_pages = iomem >> PAGE_SHIFT;
1da177e4 33 highmem_pages = highmem >> PAGE_SHIFT;
1da177e4 34
9e6a57d2 35 total_pages = phys_pages + iomem_pages + highmem_pages;
1da177e4
LT
36
37 max_mapnr = total_pages;
1da177e4
LT
38}
39
1da177e4
LT
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);
6d536e4b
JD
48 if (err) {
49 if (err == -ENOMEM)
ba180fd4 50 printk(KERN_ERR "try increasing the host's "
1da177e4
LT
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
23bbd586 58extern int __syscall_stub_start;
d67b569f 59
fe205bdd
TM
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 */
97a1fcbb
JD
80void __init setup_physmem(unsigned long start, unsigned long reserve_end,
81 unsigned long len, unsigned long long highmem)
1da177e4
LT
82{
83 unsigned long reserve = reserve_end - start;
fe205bdd
TM
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 }
1da177e4
LT
97
98 physmem_fd = create_mem_file(len + highmem);
99
1da177e4 100 err = os_map_memory((void *) uml_reserved, physmem_fd, offset,
fe205bdd 101 map_size, 1, 1, 1);
6d536e4b 102 if (err < 0) {
512b6fb1 103 printf("setup_physmem - mapping %ld bytes of memory at 0x%p "
fe205bdd 104 "failed - errno = %d\n", map_size,
512b6fb1 105 (void *) uml_reserved, err);
1da177e4
LT
106 exit(1);
107 }
108
ba180fd4
JD
109 /*
110 * Special kludge - This page will be mapped in to userspace processes
d67b569f
JD
111 * from physmem_fd, so it needs to be written out there.
112 */
113 os_seek_file(physmem_fd, __pa(&__syscall_stub_start));
a6ea4cce 114 os_write_file(physmem_fd, &__syscall_stub_start, PAGE_SIZE);
0565103d 115 os_fsync_file(physmem_fd);
d67b569f 116
1da177e4
LT
117 bootmap_size = init_bootmem(pfn, pfn + delta);
118 free_bootmem(__pa(reserve_end) + bootmap_size,
119 len - bootmap_size - reserve);
120}
121
0a7675aa 122int phys_mapping(unsigned long phys, unsigned long long *offset_out)
1da177e4 123{
1da177e4
LT
124 int fd = -1;
125
6d536e4b 126 if (phys < physmem_size) {
1da177e4
LT
127 fd = physmem_fd;
128 *offset_out = phys;
129 }
6d536e4b 130 else if (phys < __pa(end_iomem)) {
1da177e4
LT
131 struct iomem_region *region = iomem_regions;
132
6d536e4b
JD
133 while (region != NULL) {
134 if ((phys >= region->phys) &&
135 (phys < region->phys + region->size)) {
1da177e4
LT
136 fd = region->fd;
137 *offset_out = phys - region->phys;
138 break;
139 }
140 region = region->next;
141 }
142 }
6d536e4b 143 else if (phys < __pa(end_iomem) + highmem) {
1da177e4
LT
144 fd = physmem_fd;
145 *offset_out = phys - iomem_size;
146 }
147
60678bbc 148 return fd;
1da177e4
LT
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
94c282d7
JD
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 */
80e39311 179struct iomem_region *iomem_regions;
94c282d7 180
80e39311
JD
181/* Initialized in parse_iomem and unchanged thereafter */
182int iomem_size;
94c282d7 183
1da177e4
LT
184unsigned long find_iomem(char *driver, unsigned long *len_out)
185{
186 struct iomem_region *region = iomem_regions;
187
6d536e4b
JD
188 while (region != NULL) {
189 if (!strcmp(region->driver, driver)) {
1da177e4 190 *len_out = region->size;
60678bbc 191 return region->virt;
1da177e4 192 }
c39e50b4
VV
193
194 region = region->next;
1da177e4
LT
195 }
196
60678bbc 197 return 0;
1da177e4 198}
73395a00 199EXPORT_SYMBOL(find_iomem);
1da177e4 200
99764fa4 201static int setup_iomem(void)
1da177e4
LT
202{
203 struct iomem_region *region = iomem_regions;
204 unsigned long iomem_start = high_physmem + PAGE_SIZE;
205 int err;
206
6d536e4b 207 while (region != NULL) {
1da177e4
LT
208 err = os_map_memory((void *) iomem_start, region->fd, 0,
209 region->size, 1, 1, 0);
6d536e4b 210 if (err)
ba180fd4
JD
211 printk(KERN_ERR "Mapping iomem region for driver '%s' "
212 "failed, errno = %d\n", region->driver, -err);
1da177e4
LT
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
60678bbc 222 return 0;
1da177e4
LT
223}
224
225__initcall(setup_iomem);
This page took 0.759368 seconds and 5 git commands to generate.