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