main.c revision 84996
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 * $FreeBSD: head/sys/boot/sparc64/loader/main.c 84996 2001-10-15 14:35:39Z robert $
10 */
11/*
12 * FreeBSD/sparc64 kernel loader - machine dependent part
13 *
14 *  - implements copyin and readin functions that map kernel
15 *    pages on demand.  The machine independent code does not
16 *    know the size of the kernel early enough to pre-enter
17 *    TTEs and install just one 4MB mapping seemed to limiting
18 *    to me.
19 */
20#include <stand.h>
21#include <sys/exec.h>
22#include <sys/param.h>
23#include <sys/linker.h>
24
25#include <machine/asi.h>
26#include <machine/bootinfo.h>
27#include <machine/elf.h>
28#include <machine/tte.h>
29
30#include "bootstrap.h"
31#include "libofw.h"
32
33enum {
34	HEAPVA		= 0x800000,
35	HEAPSZ		= 0x1000000,
36	LOADSZ		= 0x1000000	/* for kernel and modules */
37};
38
39struct memory_slice {
40	vm_offset_t pstart;
41	vm_offset_t size;
42};
43
44extern int ofw_gate(void *);
45extern void itlb_enter(int, vm_offset_t, vm_offset_t, unsigned long);
46extern void dtlb_enter(int, vm_offset_t, vm_offset_t, unsigned long);
47extern vm_offset_t itlb_va_to_pa(vm_offset_t);
48extern vm_offset_t dtlb_va_to_pa(vm_offset_t);
49extern void jmpkern(vm_offset_t, struct bootinfo *);
50static int elf_exec(struct preloaded_file *);
51static int sparc64_autoload(void);
52static int mmu_mapin(vm_offset_t, vm_size_t);
53
54char __progname[] = "FreeBSD/sparc64 loader";
55
56vm_offset_t kernelpa;	/* Begin of kernel and mod memory. */
57vm_offset_t curkpg;	/* (PA) used for on-demand map-in. */
58vm_offset_t curkva = 0;
59vm_offset_t heapva;
60int tlbslot = 60;	/* Insert first entry at this TLB slot. */
61phandle_t pmemh;	/* OFW memory handle */
62
63struct memory_slice memslices[18];
64struct ofw_devdesc bootdev;
65
66/*
67 * Machine dependent structures that the machine independent
68 * loader part uses.
69 */
70struct devsw *devsw[] = {
71	&ofwdisk,
72	0
73};
74struct arch_switch archsw;
75
76struct file_format sparc64_elf = {
77	elf_loadfile,
78	elf_exec
79};
80struct file_format *file_formats[] = {
81	&sparc64_elf,
82	0
83};
84struct fs_ops *file_system[] = {
85	&ufs_fsops,
86	0
87};
88
89extern struct console ofwconsole;
90struct console *consoles[] = {
91	&ofwconsole,
92	0
93};
94
95/*
96 * archsw functions
97 */
98static int
99sparc64_autoload(void)
100{
101	printf("nothing to autoload yet.\n");
102	return 0;
103}
104
105static ssize_t
106sparc64_readin(const int fd, vm_offset_t va, const size_t len)
107{
108	mmu_mapin(va, len);
109	return read(fd, (void *)va, len);
110}
111
112static ssize_t
113sparc64_copyin(const void *src, vm_offset_t dest, size_t len)
114{
115	mmu_mapin(dest, len);
116	memcpy((void *)dest, src, len);
117	return len;
118}
119
120/*
121 * other MD functions
122 */
123static int
124elf_exec(struct preloaded_file *fp)
125{
126	struct file_metadata *fmp;
127	struct bootinfo bi, *bip;
128	Elf_Ehdr *Ehdr;
129	vm_offset_t entry;
130
131	if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == 0) {
132		return EFTYPE;
133	}
134	Ehdr = (Elf_Ehdr *)&fmp->md_data;
135	entry = Ehdr->e_entry;
136
137	/* align the bootinfo structure on an eight byte boundary */
138	bip = (struct bootinfo *)(curkva + 8 & 0x7);
139
140	bi.bi_version = BOOTINFO_VERSION;
141	bi.bi_kpa = kernelpa;
142	bi.bi_end = (vm_offset_t)(bip + 1);
143	bi.bi_metadata = 0;
144	sparc64_copyin(&bi, bip, sizeof(struct bootinfo));
145
146	printf("jumping to kernel entry at 0x%lx.\n", entry);
147#if 0
148	pmap_print_tlb('i');
149	pmap_print_tlb('d');
150#endif
151	jmpkern(entry, bip);
152	return 1;
153}
154
155static int
156mmu_mapin(vm_offset_t va, vm_size_t len)
157{
158	printf("mmu_mapin(): access to 0x%lx-0x%lx requested\n", va, va + len);
159
160	if (va + len > curkva)
161		curkva = va + len;
162
163	len += va & 0x3fffff;
164	va &= ~0x3fffff;
165	while (len) {
166		if (dtlb_va_to_pa(va) == (vm_offset_t)-1 ||
167		    itlb_va_to_pa(va) == (vm_offset_t)-1) {
168			printf("mmu_mapin(): map pa 0x%lx as va 0x%lx.\n",
169			    curkpg, va);
170			dtlb_enter(tlbslot, curkpg, va,
171			    TD_V | TD_4M | TD_L | TD_CP | TD_CV | TD_P | TD_W);
172			itlb_enter(tlbslot, curkpg, va,
173			    TD_V | TD_4M | TD_L | TD_CP | TD_CV | TD_P | TD_W);
174			tlbslot--;
175			curkpg += 0x400000;
176		}
177		len -= len > 0x400000 ? 0x400000 : len;
178		va += 0x400000;
179	}
180	return 0;
181}
182
183static vm_offset_t
184init_heap(void)
185{
186	if ((pmemh = OF_finddevice("/memory")) == (phandle_t)-1)
187		OF_exit();
188	if (OF_getprop(pmemh, "reg", memslices, sizeof(memslices)) <= 0)
189		OF_exit();
190
191	/* Reserve 16 MB continuous for kernel and modules. */
192	kernelpa = (vm_offset_t)OF_alloc_phys(LOADSZ, 0x400000);
193	curkpg = kernelpa;
194	/* There is no need for continuous physical heap memory. */
195	heapva = (vm_offset_t)OF_claim((void *)HEAPVA, HEAPSZ, 32);
196	return heapva;
197}
198
199int main(int (*openfirm)(void *))
200{
201	char bootpath[64];
202	struct devsw **dp;
203	phandle_t chosenh;
204
205	/*
206	 * Tell the OpenFirmware functions where they find the ofw gate.
207	 */
208	OF_init(&ofw_gate);
209
210	archsw.arch_getdev = ofw_getdev;
211	archsw.arch_copyin = sparc64_copyin;
212	archsw.arch_copyout = ofw_copyout;
213	archsw.arch_readin = sparc64_readin;
214	archsw.arch_autoload = sparc64_autoload;
215
216	init_heap();
217	setheap((void *)heapva, (void *)(heapva + HEAPSZ));
218
219	/*
220	 * Probe for a console.
221	 */
222	cons_probe();
223
224	bcache_init(32, 512);
225
226	/*
227	 * Initialize devices.
228	 */
229	for (dp = devsw; *dp != 0; dp++) {
230		if ((*dp)->dv_init != 0)
231			(*dp)->dv_init();
232	}
233
234	/*
235	 * Set up the current device.
236	 */
237	chosenh = OF_finddevice("/chosen");
238	OF_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath));
239
240	bootdev.d_type = ofw_devicetype(bootpath);
241	switch (bootdev.d_type) {
242	case DEVT_DISK:
243		bootdev.d_dev = &ofwdisk;
244		strncpy(bootdev.d_kind.ofwdisk.path, bootpath, 64);
245		ofw_parseofwdev(&bootdev, bootpath);
246		break;
247	case DEVT_NET:
248		//bootdev.d_dev = &netdev;
249		strncpy(bootdev.d_kind.netif.path, bootpath, 64);
250		bootdev.d_kind.netif.unit = 0;
251		break;
252	}
253
254	env_setenv("currdev", EV_VOLATILE, ofw_fmtdev(&bootdev),
255	    ofw_setcurrdev, env_nounset);
256	env_setenv("loaddev", EV_VOLATILE, ofw_fmtdev(&bootdev),
257	    env_noset, env_nounset);
258
259	printf("%s\n", __progname);
260	printf("bootpath=\"%s\"\n", bootpath);
261	printf("loaddev=%s\n", getenv("loaddev"));
262	printf("kernelpa=0x%x\n", curkpg);
263
264	/* Give control to the machine independent loader code. */
265	interact();
266	return 1;
267}
268
269typedef u_int64_t tte_t;
270
271const char *page_sizes[] = {
272	"  8k", " 64k", "512k", "  4m"
273};
274
275static void
276pmap_print_tte(tte_t tag, tte_t tte)
277{
278	printf("%s %s ",
279	    page_sizes[(tte & TD_SIZE_MASK) >> TD_SIZE_SHIFT],
280	    tag & TD_G ? "G" : " ");
281	printf(tte & TD_W ? "W " : "  ");
282	printf(tte & TD_P ? "\e[33mP\e[0m " : "  ");
283	printf(tte & TD_E ? "E " : "  ");
284	printf(tte & TD_CV ? "CV " : "   ");
285	printf(tte & TD_CP ? "CP " : "   ");
286	printf(tte & TD_L ? "\e[32mL\e[0m " : "  ");
287	printf(tte & TD_IE ? "IE " : "   ");
288	printf(tte & TD_NFO ? "NFO " : "    ");
289	printf("tag=0x%lx pa=0x%lx va=0x%lx ctx=%d\n", tag, TD_PA(tte),
290	    TT_VA(tag), TT_CTX(tag));
291}
292void
293pmap_print_tlb(char which)
294{
295	int i;
296	tte_t tte, tag;
297
298	for (i = 0; i < 64*8; i += 8) {
299		if (which == 'i') {
300			__asm__ __volatile__("ldxa	[%1] %2, %0\n" :
301			    "=r" (tag) : "r" (i),
302			    "i" (ASI_ITLB_TAG_READ_REG));
303			__asm__ __volatile__("ldxa	[%1] %2, %0\n" :
304			    "=r" (tte) : "r" (i),
305			    "i" (ASI_ITLB_DATA_ACCESS_REG));
306		}
307		else {
308			__asm__ __volatile__("ldxa	[%1] %2, %0\n" :
309			    "=r" (tag) : "r" (i),
310			    "i" (ASI_DTLB_TAG_READ_REG));
311			__asm__ __volatile__("ldxa	[%1] %2, %0\n" :
312			    "=r" (tte) : "r" (i),
313			    "i" (ASI_DTLB_DATA_ACCESS_REG));
314		}
315		if (!(tte & TD_V))
316			continue;
317		printf("%cTLB-%2u: ", which, i>>3);
318		pmap_print_tte(tag, tte);
319	}
320}
321