1 /*	$NetBSD: loadfile_machdep.c,v 1.7 2009/05/18 11:39:30 nakayama Exp $	*/
2 
3 /*-
4  * Copyright (c) 2005 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This work is based on the code contributed by Robert Drehmel to the
8  * FreeBSD project.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <lib/libsa/stand.h>
33 
34 #include <machine/pte.h>
35 #include <machine/cpu.h>
36 #include <machine/ctlreg.h>
37 #include <machine/vmparam.h>
38 #include <machine/promlib.h>
39 
40 #include "boot.h"
41 #include "openfirm.h"
42 
43 
44 #define MAXSEGNUM	50
45 #define hi(val)		((uint32_t)(((val) >> 32) & (uint32_t)-1))
46 #define lo(val)		((uint32_t)((val) & (uint32_t)-1))
47 
48 #define roundup2(x, y)	(((x)+((y)-1))&(~((y)-1)))
49 
50 
51 typedef int phandle_t;
52 
53 extern void	itlb_enter(vaddr_t, uint32_t, uint32_t);
54 extern void	dtlb_enter(vaddr_t, uint32_t, uint32_t);
55 extern void	dtlb_replace(vaddr_t, uint32_t, uint32_t);
56 extern vaddr_t	itlb_va_to_pa(vaddr_t);
57 extern vaddr_t	dtlb_va_to_pa(vaddr_t);
58 
59 static void	tlb_init(void);
60 
61 static int	mmu_mapin(vaddr_t, vsize_t);
62 static ssize_t	mmu_read(int, void *, size_t);
63 static void*	mmu_memcpy(void *, const void *, size_t);
64 static void*	mmu_memset(void *, int, size_t);
65 static void	mmu_freeall(void);
66 
67 static int	ofw_mapin(vaddr_t, vsize_t);
68 static ssize_t	ofw_read(int, void *, size_t);
69 static void*	ofw_memcpy(void *, const void *, size_t);
70 static void*	ofw_memset(void *, int, size_t);
71 static void	ofw_freeall(void);
72 
73 static int	nop_mapin(vaddr_t, vsize_t);
74 static ssize_t	nop_read(int, void *, size_t);
75 static void*	nop_memcpy(void *, const void *, size_t);
76 static void*	nop_memset(void *, int, size_t);
77 static void	nop_freeall(void);
78 
79 
80 struct tlb_entry *dtlb_store = 0;
81 struct tlb_entry *itlb_store = 0;
82 
83 int dtlb_slot;
84 int itlb_slot;
85 int dtlb_slot_max;
86 int itlb_slot_max;
87 
88 static struct kvamap {
89 	uint64_t start;
90 	uint64_t end;
91 } kvamap[MAXSEGNUM];
92 
93 static struct memsw {
94 	ssize_t	(* read)(int f, void *addr, size_t size);
95 	void*	(* memcpy)(void *dst, const void *src, size_t size);
96 	void*	(* memset)(void *dst, int c, size_t size);
97 	void	(* freeall)(void);
98 } memswa[] = {
99 	{ nop_read, nop_memcpy, nop_memset, nop_freeall },
100 	{ ofw_read, ofw_memcpy, ofw_memset, ofw_freeall },
101 	{ mmu_read, mmu_memcpy, mmu_memset, mmu_freeall }
102 };
103 
104 static struct memsw *memsw = &memswa[0];
105 
106 
107 /*
108  * Check if a memory region is already mapped. Return length and virtual
109  * address of unmapped sub-region, if any.
110  */
111 static uint64_t
112 kvamap_extract(vaddr_t va, vsize_t len, vaddr_t *new_va)
113 {
114 	int i;
115 
116 	*new_va  = va;
117 	for (i = 0; (len > 0) && (i < MAXSEGNUM); i++) {
118 		if (kvamap[i].start == NULL)
119 			break;
120 		if ((kvamap[i].start <= va) && (va < kvamap[i].end)) {
121 			uint64_t va_len = kvamap[i].end - va + kvamap[i].start;
122 			len = (va_len < len) ? len - va_len : 0;
123 			*new_va = kvamap[i].end;
124 		}
125 	}
126 
127 	return (len);
128 }
129 
130 /*
131  * Record new kernel mapping.
132  */
133 static void
134 kvamap_enter(uint64_t va, uint64_t len)
135 {
136 	int i;
137 
138 	DPRINTF(("kvamap_enter: %d@%p\n", (int)len, (void*)(u_long)va));
139 	for (i = 0; (len > 0) && (i < MAXSEGNUM); i++) {
140 		if (kvamap[i].start == NULL) {
141 			kvamap[i].start = va;
142 			kvamap[i].end = va + len;
143 			break;
144 		}
145 	}
146 
147 	if (i == MAXSEGNUM) {
148 		panic("Too many allocations requested.");
149 	}
150 }
151 
152 /*
153  * Initialize TLB as required by MMU mapping functions.
154  */
155 static void
156 tlb_init(void)
157 {
158 	phandle_t child;
159 	phandle_t root;
160 	char buf[128];
161 	u_int bootcpu;
162 	u_int cpu;
163 
164 	if (dtlb_store != NULL) {
165 		return;
166 	}
167 
168 	bootcpu = get_cpuid();
169 
170 	if ( (root = prom_findroot()) == -1) {
171 		panic("tlb_init: prom_findroot()");
172 	}
173 
174 	for (child = prom_firstchild(root); child != 0;
175 			child = prom_nextsibling(child)) {
176 		if (child == -1) {
177 			panic("tlb_init: OF_child");
178 		}
179 		if (_prom_getprop(child, "device_type", buf, sizeof(buf)) > 0 &&
180 		    strcmp(buf, "cpu") == 0) {
181 			if (_prom_getprop(child, "upa-portid", &cpu,
182 			    sizeof(cpu)) == -1 && _prom_getprop(child, "portid",
183 			    &cpu, sizeof(cpu)) == -1)
184 				panic("tlb_init: prom_getprop");
185 			if (cpu == bootcpu)
186 				break;
187 		}
188 	}
189 	if (cpu != bootcpu)
190 		panic("tlb_init: no node for bootcpu?!?!");
191 	if (_prom_getprop(child, "#dtlb-entries", &dtlb_slot_max,
192 	    sizeof(dtlb_slot_max)) == -1 ||
193 	    _prom_getprop(child, "#itlb-entries", &itlb_slot_max,
194 	    sizeof(itlb_slot_max)) == -1)
195 		panic("tlb_init: prom_getprop");
196 	dtlb_store = alloc(dtlb_slot_max * sizeof(*dtlb_store));
197 	itlb_store = alloc(itlb_slot_max * sizeof(*itlb_store));
198 	if (dtlb_store == NULL || itlb_store == NULL) {
199 		panic("tlb_init: malloc");
200 	}
201 
202 	dtlb_slot = itlb_slot = 0;
203 }
204 
205 /*
206  * Map requested memory region with permanent 4MB pages.
207  */
208 static int
209 mmu_mapin(vaddr_t rva, vsize_t len)
210 {
211 	uint64_t data;
212 	paddr_t pa;
213 	vaddr_t va, mva;
214 
215 	len  = roundup2(len + (rva & PAGE_MASK_4M), PAGE_SIZE_4M);
216 	rva &= ~PAGE_MASK_4M;
217 
218 	tlb_init();
219 	for (pa = (paddr_t)-1; len > 0; rva = va) {
220 		if ( (len = kvamap_extract(rva, len, &va)) == 0) {
221 			/* The rest is already mapped */
222 			break;
223 		}
224 
225 		if (dtlb_va_to_pa(va) == (u_long)-1 ||
226 		    itlb_va_to_pa(va) == (u_long)-1) {
227 			/* Allocate a physical page, claim the virtual area */
228 			if (pa == (paddr_t)-1) {
229 				pa = OF_alloc_phys(PAGE_SIZE_4M, PAGE_SIZE_4M);
230 				if (pa == (paddr_t)-1)
231 					panic("out of memory");
232 				mva = OF_claim_virt(va, PAGE_SIZE_4M);
233 				if (mva != va) {
234 					panic("can't claim virtual page "
235 					    "(wanted %#lx, got %#lx)",
236 					    va, mva);
237 				}
238 				/* The mappings may have changed, be paranoid. */
239 				continue;
240 			}
241 
242 			/*
243 			 * Actually, we can only allocate two pages less at
244 			 * most (depending on the kernel TSB size).
245 			 */
246 			if (dtlb_slot >= dtlb_slot_max)
247 				panic("mmu_mapin: out of dtlb_slots");
248 			if (itlb_slot >= itlb_slot_max)
249 				panic("mmu_mapin: out of itlb_slots");
250 
251 			DPRINTF(("mmu_mapin: %p:%p.%p\n", va, hi(pa), lo(pa)));
252 
253 			data = TSB_DATA(0,		/* global */
254 					PGSZ_4M,	/* 4mb page */
255 					pa,		/* phys.address */
256 					1,		/* privileged */
257 					1,		/* write */
258 					1,		/* cache */
259 					1,		/* alias */
260 					1,		/* valid */
261 					0		/* endianness */
262 					);
263 			data |= TLB_L | TLB_CV; /* locked, virt.cache */
264 
265 			dtlb_store[dtlb_slot].te_pa = pa;
266 			dtlb_store[dtlb_slot].te_va = va;
267 			dtlb_slot++;
268 			dtlb_enter(va, hi(data), lo(data));
269 			pa = (paddr_t)-1;
270 		}
271 
272 		kvamap_enter(va, PAGE_SIZE_4M);
273 
274 		len -= len > PAGE_SIZE_4M ? PAGE_SIZE_4M : len;
275 		va += PAGE_SIZE_4M;
276 	}
277 
278 	if (pa != (paddr_t)-1) {
279 		OF_free_phys(pa, PAGE_SIZE_4M);
280 	}
281 
282 	return (0);
283 }
284 
285 static ssize_t
286 mmu_read(int f, void *addr, size_t size)
287 {
288 	mmu_mapin((vaddr_t)addr, size);
289 	return read(f, addr, size);
290 }
291 
292 static void*
293 mmu_memcpy(void *dst, const void *src, size_t size)
294 {
295 	mmu_mapin((vaddr_t)dst, size);
296 	return memcpy(dst, src, size);
297 }
298 
299 static void*
300 mmu_memset(void *dst, int c, size_t size)
301 {
302 	mmu_mapin((vaddr_t)dst, size);
303 	return memset(dst, c, size);
304 }
305 
306 static void
307 mmu_freeall(void)
308 {
309 	int i;
310 
311 	dtlb_slot = itlb_slot = 0;
312 	for (i = 0; i < MAXSEGNUM; i++) {
313 		/* XXX return all mappings to PROM and unmap the pages! */
314 		kvamap[i].start = kvamap[i].end = 0;
315 	}
316 }
317 
318 /*
319  * Claim requested memory region in OpenFirmware allocation pool.
320  */
321 static int
322 ofw_mapin(vaddr_t rva, vsize_t len)
323 {
324 	vaddr_t va;
325 
326 	len  = roundup2(len + (rva & PAGE_MASK_4M), PAGE_SIZE_4M);
327 	rva &= ~PAGE_MASK_4M;
328 
329 	if ( (len = kvamap_extract(rva, len, &va)) != 0) {
330 		if (OF_claim((void *)(long)va, len, PAGE_SIZE_4M) == (void*)-1){
331 			panic("ofw_mapin: Cannot claim memory.");
332 		}
333 		kvamap_enter(va, len);
334 	}
335 
336 	return (0);
337 }
338 
339 static ssize_t
340 ofw_read(int f, void *addr, size_t size)
341 {
342 	ofw_mapin((vaddr_t)addr, size);
343 	return read(f, addr, size);
344 }
345 
346 static void*
347 ofw_memcpy(void *dst, const void *src, size_t size)
348 {
349 	ofw_mapin((vaddr_t)dst, size);
350 	return memcpy(dst, src, size);
351 }
352 
353 static void*
354 ofw_memset(void *dst, int c, size_t size)
355 {
356 	ofw_mapin((vaddr_t)dst, size);
357 	return memset(dst, c, size);
358 }
359 
360 static void
361 ofw_freeall(void)
362 {
363 	int i;
364 
365 	dtlb_slot = itlb_slot = 0;
366 	for (i = 0; i < MAXSEGNUM; i++) {
367 		OF_release((void*)(u_long)kvamap[i].start,
368 				(u_int)(kvamap[i].end - kvamap[i].start));
369 		kvamap[i].start = kvamap[i].end = 0;
370 	}
371 }
372 
373 /*
374  * NOP implementation exists solely for kernel header loading sake. Here
375  * we use alloc() interface to allocate memory and avoid doing some dangerous
376  * things.
377  */
378 static ssize_t
379 nop_read(int f, void *addr, size_t size)
380 {
381 	return read(f, addr, size);
382 }
383 
384 static void*
385 nop_memcpy(void *dst, const void *src, size_t size)
386 {
387 	/*
388 	 * Real NOP to make LOAD_HDR work: loadfile_elfXX copies ELF headers
389 	 * right after the highest kernel address which will not be mapped with
390 	 * nop_XXX operations.
391 	 */
392 	return (dst);
393 }
394 
395 static void*
396 nop_memset(void *dst, int c, size_t size)
397 {
398 	return memset(dst, c, size);
399 }
400 
401 static void
402 nop_freeall(void)
403 { }
404 
405 /*
406  * loadfile() hooks.
407  */
408 ssize_t
409 sparc64_read(int f, void *addr, size_t size)
410 {
411 	return (*memsw->read)(f, addr, size);
412 }
413 
414 void*
415 sparc64_memcpy(void *dst, const void *src, size_t size)
416 {
417 	return (*memsw->memcpy)(dst, src, size);
418 }
419 
420 void*
421 sparc64_memset(void *dst, int c, size_t size)
422 {
423 	return (*memsw->memset)(dst, c, size);
424 }
425 
426 /*
427  * Remove write permissions from text mappings in the dTLB.
428  * Add entries in the iTLB.
429  */
430 void
431 sparc64_finalize_tlb(u_long data_va)
432 {
433 	int i;
434 	int64_t data;
435 	bool writable_text = false;
436 
437 	for (i = 0; i < dtlb_slot; i++) {
438 		if (dtlb_store[i].te_va >= data_va) {
439 			/*
440 			 * If (for whatever reason) the start of the
441 			 * writable section is right at the start of
442 			 * the kernel, we need to map it into the ITLB
443 			 * nevertheless (and don't make it readonly).
444 			 */
445 			if (i == 0 && dtlb_store[i].te_va == data_va)
446 				writable_text = true;
447 			else
448 				continue;
449 		}
450 
451 		data = TSB_DATA(0,		/* global */
452 				PGSZ_4M,	/* 4mb page */
453 				dtlb_store[i].te_pa,	/* phys.address */
454 				1,		/* privileged */
455 				0,		/* write */
456 				1,		/* cache */
457 				1,		/* alias */
458 				1,		/* valid */
459 				0		/* endianness */
460 				);
461 		data |= TLB_L | TLB_CV; /* locked, virt.cache */
462 		if (!writable_text)
463 			dtlb_replace(dtlb_store[i].te_va, hi(data), lo(data));
464 		itlb_store[itlb_slot] = dtlb_store[i];
465 		itlb_slot++;
466 		itlb_enter(dtlb_store[i].te_va, hi(data), lo(data));
467 	}
468 	if (writable_text)
469 		printf("WARNING: kernel text mapped writable!\n");
470 }
471 
472 /*
473  * Record kernel mappings in bootinfo structure.
474  */
475 void
476 sparc64_bi_add(void)
477 {
478 	int i;
479 	int itlb_size, dtlb_size;
480 	struct btinfo_count bi_count;
481 	struct btinfo_tlb *bi_itlb, *bi_dtlb;
482 
483 	bi_count.count = itlb_slot;
484 	bi_add(&bi_count, BTINFO_ITLB_SLOTS, sizeof(bi_count));
485 	bi_count.count = dtlb_slot;
486 	bi_add(&bi_count, BTINFO_DTLB_SLOTS, sizeof(bi_count));
487 
488 	itlb_size = sizeof(*bi_itlb) + sizeof(struct tlb_entry) * itlb_slot;
489 	dtlb_size = sizeof(*bi_dtlb) + sizeof(struct tlb_entry) * dtlb_slot;
490 
491 	bi_itlb = alloc(itlb_size);
492 	bi_dtlb = alloc(dtlb_size);
493 
494 	if ((bi_itlb == NULL) || (bi_dtlb == NULL)) {
495 		panic("Out of memory in sparc64_bi_add.\n");
496 	}
497 
498 	for (i = 0; i < itlb_slot; i++) {
499 		bi_itlb->tlb[i].te_va = itlb_store[i].te_va;
500 		bi_itlb->tlb[i].te_pa = itlb_store[i].te_pa;
501 	}
502 	bi_add(bi_itlb, BTINFO_ITLB, itlb_size);
503 
504 	for (i = 0; i < dtlb_slot; i++) {
505 		bi_dtlb->tlb[i].te_va = dtlb_store[i].te_va;
506 		bi_dtlb->tlb[i].te_pa = dtlb_store[i].te_pa;
507 	}
508 	bi_add(bi_dtlb, BTINFO_DTLB, dtlb_size);
509 }
510 
511 /*
512  * Choose kernel image mapping strategy:
513  *
514  * LOADFILE_NOP_ALLOCATOR	To load kernel image headers
515  * LOADFILE_OFW_ALLOCATOR	To map the kernel by OpenFirmware means
516  * LOADFILE_MMU_ALLOCATOR	To use permanent 4MB mappings
517  */
518 void
519 loadfile_set_allocator(int type)
520 {
521 	if (type >= (sizeof(memswa) / sizeof(struct memsw))) {
522 		panic("Bad allocator request.\n");
523 	}
524 
525 	/*
526 	 * Release all memory claimed by previous allocator and schedule
527 	 * another allocator for succeeding memory allocation calls.
528 	 */
529 	(*memsw->freeall)();
530 	memsw = &memswa[type];
531 }
532