physmem.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. /*
  2. * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  3. * Licensed under the GPL
  4. */
  5. #include <linux/module.h>
  6. #include <linux/bootmem.h>
  7. #include <linux/mm.h>
  8. #include <linux/pfn.h>
  9. #include <asm/page.h>
  10. #include <as-layout.h>
  11. #include <init.h>
  12. #include <kern.h>
  13. #include <mem_user.h>
  14. #include <os.h>
  15. static int physmem_fd = -1;
  16. /* Changed during early boot */
  17. unsigned long high_physmem;
  18. EXPORT_SYMBOL(high_physmem);
  19. extern unsigned long long physmem_size;
  20. void __init mem_total_pages(unsigned long physmem, unsigned long iomem,
  21. unsigned long highmem)
  22. {
  23. unsigned long phys_pages, highmem_pages;
  24. unsigned long iomem_pages, total_pages;
  25. phys_pages = physmem >> PAGE_SHIFT;
  26. iomem_pages = iomem >> PAGE_SHIFT;
  27. highmem_pages = highmem >> PAGE_SHIFT;
  28. total_pages = phys_pages + iomem_pages + highmem_pages;
  29. max_mapnr = total_pages;
  30. }
  31. void map_memory(unsigned long virt, unsigned long phys, unsigned long len,
  32. int r, int w, int x)
  33. {
  34. __u64 offset;
  35. int fd, err;
  36. fd = phys_mapping(phys, &offset);
  37. err = os_map_memory((void *) virt, fd, offset, len, r, w, x);
  38. if (err) {
  39. if (err == -ENOMEM)
  40. printk(KERN_ERR "try increasing the host's "
  41. "/proc/sys/vm/max_map_count to <physical "
  42. "memory size>/4096\n");
  43. panic("map_memory(0x%lx, %d, 0x%llx, %ld, %d, %d, %d) failed, "
  44. "err = %d\n", virt, fd, offset, len, r, w, x, err);
  45. }
  46. }
  47. extern int __syscall_stub_start;
  48. void __init setup_physmem(unsigned long start, unsigned long reserve_end,
  49. unsigned long len, unsigned long long highmem)
  50. {
  51. unsigned long reserve = reserve_end - start;
  52. int pfn = PFN_UP(__pa(reserve_end));
  53. int delta = (len - reserve) >> PAGE_SHIFT;
  54. int err, offset, bootmap_size;
  55. physmem_fd = create_mem_file(len + highmem);
  56. offset = uml_reserved - uml_physmem;
  57. err = os_map_memory((void *) uml_reserved, physmem_fd, offset,
  58. len - offset, 1, 1, 1);
  59. if (err < 0) {
  60. printf("setup_physmem - mapping %ld bytes of memory at 0x%p "
  61. "failed - errno = %d\n", len - offset,
  62. (void *) uml_reserved, err);
  63. exit(1);
  64. }
  65. /*
  66. * Special kludge - This page will be mapped in to userspace processes
  67. * from physmem_fd, so it needs to be written out there.
  68. */
  69. os_seek_file(physmem_fd, __pa(&__syscall_stub_start));
  70. os_write_file(physmem_fd, &__syscall_stub_start, PAGE_SIZE);
  71. os_fsync_file(physmem_fd);
  72. bootmap_size = init_bootmem(pfn, pfn + delta);
  73. free_bootmem(__pa(reserve_end) + bootmap_size,
  74. len - bootmap_size - reserve);
  75. }
  76. int phys_mapping(unsigned long phys, unsigned long long *offset_out)
  77. {
  78. int fd = -1;
  79. if (phys < physmem_size) {
  80. fd = physmem_fd;
  81. *offset_out = phys;
  82. }
  83. else if (phys < __pa(end_iomem)) {
  84. struct iomem_region *region = iomem_regions;
  85. while (region != NULL) {
  86. if ((phys >= region->phys) &&
  87. (phys < region->phys + region->size)) {
  88. fd = region->fd;
  89. *offset_out = phys - region->phys;
  90. break;
  91. }
  92. region = region->next;
  93. }
  94. }
  95. else if (phys < __pa(end_iomem) + highmem) {
  96. fd = physmem_fd;
  97. *offset_out = phys - iomem_size;
  98. }
  99. return fd;
  100. }
  101. static int __init uml_mem_setup(char *line, int *add)
  102. {
  103. char *retptr;
  104. physmem_size = memparse(line,&retptr);
  105. return 0;
  106. }
  107. __uml_setup("mem=", uml_mem_setup,
  108. "mem=<Amount of desired ram>\n"
  109. " This controls how much \"physical\" memory the kernel allocates\n"
  110. " for the system. The size is specified as a number followed by\n"
  111. " one of 'k', 'K', 'm', 'M', which have the obvious meanings.\n"
  112. " This is not related to the amount of memory in the host. It can\n"
  113. " be more, and the excess, if it's ever used, will just be swapped out.\n"
  114. " Example: mem=64M\n\n"
  115. );
  116. extern int __init parse_iomem(char *str, int *add);
  117. __uml_setup("iomem=", parse_iomem,
  118. "iomem=<name>,<file>\n"
  119. " Configure <file> as an IO memory region named <name>.\n\n"
  120. );
  121. /*
  122. * This list is constructed in parse_iomem and addresses filled in in
  123. * setup_iomem, both of which run during early boot. Afterwards, it's
  124. * unchanged.
  125. */
  126. struct iomem_region *iomem_regions;
  127. /* Initialized in parse_iomem and unchanged thereafter */
  128. int iomem_size;
  129. unsigned long find_iomem(char *driver, unsigned long *len_out)
  130. {
  131. struct iomem_region *region = iomem_regions;
  132. while (region != NULL) {
  133. if (!strcmp(region->driver, driver)) {
  134. *len_out = region->size;
  135. return region->virt;
  136. }
  137. region = region->next;
  138. }
  139. return 0;
  140. }
  141. EXPORT_SYMBOL(find_iomem);
  142. static int setup_iomem(void)
  143. {
  144. struct iomem_region *region = iomem_regions;
  145. unsigned long iomem_start = high_physmem + PAGE_SIZE;
  146. int err;
  147. while (region != NULL) {
  148. err = os_map_memory((void *) iomem_start, region->fd, 0,
  149. region->size, 1, 1, 0);
  150. if (err)
  151. printk(KERN_ERR "Mapping iomem region for driver '%s' "
  152. "failed, errno = %d\n", region->driver, -err);
  153. else {
  154. region->virt = iomem_start;
  155. region->phys = __pa(region->virt);
  156. }
  157. iomem_start += region->size + PAGE_SIZE;
  158. region = region->next;
  159. }
  160. return 0;
  161. }
  162. __initcall(setup_iomem);