Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec...
[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
97a1fcbb
JD
25int __init init_maps(unsigned long physmem, unsigned long iomem,
26 unsigned long highmem)
1da177e4
LT
27{
28 struct page *p, *map;
29 unsigned long phys_len, phys_pages, highmem_len, highmem_pages;
30 unsigned long iomem_len, iomem_pages, total_len, total_pages;
31 int i;
32
33 phys_pages = physmem >> PAGE_SHIFT;
34 phys_len = phys_pages * sizeof(struct page);
35
36 iomem_pages = iomem >> PAGE_SHIFT;
37 iomem_len = iomem_pages * sizeof(struct page);
38
39 highmem_pages = highmem >> PAGE_SHIFT;
40 highmem_len = highmem_pages * sizeof(struct page);
41
42 total_pages = phys_pages + iomem_pages + highmem_pages;
3dfd95b3 43 total_len = phys_len + iomem_len + highmem_len;
1da177e4 44
97a1fcbb 45 map = alloc_bootmem_low_pages(total_len);
6d536e4b 46 if (map == NULL)
60678bbc 47 return -ENOMEM;
1da177e4 48
6d536e4b 49 for (i = 0; i < total_pages; i++) {
1da177e4 50 p = &map[i];
70dc991d 51 memset(p, 0, sizeof(struct page));
1da177e4
LT
52 SetPageReserved(p);
53 INIT_LIST_HEAD(&p->lru);
54 }
55
56 max_mapnr = total_pages;
60678bbc 57 return 0;
1da177e4
LT
58}
59
1da177e4
LT
60void map_memory(unsigned long virt, unsigned long phys, unsigned long len,
61 int r, int w, int x)
62{
63 __u64 offset;
64 int fd, err;
65
66 fd = phys_mapping(phys, &offset);
67 err = os_map_memory((void *) virt, fd, offset, len, r, w, x);
6d536e4b
JD
68 if (err) {
69 if (err == -ENOMEM)
ba180fd4 70 printk(KERN_ERR "try increasing the host's "
1da177e4
LT
71 "/proc/sys/vm/max_map_count to <physical "
72 "memory size>/4096\n");
73 panic("map_memory(0x%lx, %d, 0x%llx, %ld, %d, %d, %d) failed, "
74 "err = %d\n", virt, fd, offset, len, r, w, x, err);
75 }
76}
77
23bbd586 78extern int __syscall_stub_start;
d67b569f 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;
84 int pfn = PFN_UP(__pa(reserve_end));
85 int delta = (len - reserve) >> PAGE_SHIFT;
86 int err, offset, bootmap_size;
87
88 physmem_fd = create_mem_file(len + highmem);
89
90 offset = uml_reserved - uml_physmem;
91 err = os_map_memory((void *) uml_reserved, physmem_fd, offset,
5c8aacea 92 len - offset, 1, 1, 1);
6d536e4b 93 if (err < 0) {
512b6fb1
JD
94 printf("setup_physmem - mapping %ld bytes of memory at 0x%p "
95 "failed - errno = %d\n", len - offset,
96 (void *) uml_reserved, err);
1da177e4
LT
97 exit(1);
98 }
99
ba180fd4
JD
100 /*
101 * Special kludge - This page will be mapped in to userspace processes
d67b569f
JD
102 * from physmem_fd, so it needs to be written out there.
103 */
104 os_seek_file(physmem_fd, __pa(&__syscall_stub_start));
a6ea4cce 105 os_write_file(physmem_fd, &__syscall_stub_start, PAGE_SIZE);
0565103d 106 os_fsync_file(physmem_fd);
d67b569f 107
1da177e4
LT
108 bootmap_size = init_bootmem(pfn, pfn + delta);
109 free_bootmem(__pa(reserve_end) + bootmap_size,
110 len - bootmap_size - reserve);
111}
112
0a7675aa 113int phys_mapping(unsigned long phys, unsigned long long *offset_out)
1da177e4 114{
1da177e4
LT
115 int fd = -1;
116
6d536e4b 117 if (phys < physmem_size) {
1da177e4
LT
118 fd = physmem_fd;
119 *offset_out = phys;
120 }
6d536e4b 121 else if (phys < __pa(end_iomem)) {
1da177e4
LT
122 struct iomem_region *region = iomem_regions;
123
6d536e4b
JD
124 while (region != NULL) {
125 if ((phys >= region->phys) &&
126 (phys < region->phys + region->size)) {
1da177e4
LT
127 fd = region->fd;
128 *offset_out = phys - region->phys;
129 break;
130 }
131 region = region->next;
132 }
133 }
6d536e4b 134 else if (phys < __pa(end_iomem) + highmem) {
1da177e4
LT
135 fd = physmem_fd;
136 *offset_out = phys - iomem_size;
137 }
138
60678bbc 139 return fd;
1da177e4
LT
140}
141
142static int __init uml_mem_setup(char *line, int *add)
143{
144 char *retptr;
145 physmem_size = memparse(line,&retptr);
146 return 0;
147}
148__uml_setup("mem=", uml_mem_setup,
149"mem=<Amount of desired ram>\n"
150" This controls how much \"physical\" memory the kernel allocates\n"
151" for the system. The size is specified as a number followed by\n"
152" one of 'k', 'K', 'm', 'M', which have the obvious meanings.\n"
153" This is not related to the amount of memory in the host. It can\n"
154" be more, and the excess, if it's ever used, will just be swapped out.\n"
155" Example: mem=64M\n\n"
156);
157
94c282d7
JD
158extern int __init parse_iomem(char *str, int *add);
159
160__uml_setup("iomem=", parse_iomem,
161"iomem=<name>,<file>\n"
162" Configure <file> as an IO memory region named <name>.\n\n"
163);
164
165/*
166 * This list is constructed in parse_iomem and addresses filled in in
167 * setup_iomem, both of which run during early boot. Afterwards, it's
168 * unchanged.
169 */
80e39311 170struct iomem_region *iomem_regions;
94c282d7 171
80e39311
JD
172/* Initialized in parse_iomem and unchanged thereafter */
173int iomem_size;
94c282d7 174
1da177e4
LT
175unsigned long find_iomem(char *driver, unsigned long *len_out)
176{
177 struct iomem_region *region = iomem_regions;
178
6d536e4b
JD
179 while (region != NULL) {
180 if (!strcmp(region->driver, driver)) {
1da177e4 181 *len_out = region->size;
60678bbc 182 return region->virt;
1da177e4 183 }
c39e50b4
VV
184
185 region = region->next;
1da177e4
LT
186 }
187
60678bbc 188 return 0;
1da177e4 189}
73395a00 190EXPORT_SYMBOL(find_iomem);
1da177e4 191
99764fa4 192static int setup_iomem(void)
1da177e4
LT
193{
194 struct iomem_region *region = iomem_regions;
195 unsigned long iomem_start = high_physmem + PAGE_SIZE;
196 int err;
197
6d536e4b 198 while (region != NULL) {
1da177e4
LT
199 err = os_map_memory((void *) iomem_start, region->fd, 0,
200 region->size, 1, 1, 0);
6d536e4b 201 if (err)
ba180fd4
JD
202 printk(KERN_ERR "Mapping iomem region for driver '%s' "
203 "failed, errno = %d\n", region->driver, -err);
1da177e4
LT
204 else {
205 region->virt = iomem_start;
206 region->phys = __pa(region->virt);
207 }
208
209 iomem_start += region->size + PAGE_SIZE;
210 region = region->next;
211 }
212
60678bbc 213 return 0;
1da177e4
LT
214}
215
216__initcall(setup_iomem);
This page took 0.840847 seconds and 5 git commands to generate.