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