linux/arch/um/kernel/physmem.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
   3 * Licensed under the GPL
   4 */
   5
   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>
  11#include <as-layout.h>
  12#include <init.h>
  13#include <kern.h>
  14#include <mem_user.h>
  15#include <os.h>
  16
  17static int physmem_fd = -1;
  18
  19/* Changed during early boot */
  20unsigned long high_physmem;
  21EXPORT_SYMBOL(high_physmem);
  22
  23extern unsigned long long physmem_size;
  24
  25int __init init_maps(unsigned long physmem, unsigned long iomem,
  26                     unsigned long highmem)
  27{
  28        struct page *p, *map;
  29        unsigned long phys_len, phys_pages, highmem_len, highmem_pages;
  30        unsigned long iomem_len, iomem_pages, total_len, total_pages;
  31        int i;
  32
  33        phys_pages = physmem >> PAGE_SHIFT;
  34        phys_len = phys_pages * sizeof(struct page);
  35
  36        iomem_pages = iomem >> PAGE_SHIFT;
  37        iomem_len = iomem_pages * sizeof(struct page);
  38
  39        highmem_pages = highmem >> PAGE_SHIFT;
  40        highmem_len = highmem_pages * sizeof(struct page);
  41
  42        total_pages = phys_pages + iomem_pages + highmem_pages;
  43        total_len = phys_len + iomem_len + highmem_len;
  44
  45        map = alloc_bootmem_low_pages(total_len);
  46        if (map == NULL)
  47                return -ENOMEM;
  48
  49        for (i = 0; i < total_pages; i++) {
  50                p = &map[i];
  51                memset(p, 0, sizeof(struct page));
  52                SetPageReserved(p);
  53                INIT_LIST_HEAD(&p->lru);
  54        }
  55
  56        max_mapnr = total_pages;
  57        return 0;
  58}
  59
  60void map_memory(unsigned long virt, unsigned long phys, unsigned long len,
  61                int r, int w, int x)
  62{
  63        __u64 offset;
  64        int fd, err;
  65
  66        fd = phys_mapping(phys, &offset);
  67        err = os_map_memory((void *) virt, fd, offset, len, r, w, x);
  68        if (err) {
  69                if (err == -ENOMEM)
  70                        printk(KERN_ERR "try increasing the host's "
  71                               "/proc/sys/vm/max_map_count to <physical "
  72                               "memory size>/4096\n");
  73                panic("map_memory(0x%lx, %d, 0x%llx, %ld, %d, %d, %d) failed, "
  74                      "err = %d\n", virt, fd, offset, len, r, w, x, err);
  75        }
  76}
  77
  78extern int __syscall_stub_start;
  79
  80void __init setup_physmem(unsigned long start, unsigned long reserve_end,
  81                          unsigned long len, unsigned long long highmem)
  82{
  83        unsigned long reserve = reserve_end - start;
  84        int pfn = PFN_UP(__pa(reserve_end));
  85        int delta = (len - reserve) >> PAGE_SHIFT;
  86        int err, offset, bootmap_size;
  87
  88        physmem_fd = create_mem_file(len + highmem);
  89
  90        offset = uml_reserved - uml_physmem;
  91        err = os_map_memory((void *) uml_reserved, physmem_fd, offset,
  92                            len - offset, 1, 1, 1);
  93        if (err < 0) {
  94                printf("setup_physmem - mapping %ld bytes of memory at 0x%p "
  95                       "failed - errno = %d\n", len - offset,
  96                       (void *) uml_reserved, err);
  97                exit(1);
  98        }
  99
 100        /*
 101         * Special kludge - This page will be mapped in to userspace processes
 102         * from physmem_fd, so it needs to be written out there.
 103         */
 104        os_seek_file(physmem_fd, __pa(&__syscall_stub_start));
 105        os_write_file(physmem_fd, &__syscall_stub_start, PAGE_SIZE);
 106
 107        bootmap_size = init_bootmem(pfn, pfn + delta);
 108        free_bootmem(__pa(reserve_end) + bootmap_size,
 109                     len - bootmap_size - reserve);
 110}
 111
 112int 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        else if (phys < __pa(end_iomem) + highmem) {
 134                fd = physmem_fd;
 135                *offset_out = phys - iomem_size;
 136        }
 137
 138        return fd;
 139}
 140
 141static int __init uml_mem_setup(char *line, int *add)
 142{
 143        char *retptr;
 144        physmem_size = memparse(line,&retptr);
 145        return 0;
 146}
 147__uml_setup("mem=", uml_mem_setup,
 148"mem=<Amount of desired ram>\n"
 149"    This controls how much \"physical\" memory the kernel allocates\n"
 150"    for the system. The size is specified as a number followed by\n"
 151"    one of 'k', 'K', 'm', 'M', which have the obvious meanings.\n"
 152"    This is not related to the amount of memory in the host.  It can\n"
 153"    be more, and the excess, if it's ever used, will just be swapped out.\n"
 154"       Example: mem=64M\n\n"
 155);
 156
 157extern int __init parse_iomem(char *str, int *add);
 158
 159__uml_setup("iomem=", parse_iomem,
 160"iomem=<name>,<file>\n"
 161"    Configure <file> as an IO memory region named <name>.\n\n"
 162);
 163
 164/*
 165 * This list is constructed in parse_iomem and addresses filled in in
 166 * setup_iomem, both of which run during early boot.  Afterwards, it's
 167 * unchanged.
 168 */
 169struct iomem_region *iomem_regions;
 170
 171/* Initialized in parse_iomem and unchanged thereafter */
 172int iomem_size;
 173
 174unsigned long find_iomem(char *driver, unsigned long *len_out)
 175{
 176        struct iomem_region *region = iomem_regions;
 177
 178        while (region != NULL) {
 179                if (!strcmp(region->driver, driver)) {
 180                        *len_out = region->size;
 181                        return region->virt;
 182                }
 183
 184                region = region->next;
 185        }
 186
 187        return 0;
 188}
 189EXPORT_SYMBOL(find_iomem);
 190
 191static int setup_iomem(void)
 192{
 193        struct iomem_region *region = iomem_regions;
 194        unsigned long iomem_start = high_physmem + PAGE_SIZE;
 195        int err;
 196
 197        while (region != NULL) {
 198                err = os_map_memory((void *) iomem_start, region->fd, 0,
 199                                    region->size, 1, 1, 0);
 200                if (err)
 201                        printk(KERN_ERR "Mapping iomem region for driver '%s' "
 202                               "failed, errno = %d\n", region->driver, -err);
 203                else {
 204                        region->virt = iomem_start;
 205                        region->phys = __pa(region->virt);
 206                }
 207
 208                iomem_start += region->size + PAGE_SIZE;
 209                region = region->next;
 210        }
 211
 212        return 0;
 213}
 214
 215__initcall(setup_iomem);
 216