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