blob: 8aeac4d9351168e30ba8fc978caf679fce47077d [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#include "linux/mm.h"
7#include "linux/rbtree.h"
8#include "linux/slab.h"
9#include "linux/vmalloc.h"
10#include "linux/bootmem.h"
11#include "linux/module.h"
Dave Hansen22a98352006-03-27 01:16:04 -080012#include "linux/pfn.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include "asm/types.h"
14#include "asm/pgtable.h"
15#include "kern_util.h"
Jeff Dike4ff83ce2007-05-06 14:51:08 -070016#include "as-layout.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include "mode_kern.h"
18#include "mem.h"
19#include "mem_user.h"
20#include "os.h"
21#include "kern.h"
22#include "init.h"
23
Linus Torvalds1da177e2005-04-16 15:20:36 -070024static int physmem_fd = -1;
25
Linus Torvalds1da177e2005-04-16 15:20:36 -070026/* Changed during early boot */
27unsigned long high_physmem;
28
Jeff Dikeae173812005-11-07 00:58:57 -080029extern unsigned long long physmem_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -070030
Jeff Dike97a1fcb2007-07-23 18:43:48 -070031int __init init_maps(unsigned long physmem, unsigned long iomem,
32 unsigned long highmem)
Linus Torvalds1da177e2005-04-16 15:20:36 -070033{
34 struct page *p, *map;
35 unsigned long phys_len, phys_pages, highmem_len, highmem_pages;
36 unsigned long iomem_len, iomem_pages, total_len, total_pages;
37 int i;
38
39 phys_pages = physmem >> PAGE_SHIFT;
40 phys_len = phys_pages * sizeof(struct page);
41
42 iomem_pages = iomem >> PAGE_SHIFT;
43 iomem_len = iomem_pages * sizeof(struct page);
44
45 highmem_pages = highmem >> PAGE_SHIFT;
46 highmem_len = highmem_pages * sizeof(struct page);
47
48 total_pages = phys_pages + iomem_pages + highmem_pages;
Paolo 'Blaisorblade' Giarrusso3dfd95b2006-02-01 03:06:26 -080049 total_len = phys_len + iomem_len + highmem_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -070050
Jeff Dike97a1fcb2007-07-23 18:43:48 -070051 map = alloc_bootmem_low_pages(total_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -070052 if(map == NULL)
Jeff Dike60678bb2007-02-10 01:44:10 -080053 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
55 for(i = 0; i < total_pages; i++){
56 p = &map[i];
Nick Piggin70dc9912006-03-22 00:08:35 -080057 memset(p, 0, sizeof(struct page));
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 SetPageReserved(p);
59 INIT_LIST_HEAD(&p->lru);
60 }
61
62 max_mapnr = total_pages;
Jeff Dike60678bb2007-02-10 01:44:10 -080063 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070064}
65
Linus Torvalds1da177e2005-04-16 15:20:36 -070066/* Changed during early boot */
67static unsigned long kmem_top = 0;
68
69unsigned long get_kmem_end(void)
70{
71 if(kmem_top == 0)
72 kmem_top = CHOOSE_MODE(kmem_end_tt, kmem_end_skas);
Jeff Dike60678bb2007-02-10 01:44:10 -080073 return kmem_top;
Linus Torvalds1da177e2005-04-16 15:20:36 -070074}
75
76void map_memory(unsigned long virt, unsigned long phys, unsigned long len,
77 int r, int w, int x)
78{
79 __u64 offset;
80 int fd, err;
81
82 fd = phys_mapping(phys, &offset);
83 err = os_map_memory((void *) virt, fd, offset, len, r, w, x);
84 if(err) {
85 if(err == -ENOMEM)
86 printk("try increasing the host's "
87 "/proc/sys/vm/max_map_count to <physical "
88 "memory size>/4096\n");
89 panic("map_memory(0x%lx, %d, 0x%llx, %ld, %d, %d, %d) failed, "
90 "err = %d\n", virt, fd, offset, len, r, w, x, err);
91 }
92}
93
Jeff Dike23bbd5862006-07-10 04:45:06 -070094extern int __syscall_stub_start;
Jeff Diked67b5692005-07-07 17:56:49 -070095
Jeff Dike97a1fcb2007-07-23 18:43:48 -070096void __init setup_physmem(unsigned long start, unsigned long reserve_end,
97 unsigned long len, unsigned long long highmem)
Linus Torvalds1da177e2005-04-16 15:20:36 -070098{
99 unsigned long reserve = reserve_end - start;
100 int pfn = PFN_UP(__pa(reserve_end));
101 int delta = (len - reserve) >> PAGE_SHIFT;
102 int err, offset, bootmap_size;
103
104 physmem_fd = create_mem_file(len + highmem);
105
106 offset = uml_reserved - uml_physmem;
107 err = os_map_memory((void *) uml_reserved, physmem_fd, offset,
Jeff Dike5c8aace2007-10-16 01:26:46 -0700108 len - offset, 1, 1, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 if(err < 0){
110 os_print_error(err, "Mapping memory");
111 exit(1);
112 }
113
Jeff Diked67b5692005-07-07 17:56:49 -0700114 /* Special kludge - This page will be mapped in to userspace processes
115 * from physmem_fd, so it needs to be written out there.
116 */
117 os_seek_file(physmem_fd, __pa(&__syscall_stub_start));
Jeff Dikea6ea4cc2007-05-06 14:51:43 -0700118 os_write_file(physmem_fd, &__syscall_stub_start, PAGE_SIZE);
Jeff Diked67b5692005-07-07 17:56:49 -0700119
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 bootmap_size = init_bootmem(pfn, pfn + delta);
121 free_bootmem(__pa(reserve_end) + bootmap_size,
122 len - bootmap_size - reserve);
123}
124
125int phys_mapping(unsigned long phys, __u64 *offset_out)
126{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 int fd = -1;
128
Jeff Dike16dd07b2007-05-06 14:51:48 -0700129 if(phys < physmem_size){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 fd = physmem_fd;
131 *offset_out = phys;
132 }
133 else if(phys < __pa(end_iomem)){
134 struct iomem_region *region = iomem_regions;
135
136 while(region != NULL){
137 if((phys >= region->phys) &&
138 (phys < region->phys + region->size)){
139 fd = region->fd;
140 *offset_out = phys - region->phys;
141 break;
142 }
143 region = region->next;
144 }
145 }
146 else if(phys < __pa(end_iomem) + highmem){
147 fd = physmem_fd;
148 *offset_out = phys - iomem_size;
149 }
150
Jeff Dike60678bb2007-02-10 01:44:10 -0800151 return fd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152}
153
154static int __init uml_mem_setup(char *line, int *add)
155{
156 char *retptr;
157 physmem_size = memparse(line,&retptr);
158 return 0;
159}
160__uml_setup("mem=", uml_mem_setup,
161"mem=<Amount of desired ram>\n"
162" This controls how much \"physical\" memory the kernel allocates\n"
163" for the system. The size is specified as a number followed by\n"
164" one of 'k', 'K', 'm', 'M', which have the obvious meanings.\n"
165" This is not related to the amount of memory in the host. It can\n"
166" be more, and the excess, if it's ever used, will just be swapped out.\n"
167" Example: mem=64M\n\n"
168);
169
Jeff Dike94c282d2007-02-10 01:44:09 -0800170extern int __init parse_iomem(char *str, int *add);
171
172__uml_setup("iomem=", parse_iomem,
173"iomem=<name>,<file>\n"
174" Configure <file> as an IO memory region named <name>.\n\n"
175);
176
177/*
178 * This list is constructed in parse_iomem and addresses filled in in
179 * setup_iomem, both of which run during early boot. Afterwards, it's
180 * unchanged.
181 */
182struct iomem_region *iomem_regions = NULL;
183
184/* Initialized in parse_iomem */
185int iomem_size = 0;
186
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187unsigned long find_iomem(char *driver, unsigned long *len_out)
188{
189 struct iomem_region *region = iomem_regions;
190
191 while(region != NULL){
192 if(!strcmp(region->driver, driver)){
193 *len_out = region->size;
Jeff Dike60678bb2007-02-10 01:44:10 -0800194 return region->virt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 }
Victor V. Vengerovc39e50b2006-05-01 12:15:53 -0700196
197 region = region->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 }
199
Jeff Dike60678bb2007-02-10 01:44:10 -0800200 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201}
202
203int setup_iomem(void)
204{
205 struct iomem_region *region = iomem_regions;
206 unsigned long iomem_start = high_physmem + PAGE_SIZE;
207 int err;
208
209 while(region != NULL){
210 err = os_map_memory((void *) iomem_start, region->fd, 0,
211 region->size, 1, 1, 0);
212 if(err)
213 printk("Mapping iomem region for driver '%s' failed, "
214 "errno = %d\n", region->driver, -err);
215 else {
216 region->virt = iomem_start;
217 region->phys = __pa(region->virt);
218 }
219
220 iomem_start += region->size + PAGE_SIZE;
221 region = region->next;
222 }
223
Jeff Dike60678bb2007-02-10 01:44:10 -0800224 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225}
226
227__initcall(setup_iomem);