diff options
Diffstat (limited to 'arch/um/kernel/physmem.c')
-rw-r--r-- | arch/um/kernel/physmem.c | 230 |
1 files changed, 2 insertions, 228 deletions
diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c index 638f3b5f6094..3ba6e4c841da 100644 --- a/arch/um/kernel/physmem.c +++ b/arch/um/kernel/physmem.c | |||
@@ -13,7 +13,7 @@ | |||
13 | #include "asm/types.h" | 13 | #include "asm/types.h" |
14 | #include "asm/pgtable.h" | 14 | #include "asm/pgtable.h" |
15 | #include "kern_util.h" | 15 | #include "kern_util.h" |
16 | #include "user_util.h" | 16 | #include "as-layout.h" |
17 | #include "mode_kern.h" | 17 | #include "mode_kern.h" |
18 | #include "mem.h" | 18 | #include "mem.h" |
19 | #include "mem_user.h" | 19 | #include "mem_user.h" |
@@ -21,229 +21,8 @@ | |||
21 | #include "kern.h" | 21 | #include "kern.h" |
22 | #include "init.h" | 22 | #include "init.h" |
23 | 23 | ||
24 | struct phys_desc { | ||
25 | struct rb_node rb; | ||
26 | int fd; | ||
27 | __u64 offset; | ||
28 | void *virt; | ||
29 | unsigned long phys; | ||
30 | struct list_head list; | ||
31 | }; | ||
32 | |||
33 | static struct rb_root phys_mappings = RB_ROOT; | ||
34 | |||
35 | static struct rb_node **find_rb(void *virt) | ||
36 | { | ||
37 | struct rb_node **n = &phys_mappings.rb_node; | ||
38 | struct phys_desc *d; | ||
39 | |||
40 | while(*n != NULL){ | ||
41 | d = rb_entry(*n, struct phys_desc, rb); | ||
42 | if(d->virt == virt) | ||
43 | return n; | ||
44 | |||
45 | if(d->virt > virt) | ||
46 | n = &(*n)->rb_left; | ||
47 | else | ||
48 | n = &(*n)->rb_right; | ||
49 | } | ||
50 | |||
51 | return n; | ||
52 | } | ||
53 | |||
54 | static struct phys_desc *find_phys_mapping(void *virt) | ||
55 | { | ||
56 | struct rb_node **n = find_rb(virt); | ||
57 | |||
58 | if(*n == NULL) | ||
59 | return NULL; | ||
60 | |||
61 | return rb_entry(*n, struct phys_desc, rb); | ||
62 | } | ||
63 | |||
64 | static void insert_phys_mapping(struct phys_desc *desc) | ||
65 | { | ||
66 | struct rb_node **n = find_rb(desc->virt); | ||
67 | |||
68 | if(*n != NULL) | ||
69 | panic("Physical remapping for %p already present", | ||
70 | desc->virt); | ||
71 | |||
72 | rb_link_node(&desc->rb, rb_parent(*n), n); | ||
73 | rb_insert_color(&desc->rb, &phys_mappings); | ||
74 | } | ||
75 | |||
76 | LIST_HEAD(descriptor_mappings); | ||
77 | |||
78 | struct desc_mapping { | ||
79 | int fd; | ||
80 | struct list_head list; | ||
81 | struct list_head pages; | ||
82 | }; | ||
83 | |||
84 | static struct desc_mapping *find_mapping(int fd) | ||
85 | { | ||
86 | struct desc_mapping *desc; | ||
87 | struct list_head *ele; | ||
88 | |||
89 | list_for_each(ele, &descriptor_mappings){ | ||
90 | desc = list_entry(ele, struct desc_mapping, list); | ||
91 | if(desc->fd == fd) | ||
92 | return desc; | ||
93 | } | ||
94 | |||
95 | return NULL; | ||
96 | } | ||
97 | |||
98 | static struct desc_mapping *descriptor_mapping(int fd) | ||
99 | { | ||
100 | struct desc_mapping *desc; | ||
101 | |||
102 | desc = find_mapping(fd); | ||
103 | if(desc != NULL) | ||
104 | return desc; | ||
105 | |||
106 | desc = kmalloc(sizeof(*desc), GFP_ATOMIC); | ||
107 | if(desc == NULL) | ||
108 | return NULL; | ||
109 | |||
110 | *desc = ((struct desc_mapping) | ||
111 | { .fd = fd, | ||
112 | .list = LIST_HEAD_INIT(desc->list), | ||
113 | .pages = LIST_HEAD_INIT(desc->pages) }); | ||
114 | list_add(&desc->list, &descriptor_mappings); | ||
115 | |||
116 | return desc; | ||
117 | } | ||
118 | |||
119 | int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w) | ||
120 | { | ||
121 | struct desc_mapping *fd_maps; | ||
122 | struct phys_desc *desc; | ||
123 | unsigned long phys; | ||
124 | int err; | ||
125 | |||
126 | fd_maps = descriptor_mapping(fd); | ||
127 | if(fd_maps == NULL) | ||
128 | return -ENOMEM; | ||
129 | |||
130 | phys = __pa(virt); | ||
131 | desc = find_phys_mapping(virt); | ||
132 | if(desc != NULL) | ||
133 | panic("Address 0x%p is already substituted\n", virt); | ||
134 | |||
135 | err = -ENOMEM; | ||
136 | desc = kmalloc(sizeof(*desc), GFP_ATOMIC); | ||
137 | if(desc == NULL) | ||
138 | goto out; | ||
139 | |||
140 | *desc = ((struct phys_desc) | ||
141 | { .fd = fd, | ||
142 | .offset = offset, | ||
143 | .virt = virt, | ||
144 | .phys = __pa(virt), | ||
145 | .list = LIST_HEAD_INIT(desc->list) }); | ||
146 | insert_phys_mapping(desc); | ||
147 | |||
148 | list_add(&desc->list, &fd_maps->pages); | ||
149 | |||
150 | virt = (void *) ((unsigned long) virt & PAGE_MASK); | ||
151 | err = os_map_memory(virt, fd, offset, PAGE_SIZE, 1, w, 0); | ||
152 | if(!err) | ||
153 | goto out; | ||
154 | |||
155 | rb_erase(&desc->rb, &phys_mappings); | ||
156 | kfree(desc); | ||
157 | out: | ||
158 | return err; | ||
159 | } | ||
160 | |||
161 | static int physmem_fd = -1; | 24 | static int physmem_fd = -1; |
162 | 25 | ||
163 | static void remove_mapping(struct phys_desc *desc) | ||
164 | { | ||
165 | void *virt = desc->virt; | ||
166 | int err; | ||
167 | |||
168 | rb_erase(&desc->rb, &phys_mappings); | ||
169 | list_del(&desc->list); | ||
170 | kfree(desc); | ||
171 | |||
172 | err = os_map_memory(virt, physmem_fd, __pa(virt), PAGE_SIZE, 1, 1, 0); | ||
173 | if(err) | ||
174 | panic("Failed to unmap block device page from physical memory, " | ||
175 | "errno = %d", -err); | ||
176 | } | ||
177 | |||
178 | int physmem_remove_mapping(void *virt) | ||
179 | { | ||
180 | struct phys_desc *desc; | ||
181 | |||
182 | virt = (void *) ((unsigned long) virt & PAGE_MASK); | ||
183 | desc = find_phys_mapping(virt); | ||
184 | if(desc == NULL) | ||
185 | return 0; | ||
186 | |||
187 | remove_mapping(desc); | ||
188 | return 1; | ||
189 | } | ||
190 | |||
191 | void physmem_forget_descriptor(int fd) | ||
192 | { | ||
193 | struct desc_mapping *desc; | ||
194 | struct phys_desc *page; | ||
195 | struct list_head *ele, *next; | ||
196 | __u64 offset; | ||
197 | void *addr; | ||
198 | int err; | ||
199 | |||
200 | desc = find_mapping(fd); | ||
201 | if(desc == NULL) | ||
202 | return; | ||
203 | |||
204 | list_for_each_safe(ele, next, &desc->pages){ | ||
205 | page = list_entry(ele, struct phys_desc, list); | ||
206 | offset = page->offset; | ||
207 | addr = page->virt; | ||
208 | remove_mapping(page); | ||
209 | err = os_seek_file(fd, offset); | ||
210 | if(err) | ||
211 | panic("physmem_forget_descriptor - failed to seek " | ||
212 | "to %lld in fd %d, error = %d\n", | ||
213 | offset, fd, -err); | ||
214 | err = os_read_file(fd, addr, PAGE_SIZE); | ||
215 | if(err < 0) | ||
216 | panic("physmem_forget_descriptor - failed to read " | ||
217 | "from fd %d to 0x%p, error = %d\n", | ||
218 | fd, addr, -err); | ||
219 | } | ||
220 | |||
221 | list_del(&desc->list); | ||
222 | kfree(desc); | ||
223 | } | ||
224 | |||
225 | EXPORT_SYMBOL(physmem_forget_descriptor); | ||
226 | EXPORT_SYMBOL(physmem_remove_mapping); | ||
227 | EXPORT_SYMBOL(physmem_subst_mapping); | ||
228 | |||
229 | void arch_free_page(struct page *page, int order) | ||
230 | { | ||
231 | void *virt; | ||
232 | int i; | ||
233 | |||
234 | for(i = 0; i < (1 << order); i++){ | ||
235 | virt = __va(page_to_phys(page + i)); | ||
236 | physmem_remove_mapping(virt); | ||
237 | } | ||
238 | } | ||
239 | |||
240 | int is_remapped(void *virt) | ||
241 | { | ||
242 | struct phys_desc *desc = find_phys_mapping(virt); | ||
243 | |||
244 | return desc != NULL; | ||
245 | } | ||
246 | |||
247 | /* Changed during early boot */ | 26 | /* Changed during early boot */ |
248 | unsigned long high_physmem; | 27 | unsigned long high_physmem; |
249 | 28 | ||
@@ -350,14 +129,9 @@ void setup_physmem(unsigned long start, unsigned long reserve_end, | |||
350 | 129 | ||
351 | int phys_mapping(unsigned long phys, __u64 *offset_out) | 130 | int phys_mapping(unsigned long phys, __u64 *offset_out) |
352 | { | 131 | { |
353 | struct phys_desc *desc = find_phys_mapping(__va(phys & PAGE_MASK)); | ||
354 | int fd = -1; | 132 | int fd = -1; |
355 | 133 | ||
356 | if(desc != NULL){ | 134 | if(phys < physmem_size){ |
357 | fd = desc->fd; | ||
358 | *offset_out = desc->offset; | ||
359 | } | ||
360 | else if(phys < physmem_size){ | ||
361 | fd = physmem_fd; | 135 | fd = physmem_fd; |
362 | *offset_out = phys; | 136 | *offset_out = phys; |
363 | } | 137 | } |