Blame view

arch/um/kernel/physmem.c 5.35 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
6d536e4b5   Jeff Dike   uml: physmem code...
2
   * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
4
   * Licensed under the GPL
   */
73395a000   Al Viro   um: distribute ex...
5
6
7
8
9
10
11
12
13
14
  #include <linux/module.h>
  #include <linux/bootmem.h>
  #include <linux/mm.h>
  #include <linux/pfn.h>
  #include <asm/page.h>
  #include <as-layout.h>
  #include <init.h>
  #include <kern.h>
  #include <mem_user.h>
  #include <os.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
  static int physmem_fd = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
  /* Changed during early boot */
  unsigned long high_physmem;
73395a000   Al Viro   um: distribute ex...
19
  EXPORT_SYMBOL(high_physmem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20

ae1738160   Jeff Dike   [PATCH] uml: big ...
21
  extern unsigned long long physmem_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22

97a1fcbb2   Jeff Dike   uml: more __init ...
23
24
  int __init init_maps(unsigned long physmem, unsigned long iomem,
  		     unsigned long highmem)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
  {
  	struct page *p, *map;
  	unsigned long phys_len, phys_pages, highmem_len, highmem_pages;
  	unsigned long iomem_len, iomem_pages, total_len, total_pages;
  	int i;
  
  	phys_pages = physmem >> PAGE_SHIFT;
  	phys_len = phys_pages * sizeof(struct page);
  
  	iomem_pages = iomem >> PAGE_SHIFT;
  	iomem_len = iomem_pages * sizeof(struct page);
  
  	highmem_pages = highmem >> PAGE_SHIFT;
  	highmem_len = highmem_pages * sizeof(struct page);
  
  	total_pages = phys_pages + iomem_pages + highmem_pages;
3dfd95b37   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: fix ...
41
  	total_len = phys_len + iomem_len + highmem_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42

97a1fcbb2   Jeff Dike   uml: more __init ...
43
  	map = alloc_bootmem_low_pages(total_len);
6d536e4b5   Jeff Dike   uml: physmem code...
44
  	if (map == NULL)
60678bbc7   Jeff Dike   [PATCH] uml: mem....
45
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46

6d536e4b5   Jeff Dike   uml: physmem code...
47
  	for (i = 0; i < total_pages; i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
  		p = &map[i];
70dc991d6   Nick Piggin   [PATCH] remove se...
49
  		memset(p, 0, sizeof(struct page));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
51
52
53
54
  		SetPageReserved(p);
  		INIT_LIST_HEAD(&p->lru);
  	}
  
  	max_mapnr = total_pages;
60678bbc7   Jeff Dike   [PATCH] uml: mem....
55
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
59
60
61
62
63
64
  void map_memory(unsigned long virt, unsigned long phys, unsigned long len,
  		int r, int w, int x)
  {
  	__u64 offset;
  	int fd, err;
  
  	fd = phys_mapping(phys, &offset);
  	err = os_map_memory((void *) virt, fd, offset, len, r, w, x);
6d536e4b5   Jeff Dike   uml: physmem code...
65
66
  	if (err) {
  		if (err == -ENOMEM)
ba180fd43   Jeff Dike   uml: style fixes ...
67
  			printk(KERN_ERR "try increasing the host's "
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
69
70
71
72
73
74
75
  			       "/proc/sys/vm/max_map_count to <physical "
  			       "memory size>/4096
  ");
  		panic("map_memory(0x%lx, %d, 0x%llx, %ld, %d, %d, %d) failed, "
  		      "err = %d
  ", virt, fd, offset, len, r, w, x, err);
  	}
  }
23bbd586e   Jeff Dike   [PATCH] uml: fix ...
76
  extern int __syscall_stub_start;
d67b569f5   Jeff Dike   [PATCH] uml: skas...
77

97a1fcbb2   Jeff Dike   uml: more __init ...
78
79
  void __init setup_physmem(unsigned long start, unsigned long reserve_end,
  			  unsigned long len, unsigned long long highmem)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80
81
82
83
84
85
86
87
88
89
  {
  	unsigned long reserve = reserve_end - start;
  	int pfn = PFN_UP(__pa(reserve_end));
  	int delta = (len - reserve) >> PAGE_SHIFT;
  	int err, offset, bootmap_size;
  
  	physmem_fd = create_mem_file(len + highmem);
  
  	offset = uml_reserved - uml_physmem;
  	err = os_map_memory((void *) uml_reserved, physmem_fd, offset,
5c8aaceab   Jeff Dike   uml: stop special...
90
  			    len - offset, 1, 1, 1);
6d536e4b5   Jeff Dike   uml: physmem code...
91
  	if (err < 0) {
512b6fb1c   Jeff Dike   uml: userspace fi...
92
93
94
95
  		printf("setup_physmem - mapping %ld bytes of memory at 0x%p "
  		       "failed - errno = %d
  ", len - offset,
  		       (void *) uml_reserved, err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
97
  		exit(1);
  	}
ba180fd43   Jeff Dike   uml: style fixes ...
98
99
  	/*
  	 * Special kludge - This page will be mapped in to userspace processes
d67b569f5   Jeff Dike   [PATCH] uml: skas...
100
101
102
  	 * from physmem_fd, so it needs to be written out there.
  	 */
  	os_seek_file(physmem_fd, __pa(&__syscall_stub_start));
a6ea4ccee   Jeff Dike   uml: rename os_{r...
103
  	os_write_file(physmem_fd, &__syscall_stub_start, PAGE_SIZE);
d67b569f5   Jeff Dike   [PATCH] uml: skas...
104

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
106
107
108
  	bootmap_size = init_bootmem(pfn, pfn + delta);
  	free_bootmem(__pa(reserve_end) + bootmap_size,
  		     len - bootmap_size - reserve);
  }
0a7675aa2   Jeff Dike   uml: remove __u64...
109
  int phys_mapping(unsigned long phys, unsigned long long *offset_out)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
111
  	int fd = -1;
6d536e4b5   Jeff Dike   uml: physmem code...
112
  	if (phys < physmem_size) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
114
115
  		fd = physmem_fd;
  		*offset_out = phys;
  	}
6d536e4b5   Jeff Dike   uml: physmem code...
116
  	else if (phys < __pa(end_iomem)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117
  		struct iomem_region *region = iomem_regions;
6d536e4b5   Jeff Dike   uml: physmem code...
118
119
120
  		while (region != NULL) {
  			if ((phys >= region->phys) &&
  			    (phys < region->phys + region->size)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
122
123
124
125
126
127
  				fd = region->fd;
  				*offset_out = phys - region->phys;
  				break;
  			}
  			region = region->next;
  		}
  	}
6d536e4b5   Jeff Dike   uml: physmem code...
128
  	else if (phys < __pa(end_iomem) + highmem) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
130
131
  		fd = physmem_fd;
  		*offset_out = phys - iomem_size;
  	}
60678bbc7   Jeff Dike   [PATCH] uml: mem....
132
  	return fd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
  }
  
  static int __init uml_mem_setup(char *line, int *add)
  {
  	char *retptr;
  	physmem_size = memparse(line,&retptr);
  	return 0;
  }
  __uml_setup("mem=", uml_mem_setup,
  "mem=<Amount of desired ram>
  "
  "    This controls how much \"physical\" memory the kernel allocates
  "
  "    for the system. The size is specified as a number followed by
  "
  "    one of 'k', 'K', 'm', 'M', which have the obvious meanings.
  "
  "    This is not related to the amount of memory in the host.  It can
  "
  "    be more, and the excess, if it's ever used, will just be swapped out.
  "
  "	Example: mem=64M
  
  "
  );
94c282d79   Jeff Dike   [PATCH] uml: lock...
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
  extern int __init parse_iomem(char *str, int *add);
  
  __uml_setup("iomem=", parse_iomem,
  "iomem=<name>,<file>
  "
  "    Configure <file> as an IO memory region named <name>.
  
  "
  );
  
  /*
   * This list is constructed in parse_iomem and addresses filled in in
   * setup_iomem, both of which run during early boot.  Afterwards, it's
   * unchanged.
   */
80e39311f   Jeff Dike   uml: SMP locking ...
173
  struct iomem_region *iomem_regions;
94c282d79   Jeff Dike   [PATCH] uml: lock...
174

80e39311f   Jeff Dike   uml: SMP locking ...
175
176
  /* Initialized in parse_iomem and unchanged thereafter */
  int iomem_size;
94c282d79   Jeff Dike   [PATCH] uml: lock...
177

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
179
180
  unsigned long find_iomem(char *driver, unsigned long *len_out)
  {
  	struct iomem_region *region = iomem_regions;
6d536e4b5   Jeff Dike   uml: physmem code...
181
182
  	while (region != NULL) {
  		if (!strcmp(region->driver, driver)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183
  			*len_out = region->size;
60678bbc7   Jeff Dike   [PATCH] uml: mem....
184
  			return region->virt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
  		}
c39e50b4b   Victor V. Vengerov   [PATCH] uml: fix ...
186
187
  
  		region = region->next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
  	}
60678bbc7   Jeff Dike   [PATCH] uml: mem....
189
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
  }
73395a000   Al Viro   um: distribute ex...
191
  EXPORT_SYMBOL(find_iomem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192

99764fa4c   WANG Cong   UML: make several...
193
  static int setup_iomem(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
195
196
197
  {
  	struct iomem_region *region = iomem_regions;
  	unsigned long iomem_start = high_physmem + PAGE_SIZE;
  	int err;
6d536e4b5   Jeff Dike   uml: physmem code...
198
  	while (region != NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199
200
  		err = os_map_memory((void *) iomem_start, region->fd, 0,
  				    region->size, 1, 1, 0);
6d536e4b5   Jeff Dike   uml: physmem code...
201
  		if (err)
ba180fd43   Jeff Dike   uml: style fixes ...
202
203
204
  			printk(KERN_ERR "Mapping iomem region for driver '%s' "
  			       "failed, errno = %d
  ", region->driver, -err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205
206
207
208
209
210
211
212
  		else {
  			region->virt = iomem_start;
  			region->phys = __pa(region->virt);
  		}
  
  		iomem_start += region->size + PAGE_SIZE;
  		region = region->next;
  	}
60678bbc7   Jeff Dike   [PATCH] uml: mem....
213
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
214
215
216
  }
  
  __initcall(setup_iomem);