]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - arch/um/kernel/physmem.c
Merge tag 'driver-core-4.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[mirror_ubuntu-bionic-kernel.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>
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;
fe205bdd
TM
83 unsigned long pfn = PFN_UP(__pa(reserve_end));
84 unsigned long delta = (len - reserve) >> PAGE_SHIFT;
85 unsigned long offset, bootmap_size;
86 long map_size;
87 int err;
88
89 offset = uml_reserved - uml_physmem;
90 map_size = len - offset;
91 if(map_size <= 0) {
92 printf("Too few physical memory! Needed=%d, given=%d\n",
93 offset, len);
94 exit(1);
95 }
1da177e4
LT
96
97 physmem_fd = create_mem_file(len + highmem);
98
1da177e4 99 err = os_map_memory((void *) uml_reserved, physmem_fd, offset,
fe205bdd 100 map_size, 1, 1, 1);
6d536e4b 101 if (err < 0) {
512b6fb1 102 printf("setup_physmem - mapping %ld bytes of memory at 0x%p "
fe205bdd 103 "failed - errno = %d\n", map_size,
512b6fb1 104 (void *) uml_reserved, err);
1da177e4
LT
105 exit(1);
106 }
107
ba180fd4
JD
108 /*
109 * Special kludge - This page will be mapped in to userspace processes
d67b569f
JD
110 * from physmem_fd, so it needs to be written out there.
111 */
05eacfd0
NI
112 os_seek_file(physmem_fd, __pa(__syscall_stub_start));
113 os_write_file(physmem_fd, __syscall_stub_start, PAGE_SIZE);
0565103d 114 os_fsync_file(physmem_fd);
d67b569f 115
1da177e4
LT
116 bootmap_size = init_bootmem(pfn, pfn + delta);
117 free_bootmem(__pa(reserve_end) + bootmap_size,
118 len - bootmap_size - reserve);
119}
120
0a7675aa 121int phys_mapping(unsigned long phys, unsigned long long *offset_out)
1da177e4 122{
1da177e4
LT
123 int fd = -1;
124
6d536e4b 125 if (phys < physmem_size) {
1da177e4
LT
126 fd = physmem_fd;
127 *offset_out = phys;
128 }
6d536e4b 129 else if (phys < __pa(end_iomem)) {
1da177e4
LT
130 struct iomem_region *region = iomem_regions;
131
6d536e4b
JD
132 while (region != NULL) {
133 if ((phys >= region->phys) &&
134 (phys < region->phys + region->size)) {
1da177e4
LT
135 fd = region->fd;
136 *offset_out = phys - region->phys;
137 break;
138 }
139 region = region->next;
140 }
141 }
6d536e4b 142 else if (phys < __pa(end_iomem) + highmem) {
1da177e4
LT
143 fd = physmem_fd;
144 *offset_out = phys - iomem_size;
145 }
146
60678bbc 147 return fd;
1da177e4
LT
148}
149
150static int __init uml_mem_setup(char *line, int *add)
151{
152 char *retptr;
153 physmem_size = memparse(line,&retptr);
154 return 0;
155}
156__uml_setup("mem=", uml_mem_setup,
157"mem=<Amount of desired ram>\n"
158" This controls how much \"physical\" memory the kernel allocates\n"
159" for the system. The size is specified as a number followed by\n"
160" one of 'k', 'K', 'm', 'M', which have the obvious meanings.\n"
161" This is not related to the amount of memory in the host. It can\n"
162" be more, and the excess, if it's ever used, will just be swapped out.\n"
163" Example: mem=64M\n\n"
164);
165
94c282d7
JD
166extern int __init parse_iomem(char *str, int *add);
167
168__uml_setup("iomem=", parse_iomem,
169"iomem=<name>,<file>\n"
170" Configure <file> as an IO memory region named <name>.\n\n"
171);
172
173/*
174 * This list is constructed in parse_iomem and addresses filled in in
175 * setup_iomem, both of which run during early boot. Afterwards, it's
176 * unchanged.
177 */
80e39311 178struct iomem_region *iomem_regions;
94c282d7 179
80e39311
JD
180/* Initialized in parse_iomem and unchanged thereafter */
181int iomem_size;
94c282d7 182
1da177e4
LT
183unsigned long find_iomem(char *driver, unsigned long *len_out)
184{
185 struct iomem_region *region = iomem_regions;
186
6d536e4b
JD
187 while (region != NULL) {
188 if (!strcmp(region->driver, driver)) {
1da177e4 189 *len_out = region->size;
60678bbc 190 return region->virt;
1da177e4 191 }
c39e50b4
VV
192
193 region = region->next;
1da177e4
LT
194 }
195
60678bbc 196 return 0;
1da177e4 197}
73395a00 198EXPORT_SYMBOL(find_iomem);
1da177e4 199
99764fa4 200static int setup_iomem(void)
1da177e4
LT
201{
202 struct iomem_region *region = iomem_regions;
203 unsigned long iomem_start = high_physmem + PAGE_SIZE;
204 int err;
205
6d536e4b 206 while (region != NULL) {
1da177e4
LT
207 err = os_map_memory((void *) iomem_start, region->fd, 0,
208 region->size, 1, 1, 0);
6d536e4b 209 if (err)
ba180fd4
JD
210 printk(KERN_ERR "Mapping iomem region for driver '%s' "
211 "failed, errno = %d\n", region->driver, -err);
1da177e4
LT
212 else {
213 region->virt = iomem_start;
214 region->phys = __pa(region->virt);
215 }
216
217 iomem_start += region->size + PAGE_SIZE;
218 region = region->next;
219 }
220
60678bbc 221 return 0;
1da177e4
LT
222}
223
224__initcall(setup_iomem);