main.c revision 165325
1/*-
2 * Initial implementation:
3 * Copyright (c) 2001 Robert Drehmel
4 * All rights reserved.
5 *
6 * As long as the above copyright statement and this notice remain
7 * unchanged, you can do what ever you want with this file.
8 */
9
10#include <sys/cdefs.h>
11__FBSDID("$FreeBSD: head/sys/boot/sparc64/loader/main.c 165325 2006-12-18 07:35:14Z kmacy $");
12/*
13 * FreeBSD/sparc64 kernel loader - machine dependent part
14 *
15 *  - implements copyin and readin functions that map kernel
16 *    pages on demand.  The machine independent code does not
17 *    know the size of the kernel early enough to pre-enter
18 *    TTEs and install just one 4MB mapping seemed to limiting
19 *    to me.
20 */
21
22#include <stand.h>
23#include <sys/exec.h>
24#include <sys/param.h>
25#include <sys/queue.h>
26#include <sys/linker.h>
27#include <sys/types.h>
28
29#include <vm/vm.h>
30#include <machine/asi.h>
31#include <machine/atomic.h>
32#include <machine/cpufunc.h>
33#include <machine/elf.h>
34#include <machine/lsu.h>
35#include <machine/metadata.h>
36#include <machine/tte.h>
37#include <machine/upa.h>
38
39#include "bootstrap.h"
40#include "libofw.h"
41#include "dev_net.h"
42
43enum {
44	HEAPVA		= 0x800000,
45	HEAPSZ		= 0x1000000,
46	LOADSZ		= 0x1000000	/* for kernel and modules */
47};
48
49struct memory_slice {
50	vm_offset_t pstart;
51	vm_offset_t size;
52};
53
54struct mmu_ops {
55	void (*tlb_init)(void);
56	int (*mmu_mapin)(vm_offset_t va, vm_size_t len);
57} *mmu_ops;
58
59
60typedef void kernel_entry_t(vm_offset_t mdp, u_long o1, u_long o2, u_long o3,
61			    void *openfirmware);
62
63extern void itlb_enter(u_long vpn, u_long data);
64extern void dtlb_enter(u_long vpn, u_long data);
65extern vm_offset_t itlb_va_to_pa(vm_offset_t);
66extern vm_offset_t dtlb_va_to_pa(vm_offset_t);
67extern vm_offset_t md_load(char *, vm_offset_t *);
68static int __elfN(exec)(struct preloaded_file *);
69static int sparc64_autoload(void);
70static int mmu_mapin_sun4u(vm_offset_t, vm_size_t);
71static int mmu_mapin_sun4v(vm_offset_t, vm_size_t);
72static void tlb_init_sun4u(void);
73static void tlb_init_sun4v(void);
74
75struct mmu_ops mmu_ops_sun4u = 	{ tlb_init_sun4u, mmu_mapin_sun4u };
76struct mmu_ops mmu_ops_sun4v = 	{ tlb_init_sun4v, mmu_mapin_sun4v };
77
78extern char bootprog_name[], bootprog_rev[], bootprog_date[], bootprog_maker[];
79
80/* sun4u */
81struct tlb_entry *dtlb_store;
82struct tlb_entry *itlb_store;
83int dtlb_slot;
84int itlb_slot;
85int dtlb_slot_max;
86int itlb_slot_max;
87
88/* sun4v */
89struct tlb_entry *tlb_store;
90int is_sun4v = 0;
91/*
92 * no direct TLB access on sun4v
93 * we somewhat arbitrarily declare enough
94 * slots to cover a 4GB AS with 4MB pages
95 */
96#define SUN4V_TLB_SLOT_MAX (1 << 10)
97
98
99extern char bootprog_name[], bootprog_rev[], bootprog_date[], bootprog_maker[];
100
101struct tlb_entry *dtlb_store;
102struct tlb_entry *itlb_store;
103
104int dtlb_slot;
105int itlb_slot;
106int dtlb_slot_max;
107int itlb_slot_max;
108
109vm_offset_t curkva = 0;
110vm_offset_t heapva;
111phandle_t pmemh;	/* OFW memory handle */
112
113struct memory_slice memslices[18];
114
115/*
116 * Machine dependent structures that the machine independent
117 * loader part uses.
118 */
119struct devsw *devsw[] = {
120#ifdef LOADER_DISK_SUPPORT
121	&ofwdisk,
122#endif
123#ifdef LOADER_NET_SUPPORT
124	&netdev,
125#endif
126	0
127};
128struct arch_switch archsw;
129
130struct file_format sparc64_elf = {
131	__elfN(loadfile),
132	__elfN(exec)
133};
134struct file_format *file_formats[] = {
135	&sparc64_elf,
136	0
137};
138struct fs_ops *file_system[] = {
139#ifdef LOADER_UFS_SUPPORT
140	&ufs_fsops,
141#endif
142#ifdef LOADER_CD9660_SUPPORT
143	&cd9660_fsops,
144#endif
145#ifdef LOADER_ZIP_SUPPORT
146	&zipfs_fsops,
147#endif
148#ifdef LOADER_GZIP_SUPPORT
149	&gzipfs_fsops,
150#endif
151#ifdef LOADER_BZIP2_SUPPORT
152	&bzipfs_fsops,
153#endif
154#ifdef LOADER_NFS_SUPPORT
155	&nfs_fsops,
156#endif
157#ifdef LOADER_TFTP_SUPPORT
158	&tftp_fsops,
159#endif
160	0
161};
162struct netif_driver *netif_drivers[] = {
163#ifdef LOADER_NET_SUPPORT
164	&ofwnet,
165#endif
166	0
167};
168
169extern struct console ofwconsole;
170struct console *consoles[] = {
171	&ofwconsole,
172	0
173};
174
175#ifdef LOADER_DEBUG
176static int
177watch_phys_set_mask(vm_offset_t pa, u_long mask)
178{
179	u_long lsucr;
180
181	stxa(AA_DMMU_PWPR, ASI_DMMU, pa & (((2UL << 38) - 1) << 3));
182	lsucr = ldxa(0, ASI_LSU_CTL_REG);
183	lsucr = ((lsucr | LSU_PW) & ~LSU_PM_MASK) |
184	    (mask << LSU_PM_SHIFT);
185	stxa(0, ASI_LSU_CTL_REG, lsucr);
186	return (0);
187}
188
189static int
190watch_phys_set(vm_offset_t pa, int sz)
191{
192	u_long off;
193
194	off = (u_long)pa & 7;
195	/* Test for misaligned watch points. */
196	if (off + sz > 8)
197		return (-1);
198	return (watch_phys_set_mask(pa, ((1 << sz) - 1) << off));
199}
200
201
202static int
203watch_virt_set_mask(vm_offset_t va, u_long mask)
204{
205	u_long lsucr;
206
207	stxa(AA_DMMU_VWPR, ASI_DMMU, va & (((2UL << 41) - 1) << 3));
208	lsucr = ldxa(0, ASI_LSU_CTL_REG);
209	lsucr = ((lsucr | LSU_VW) & ~LSU_VM_MASK) |
210	    (mask << LSU_VM_SHIFT);
211	stxa(0, ASI_LSU_CTL_REG, lsucr);
212	return (0);
213}
214
215static int
216watch_virt_set(vm_offset_t va, int sz)
217{
218	u_long off;
219
220	off = (u_long)va & 7;
221	/* Test for misaligned watch points. */
222	if (off + sz > 8)
223		return (-1);
224	return (watch_virt_set_mask(va, ((1 << sz) - 1) << off));
225}
226#endif
227
228/*
229 * archsw functions
230 */
231static int
232sparc64_autoload(void)
233{
234	printf("nothing to autoload yet.\n");
235	return 0;
236}
237
238static ssize_t
239sparc64_readin(const int fd, vm_offset_t va, const size_t len)
240{
241	mmu_ops->mmu_mapin(va, len);
242	return read(fd, (void *)va, len);
243}
244
245static ssize_t
246sparc64_copyin(const void *src, vm_offset_t dest, size_t len)
247{
248	mmu_ops->mmu_mapin(dest, len);
249	memcpy((void *)dest, src, len);
250	return len;
251}
252
253static void
254sparc64_maphint(vm_offset_t va, size_t len)
255{
256	vm_paddr_t pa;
257	vm_offset_t mva;
258	size_t size;
259	int i, ret, free_excess = 0;
260
261	if (!is_sun4v)
262		return;
263
264	if (tlb_store[va >> 22].te_pa != -1)
265		return;
266
267	/* round up to nearest 4MB page */
268	size = (len + PAGE_MASK_4M) & ~PAGE_MASK_4M;
269#if 0
270	pa = (vm_offset_t)OF_alloc_phys(PAGE_SIZE_256M,	PAGE_SIZE_256M);
271
272	if (pa != -1)
273		free_excess = 1;
274	else
275#endif
276		pa = (vm_offset_t)OF_alloc_phys(size, PAGE_SIZE_256M);
277	if (pa == -1)
278		pa = (vm_offset_t)OF_alloc_phys(size, PAGE_SIZE_4M);
279	if (pa == -1)
280		panic("out of memory");
281
282	for (i = 0; i < size; i += PAGE_SIZE_4M) {
283		mva = (vm_offset_t)OF_claim_virt(va + i, PAGE_SIZE_4M, 0);
284		if (mva != (va + i)) {
285			panic("can't claim virtual page "
286			      "(wanted %#lx, got %#lx)",
287			      va, mva);
288		}
289
290		tlb_store[mva >> 22].te_pa = pa + i;
291		if ((ret = OF_map_phys(-1, PAGE_SIZE_4M, mva, pa + i)) != 0)
292			printf("OF_map_phys failed: %d\n", ret);
293	}
294	if (free_excess)
295		OF_release_phys((vm_offset_t)pa, PAGE_SIZE_256M);
296}
297
298
299/*
300 * other MD functions
301 */
302static int
303__elfN(exec)(struct preloaded_file *fp)
304{
305	struct file_metadata *fmp;
306	vm_offset_t mdp;
307	Elf_Addr entry;
308	Elf_Ehdr *e;
309	int error;
310
311	if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == 0) {
312		return EFTYPE;
313	}
314	e = (Elf_Ehdr *)&fmp->md_data;
315
316	if ((error = md_load(fp->f_args, &mdp)) != 0)
317		return error;
318
319	printf("jumping to kernel entry at %#lx.\n", e->e_entry);
320#if 0
321	pmap_print_tlb('i');
322	pmap_print_tlb('d');
323#endif
324
325	entry = e->e_entry;
326
327	OF_release((void *)heapva, HEAPSZ);
328
329	((kernel_entry_t *)entry)(mdp, 0, 0, 0, openfirmware);
330
331	panic("exec returned");
332}
333
334static int
335mmu_mapin_sun4u(vm_offset_t va, vm_size_t len)
336{
337	vm_offset_t pa, mva;
338	u_long data;
339
340	if (va + len > curkva)
341		curkva = va + len;
342
343	pa = (vm_offset_t)-1;
344	len += va & PAGE_MASK_4M;
345	va &= ~PAGE_MASK_4M;
346	while (len) {
347		if (dtlb_va_to_pa(va) == (vm_offset_t)-1 ||
348		    itlb_va_to_pa(va) == (vm_offset_t)-1) {
349			/* Allocate a physical page, claim the virtual area */
350			if (pa == (vm_offset_t)-1) {
351				pa = (vm_offset_t)OF_alloc_phys(PAGE_SIZE_4M,
352				    PAGE_SIZE_4M);
353				if (pa == (vm_offset_t)-1)
354					panic("out of memory");
355				mva = (vm_offset_t)OF_claim_virt(va,
356				    PAGE_SIZE_4M, 0);
357				if (mva != va) {
358					panic("can't claim virtual page "
359					    "(wanted %#lx, got %#lx)",
360					    va, mva);
361				}
362				/* The mappings may have changed, be paranoid. */
363				continue;
364			}
365			/*
366			 * Actually, we can only allocate two pages less at
367			 * most (depending on the kernel TSB size).
368			 */
369			if (dtlb_slot >= dtlb_slot_max)
370				panic("mmu_mapin: out of dtlb_slots");
371			if (itlb_slot >= itlb_slot_max)
372				panic("mmu_mapin: out of itlb_slots");
373			data = TD_V | TD_4M | TD_PA(pa) | TD_L | TD_CP |
374			    TD_CV | TD_P | TD_W;
375			dtlb_store[dtlb_slot].te_pa = pa;
376			dtlb_store[dtlb_slot].te_va = va;
377			itlb_store[itlb_slot].te_pa = pa;
378			itlb_store[itlb_slot].te_va = va;
379			dtlb_slot++;
380			itlb_slot++;
381			dtlb_enter(va, data);
382			itlb_enter(va, data);
383			pa = (vm_offset_t)-1;
384		}
385		len -= len > PAGE_SIZE_4M ? PAGE_SIZE_4M : len;
386		va += PAGE_SIZE_4M;
387	}
388	if (pa != (vm_offset_t)-1)
389		OF_release_phys(pa, PAGE_SIZE_4M);
390
391	return 0;
392}
393
394static int
395mmu_mapin_sun4v(vm_offset_t va, vm_size_t len)
396{
397
398	vm_offset_t pa, mva;
399	u_long data;
400	int ret;
401
402	if (va + len > curkva)
403		curkva = va + len;
404
405	pa = (vm_offset_t)-1;
406	len += va & PAGE_MASK_4M;
407	va &= ~PAGE_MASK_4M;
408	while (len) {
409		if ((va >> 22) > SUN4V_TLB_SLOT_MAX)
410			panic("trying to map more than 4GB");
411		if (tlb_store[va >> 22].te_pa == -1) {
412			/* Allocate a physical page, claim the virtual area */
413			if (pa == (vm_offset_t)-1) {
414				pa = (vm_offset_t)OF_alloc_phys(PAGE_SIZE_4M,
415				    PAGE_SIZE_4M);
416				if (pa == (vm_offset_t)-1)
417					panic("out of memory");
418				mva = (vm_offset_t)OF_claim_virt(va,
419				    PAGE_SIZE_4M, 0);
420				if (mva != va) {
421					panic("can't claim virtual page "
422					    "(wanted %#lx, got %#lx)",
423					    va, mva);
424				}
425			}
426
427			tlb_store[va >> 22].te_pa = pa;
428			if ((ret = OF_map_phys(-1, PAGE_SIZE_4M, va, pa)) != 0)
429				printf("OF_map_phys failed: %d\n", ret);
430			pa = (vm_offset_t)-1;
431		}
432		len -= len > PAGE_SIZE_4M ? PAGE_SIZE_4M : len;
433		va += PAGE_SIZE_4M;
434	}
435	if (pa != (vm_offset_t)-1)
436		OF_release_phys(pa, PAGE_SIZE_4M);
437	return 0;
438}
439
440static vm_offset_t
441init_heap(void)
442{
443	if ((pmemh = OF_finddevice("/memory")) == (phandle_t)-1)
444		OF_exit();
445	if (OF_getprop(pmemh, "available", memslices, sizeof(memslices)) <= 0)
446		OF_exit();
447
448	/* There is no need for continuous physical heap memory. */
449	heapva = (vm_offset_t)OF_claim((void *)HEAPVA, HEAPSZ, 32);
450	return heapva;
451}
452
453static void
454tlb_init_sun4u(void)
455{
456	phandle_t child;
457	phandle_t root;
458	char buf[128];
459	u_int bootcpu;
460	u_int cpu;
461
462	bootcpu = UPA_CR_GET_MID(ldxa(0, ASI_UPA_CONFIG_REG));
463	if ((root = OF_peer(0)) == -1)
464		panic("main: OF_peer");
465	for (child = OF_child(root); child != 0; child = OF_peer(child)) {
466		if (child == -1)
467			panic("main: OF_child");
468		if (OF_getprop(child, "device_type", buf, sizeof(buf)) > 0 &&
469		    strcmp(buf, "cpu") == 0) {
470			if (OF_getprop(child, "upa-portid", &cpu,
471			    sizeof(cpu)) == -1 && OF_getprop(child, "portid",
472			    &cpu, sizeof(cpu)) == -1)
473				panic("main: OF_getprop");
474			if (cpu == bootcpu)
475				break;
476		}
477	}
478	if (cpu != bootcpu)
479		panic("init_tlb: no node for bootcpu?!?!");
480	if (OF_getprop(child, "#dtlb-entries", &dtlb_slot_max,
481	    sizeof(dtlb_slot_max)) == -1 ||
482	    OF_getprop(child, "#itlb-entries", &itlb_slot_max,
483	    sizeof(itlb_slot_max)) == -1)
484		panic("init_tlb: OF_getprop");
485	dtlb_store = malloc(dtlb_slot_max * sizeof(*dtlb_store));
486	itlb_store = malloc(itlb_slot_max * sizeof(*itlb_store));
487	if (dtlb_store == NULL || itlb_store == NULL)
488		panic("init_tlb: malloc");
489}
490
491static void
492tlb_init_sun4v(void)
493{
494	tlb_store = malloc(SUN4V_TLB_SLOT_MAX * sizeof(*tlb_store));
495	memset(tlb_store, 0xFF, SUN4V_TLB_SLOT_MAX * sizeof(*tlb_store));
496}
497
498int
499main(int (*openfirm)(void *))
500{
501	char bootpath[64];
502	char compatible[32];
503	struct devsw **dp;
504	phandle_t rooth;
505	phandle_t chosenh;
506
507	/*
508	 * Tell the Open Firmware functions where they find the ofw gate.
509	 */
510	OF_init(openfirm);
511
512	archsw.arch_getdev = ofw_getdev;
513	archsw.arch_copyin = sparc64_copyin;
514	archsw.arch_copyout = ofw_copyout;
515	archsw.arch_readin = sparc64_readin;
516	archsw.arch_autoload = sparc64_autoload;
517	archsw.arch_maphint = sparc64_maphint;
518
519	init_heap();
520	setheap((void *)heapva, (void *)(heapva + HEAPSZ));
521	/*
522	 * Probe for a console.
523	 */
524	cons_probe();
525
526	rooth = OF_peer(0);
527	OF_getprop(rooth, "compatible", compatible, sizeof(compatible));
528	if (!strcmp(compatible, "sun4v")) {
529		printf("\nBooting with sun4v support.\n");
530		mmu_ops = &mmu_ops_sun4v;
531		is_sun4v = 1;
532	} else {
533		printf("\nBooting with sun4u support.\n");
534		mmu_ops = &mmu_ops_sun4u;
535	}
536
537	mmu_ops->tlb_init();
538
539	/*
540	 * Initialize devices.
541	 */
542	for (dp = devsw; *dp != 0; dp++) {
543		if ((*dp)->dv_init != 0)
544			(*dp)->dv_init();
545	}
546
547	/*
548	 * Set up the current device.
549	 */
550	chosenh = OF_finddevice("/chosen");
551	OF_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath));
552
553	/*
554	 * Sun compatible bootable CD-ROMs have a disk label placed
555	 * before the cd9660 data, with the actual filesystem being
556	 * in the first partition, while the other partitions contain
557	 * pseudo disk labels with embedded boot blocks for different
558	 * architectures, which may be followed by UFS filesystems.
559	 * The firmware will set the boot path to the partition it
560	 * boots from ('f' in the sun4u case), but we want the kernel
561	 * to be loaded from the cd9660 fs ('a'), so the boot path
562	 * needs to be altered.
563	 */
564	if (bootpath[strlen(bootpath) - 2] == ':' &&
565	    bootpath[strlen(bootpath) - 1] == 'f') {
566		bootpath[strlen(bootpath) - 1] = 'a';
567		printf("Boot path set to %s\n", bootpath);
568	}
569
570	env_setenv("currdev", EV_VOLATILE, bootpath,
571	    ofw_setcurrdev, env_nounset);
572	env_setenv("loaddev", EV_VOLATILE, bootpath,
573	    env_noset, env_nounset);
574
575	printf("\n");
576	printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
577	printf("(%s, %s)\n", bootprog_maker, bootprog_date);
578	printf("bootpath=\"%s\"\n", bootpath);
579
580	/* Give control to the machine independent loader code. */
581	interact();
582	return 1;
583}
584
585COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
586
587static int
588command_reboot(int argc, char *argv[])
589{
590	int i;
591
592	for (i = 0; devsw[i] != NULL; ++i)
593		if (devsw[i]->dv_cleanup != NULL)
594			(devsw[i]->dv_cleanup)();
595
596	printf("Rebooting...\n");
597	OF_exit();
598}
599
600/* provide this for panic, as it's not in the startup code */
601void
602exit(int code)
603{
604	OF_exit();
605}
606
607#ifdef LOADER_DEBUG
608typedef u_int64_t tte_t;
609
610const char *page_sizes[] = {
611	"  8k", " 64k", "512k", "  4m"
612};
613
614static void
615pmap_print_tte(tte_t tag, tte_t tte)
616{
617	printf("%s %s ",
618	    page_sizes[(tte & TD_SIZE_MASK) >> TD_SIZE_SHIFT],
619	    tag & TD_G ? "G" : " ");
620	printf(tte & TD_W ? "W " : "  ");
621	printf(tte & TD_P ? "\e[33mP\e[0m " : "  ");
622	printf(tte & TD_E ? "E " : "  ");
623	printf(tte & TD_CV ? "CV " : "   ");
624	printf(tte & TD_CP ? "CP " : "   ");
625	printf(tte & TD_L ? "\e[32mL\e[0m " : "  ");
626	printf(tte & TD_IE ? "IE " : "   ");
627	printf(tte & TD_NFO ? "NFO " : "    ");
628	printf("tag=0x%lx pa=0x%lx va=0x%lx ctx=%ld\n", tag, TD_PA(tte),
629	    TT_VA(tag), TT_CTX(tag));
630}
631void
632pmap_print_tlb(char which)
633{
634	int i;
635	tte_t tte, tag;
636
637	for (i = 0; i < 64*8; i += 8) {
638		if (which == 'i') {
639			__asm__ __volatile__("ldxa	[%1] %2, %0\n" :
640			    "=r" (tag) : "r" (i),
641			    "i" (ASI_ITLB_TAG_READ_REG));
642			__asm__ __volatile__("ldxa	[%1] %2, %0\n" :
643			    "=r" (tte) : "r" (i),
644			    "i" (ASI_ITLB_DATA_ACCESS_REG));
645		}
646		else {
647			__asm__ __volatile__("ldxa	[%1] %2, %0\n" :
648			    "=r" (tag) : "r" (i),
649			    "i" (ASI_DTLB_TAG_READ_REG));
650			__asm__ __volatile__("ldxa	[%1] %2, %0\n" :
651			    "=r" (tte) : "r" (i),
652			    "i" (ASI_DTLB_DATA_ACCESS_REG));
653		}
654		if (!(tte & TD_V))
655			continue;
656		printf("%cTLB-%2u: ", which, i>>3);
657		pmap_print_tte(tag, tte);
658	}
659}
660#endif
661