| 1 | |
| 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 |
|
| 22 | unsigned long high_physmem;
|
| 23 | EXPORT_SYMBOL(high_physmem);
|
| 24 |
|
| 25 | void map_memory(unsigned long virt, unsigned long phys, unsigned long len,
|
| 26 | int r, int w, int x)
|
| 27 | {
|
| 28 | __u64 offset;
|
| 29 | int fd, err;
|
| 30 |
|
| 31 | fd = phys_mapping(phys, &offset);
|
| 32 | err = os_map_memory((void *) virt, fd, offset, len, r, w, x);
|
| 33 | if (err) {
|
| 34 | if (err == -ENOMEM)
|
| 35 | printk(KERN_ERR "try increasing the host's "
|
| 36 | "/proc/sys/vm/max_map_count to <physical "
|
| 37 | "memory size>/4096\n");
|
| 38 | panic("map_memory(0x%lx, %d, 0x%llx, %ld, %d, %d, %d) failed, "
|
| 39 | "err = %d\n", virt, fd, offset, len, r, w, x, err);
|
| 40 | }
|
| 41 | }
|
| 42 |
|
| 43 | |
| 44 | * setup_physmem() - Setup physical memory for UML
|
| 45 | * @start: Start address of the physical kernel memory,
|
| 46 | * i.e start address of the executable image.
|
| 47 | * @reserve_end: end address of the physical kernel memory.
|
| 48 | * @len: Length of total physical memory that should be mapped/made
|
| 49 | * available, in bytes.
|
| 50 | *
|
| 51 | * Creates an unlinked temporary file of size (len) and memory maps
|
| 52 | * it on the last executable image address (uml_reserved).
|
| 53 | *
|
| 54 | * The offset is needed as the length of the total physical memory
|
| 55 | * (len) includes the size of the memory used be the executable image,
|
| 56 | * but the mapped-to address is the last address of the executable image
|
| 57 | * (uml_reserved == end address of executable image).
|
| 58 | *
|
| 59 | * The memory mapped memory of the temporary file is used as backing memory
|
| 60 | * of all user space processes/kernel tasks.
|
| 61 |
|
| 62 | void __init setup_physmem(unsigned long start, unsigned long reserve_end,
|
| 63 | unsigned long len)
|
| 64 | {
|
| 65 | unsigned long reserve = reserve_end - start;
|
| 66 | unsigned long map_size = len - reserve;
|
| 67 | int err;
|
| 68 |
|
| 69 | if (len <= reserve) {
|
| 70 | os_warn("Too few physical memory! Needed=%lu, given=%lu\n",
|
| 71 | reserve, len);
|
| 72 | exit(1);
|
| 73 | }
|
| 74 |
|
| 75 | physmem_fd = create_mem_file(len);
|
| 76 |
|
| 77 | err = os_map_memory((void *) reserve_end, physmem_fd, reserve,
|
| 78 | map_size, 1, 1, 1);
|
| 79 | if (err < 0) {
|
| 80 | os_warn("setup_physmem - mapping %lu bytes of memory at 0x%p "
|
| 81 | "failed - errno = %d\n", map_size,
|
| 82 | (void *) reserve_end, err);
|
| 83 | exit(1);
|
| 84 | }
|
| 85 |
|
| 86 | |
| 87 | * Special kludge - This page will be mapped in to userspace processes
|
| 88 | * from physmem_fd, so it needs to be written out there.
|
| 89 |
|
| 90 | os_seek_file(physmem_fd, __pa(__syscall_stub_start));
|
| 91 | os_write_file(physmem_fd, __syscall_stub_start, PAGE_SIZE);
|
| 92 |
|
| 93 | memblock_add(__pa(start), len);
|
| 94 | memblock_reserve(__pa(start), reserve);
|
| 95 |
|
| 96 | min_low_pfn = PFN_UP(__pa(reserve_end));
|
| 97 | max_low_pfn = min_low_pfn + (map_size >> PAGE_SHIFT);
|
| 98 | }
|
| 99 |
|
| 100 | int phys_mapping(unsigned long phys, unsigned long long *offset_out)
|
| 101 | {
|
| 102 | int fd = -1;
|
| 103 |
|
| 104 | if (phys < physmem_size) {
|
| 105 | fd = physmem_fd;
|
| 106 | *offset_out = phys;
|
| 107 | }
|
| 108 |
|
| 109 | return fd;
|
| 110 | }
|
| 111 | EXPORT_SYMBOL(phys_mapping);
|
| 112 |
|
| 113 | static int __init uml_mem_setup(char *line, int *add)
|
| 114 | {
|
| 115 | char *retptr;
|
| 116 |
|
| 117 | *add = 0;
|
| 118 | physmem_size = memparse(line,&retptr);
|
| 119 | return 0;
|
| 120 | }
|
| 121 | __uml_setup("mem=", uml_mem_setup,
|
| 122 | "mem=<Amount of desired ram>\n"
|
| 123 | " This controls how much \"physical\" memory the kernel allocates\n"
|
| 124 | " for the system. The size is specified as a number followed by\n"
|
| 125 | " one of 'k', 'K', 'm', 'M', which have the obvious meanings.\n"
|
| 126 | " This is not related to the amount of memory in the host. It can\n"
|
| 127 | " be more, and the excess, if it's ever used, will just be swapped out.\n"
|
| 128 | " Example: mem=64M\n\n"
|
| 129 | );
|