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 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 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 */ 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 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 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 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 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