LCOV - code coverage report
Current view: top level - arch/um/kernel - physmem.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 41 75 54.7 %
Date: 2023-04-06 08:38:28 Functions: 6 7 85.7 %

          Line data    Source code
       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 <mem_user.h>
      16             : #include <os.h>
      17             : 
      18             : static int physmem_fd = -1;
      19             : 
      20             : /* Changed during early boot */
      21             : unsigned long high_physmem;
      22             : EXPORT_SYMBOL(high_physmem);
      23             : 
      24             : extern unsigned long long physmem_size;
      25             : 
      26           1 : void __init mem_total_pages(unsigned long physmem, unsigned long iomem,
      27             :                      unsigned long highmem)
      28             : {
      29             :         unsigned long phys_pages, highmem_pages;
      30             :         unsigned long iomem_pages, total_pages;
      31             : 
      32           1 :         phys_pages    = physmem >> PAGE_SHIFT;
      33           1 :         iomem_pages   = iomem   >> PAGE_SHIFT;
      34           1 :         highmem_pages = highmem >> PAGE_SHIFT;
      35             : 
      36           1 :         total_pages   = phys_pages + iomem_pages + highmem_pages;
      37             : 
      38           1 :         max_mapnr = total_pages;
      39           1 : }
      40             : 
      41       85019 : void 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       85019 :         fd = phys_mapping(phys, &offset);
      48       85019 :         err = os_map_memory((void *) virt, fd, offset, len, r, w, x);
      49       85019 :         if (err) {
      50           0 :                 if (err == -ENOMEM)
      51           0 :                         printk(KERN_ERR "try increasing the host's "
      52             :                                "/proc/sys/vm/max_map_count to <physical "
      53             :                                "memory size>/4096\n");
      54           0 :                 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       85019 : }
      58             : 
      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             :  */
      79           1 : void __init setup_physmem(unsigned long start, unsigned long reserve_end,
      80             :                           unsigned long len, unsigned long long highmem)
      81             : {
      82           1 :         unsigned long reserve = reserve_end - start;
      83           1 :         long map_size = len - reserve;
      84             :         int err;
      85             : 
      86           1 :         if(map_size <= 0) {
      87           0 :                 os_warn("Too few physical memory! Needed=%lu, given=%lu\n",
      88             :                         reserve, len);
      89           0 :                 exit(1);
      90             :         }
      91             : 
      92           1 :         physmem_fd = create_mem_file(len + highmem);
      93             : 
      94           1 :         err = os_map_memory((void *) reserve_end, physmem_fd, reserve,
      95             :                             map_size, 1, 1, 1);
      96           1 :         if (err < 0) {
      97           0 :                 os_warn("setup_physmem - mapping %ld bytes of memory at 0x%p "
      98             :                         "failed - errno = %d\n", map_size,
      99             :                         (void *) reserve_end, err);
     100           0 :                 exit(1);
     101             :         }
     102             : 
     103             :         /*
     104             :          * Special kludge - This page will be mapped in to userspace processes
     105             :          * from physmem_fd, so it needs to be written out there.
     106             :          */
     107           1 :         os_seek_file(physmem_fd, __pa(__syscall_stub_start));
     108           1 :         os_write_file(physmem_fd, __syscall_stub_start, PAGE_SIZE);
     109           1 :         os_fsync_file(physmem_fd);
     110             : 
     111           2 :         memblock_add(__pa(start), len + highmem);
     112           2 :         memblock_reserve(__pa(start), reserve);
     113             : 
     114           2 :         min_low_pfn = PFN_UP(__pa(reserve_end));
     115           1 :         max_low_pfn = min_low_pfn + (map_size >> PAGE_SHIFT);
     116           1 : }
     117             : 
     118       85019 : int phys_mapping(unsigned long phys, unsigned long long *offset_out)
     119             : {
     120       85019 :         int fd = -1;
     121             : 
     122       85019 :         if (phys < physmem_size) {
     123       85019 :                 fd = physmem_fd;
     124       85019 :                 *offset_out = phys;
     125             :         }
     126           0 :         else if (phys < __pa(end_iomem)) {
     127           0 :                 struct iomem_region *region = iomem_regions;
     128             : 
     129           0 :                 while (region != NULL) {
     130           0 :                         if ((phys >= region->phys) &&
     131           0 :                             (phys < region->phys + region->size)) {
     132           0 :                                 fd = region->fd;
     133           0 :                                 *offset_out = phys - region->phys;
     134           0 :                                 break;
     135             :                         }
     136           0 :                         region = region->next;
     137             :                 }
     138             :         }
     139           0 :         else if (phys < __pa(end_iomem) + highmem) {
     140           0 :                 fd = physmem_fd;
     141           0 :                 *offset_out = phys - iomem_size;
     142             :         }
     143             : 
     144       85019 :         return fd;
     145             : }
     146             : EXPORT_SYMBOL(phys_mapping);
     147             : 
     148           5 : static int __init uml_mem_setup(char *line, int *add)
     149             : {
     150             :         char *retptr;
     151           5 :         physmem_size = memparse(line,&retptr);
     152           5 :         return 0;
     153             : }
     154             : __uml_setup("mem=", uml_mem_setup,
     155             : "mem=<Amount of desired ram>\n"
     156             : "    This controls how much \"physical\" memory the kernel allocates\n"
     157             : "    for the system. The size is specified as a number followed by\n"
     158             : "    one of 'k', 'K', 'm', 'M', which have the obvious meanings.\n"
     159             : "    This is not related to the amount of memory in the host.  It can\n"
     160             : "    be more, and the excess, if it's ever used, will just be swapped out.\n"
     161             : "  Example: mem=64M\n\n"
     162             : );
     163             : 
     164             : extern int __init parse_iomem(char *str, int *add);
     165             : 
     166             : __uml_setup("iomem=", parse_iomem,
     167             : "iomem=<name>,<file>\n"
     168             : "    Configure <file> as an IO memory region named <name>.\n\n"
     169             : );
     170             : 
     171             : /*
     172             :  * This list is constructed in parse_iomem and addresses filled in
     173             :  * setup_iomem, both of which run during early boot.  Afterwards, it's
     174             :  * unchanged.
     175             :  */
     176             : struct iomem_region *iomem_regions;
     177             : 
     178             : /* Initialized in parse_iomem and unchanged thereafter */
     179             : int iomem_size;
     180             : 
     181           0 : unsigned long find_iomem(char *driver, unsigned long *len_out)
     182             : {
     183           0 :         struct iomem_region *region = iomem_regions;
     184             : 
     185           0 :         while (region != NULL) {
     186           0 :                 if (!strcmp(region->driver, driver)) {
     187           0 :                         *len_out = region->size;
     188           0 :                         return region->virt;
     189             :                 }
     190             : 
     191           0 :                 region = region->next;
     192             :         }
     193             : 
     194             :         return 0;
     195             : }
     196             : EXPORT_SYMBOL(find_iomem);
     197             : 
     198           1 : static int setup_iomem(void)
     199             : {
     200           1 :         struct iomem_region *region = iomem_regions;
     201           1 :         unsigned long iomem_start = high_physmem + PAGE_SIZE;
     202             :         int err;
     203             : 
     204           2 :         while (region != NULL) {
     205           0 :                 err = os_map_memory((void *) iomem_start, region->fd, 0,
     206           0 :                                     region->size, 1, 1, 0);
     207           0 :                 if (err)
     208           0 :                         printk(KERN_ERR "Mapping iomem region for driver '%s' "
     209             :                                "failed, errno = %d\n", region->driver, -err);
     210             :                 else {
     211           0 :                         region->virt = iomem_start;
     212           0 :                         region->phys = __pa(region->virt);
     213             :                 }
     214             : 
     215           0 :                 iomem_start += region->size + PAGE_SIZE;
     216           0 :                 region = region->next;
     217             :         }
     218             : 
     219           1 :         return 0;
     220             : }
     221             : 
     222             : __initcall(setup_iomem);

Generated by: LCOV version 1.14