2 * Initial implementation:
3 * Copyright (c) 2001 Robert Drehmel
6 * As long as the above copyright statement and this notice remain
7 * unchanged, you can do what ever you want with this file.
9 * $FreeBSD: src/sys/boot/sparc64/loader/main.c,v 1.21 2003/07/11 16:12:50 tmm Exp $
10 * $DragonFly: src/sys/boot/sparc64/loader/main.c,v 1.1 2003/11/10 06:08:40 dillon Exp $
13 * FreeBSD/sparc64 kernel loader - machine dependent part
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
24 #include <sys/param.h>
25 #include <sys/queue.h>
26 #include <sys/linker.h>
28 #include <machine/asi.h>
29 #include <machine/atomic.h>
30 #include <machine/cpufunc.h>
31 #include <machine/elf.h>
32 #include <machine/lsu.h>
33 #include <machine/metadata.h>
34 #include <machine/tte.h>
35 #include <machine/upa.h>
37 #include "bootstrap.h"
44 LOADSZ = 0x1000000 /* for kernel and modules */
52 typedef void kernel_entry_t(vm_offset_t mdp, u_long o1, u_long o2, u_long o3,
55 extern void itlb_enter(u_long vpn, u_long data);
56 extern void dtlb_enter(u_long vpn, u_long data);
57 extern vm_offset_t itlb_va_to_pa(vm_offset_t);
58 extern vm_offset_t dtlb_va_to_pa(vm_offset_t);
59 extern vm_offset_t md_load(char *, vm_offset_t *);
60 static int __elfN(exec)(struct preloaded_file *);
61 static int sparc64_autoload(void);
62 static int mmu_mapin(vm_offset_t, vm_size_t);
64 extern char bootprog_name[], bootprog_rev[], bootprog_date[], bootprog_maker[];
66 struct tlb_entry *dtlb_store;
67 struct tlb_entry *itlb_store;
74 vm_offset_t curkva = 0;
76 phandle_t pmemh; /* OFW memory handle */
78 struct memory_slice memslices[18];
81 * Machine dependent structures that the machine independent
84 struct devsw *devsw[] = {
85 #ifdef LOADER_DISK_SUPPORT
88 #ifdef LOADER_NET_SUPPORT
93 struct arch_switch archsw;
95 struct file_format sparc64_elf = {
99 struct file_format *file_formats[] = {
103 struct fs_ops *file_system[] = {
104 #ifdef LOADER_UFS_SUPPORT
107 #ifdef LOADER_CD9660_SUPPORT
110 #ifdef LOADER_ZIP_SUPPORT
113 #ifdef LOADER_GZIP_SUPPORT
116 #ifdef LOADER_BZIP2_SUPPORT
119 #ifdef LOADER_NFS_SUPPORT
122 #ifdef LOADER_TFTP_SUPPORT
127 struct netif_driver *netif_drivers[] = {
128 #ifdef LOADER_NET_SUPPORT
134 extern struct console ofwconsole;
135 struct console *consoles[] = {
142 watch_phys_set_mask(vm_offset_t pa, u_long mask)
146 stxa(AA_DMMU_PWPR, ASI_DMMU, pa & (((2UL << 38) - 1) << 3));
147 lsucr = ldxa(0, ASI_LSU_CTL_REG);
148 lsucr = ((lsucr | LSU_PW) & ~LSU_PM_MASK) |
149 (mask << LSU_PM_SHIFT);
150 stxa(0, ASI_LSU_CTL_REG, lsucr);
155 watch_phys_set(vm_offset_t pa, int sz)
159 off = (u_long)pa & 7;
160 /* Test for misaligned watch points. */
163 return (watch_phys_set_mask(pa, ((1 << sz) - 1) << off));
168 watch_virt_set_mask(vm_offset_t va, u_long mask)
172 stxa(AA_DMMU_VWPR, ASI_DMMU, va & (((2UL << 41) - 1) << 3));
173 lsucr = ldxa(0, ASI_LSU_CTL_REG);
174 lsucr = ((lsucr | LSU_VW) & ~LSU_VM_MASK) |
175 (mask << LSU_VM_SHIFT);
176 stxa(0, ASI_LSU_CTL_REG, lsucr);
181 watch_virt_set(vm_offset_t va, int sz)
185 off = (u_long)va & 7;
186 /* Test for misaligned watch points. */
189 return (watch_virt_set_mask(va, ((1 << sz) - 1) << off));
197 sparc64_autoload(void)
199 printf("nothing to autoload yet.\n");
204 sparc64_readin(const int fd, vm_offset_t va, const size_t len)
207 return read(fd, (void *)va, len);
211 sparc64_copyin(const void *src, vm_offset_t dest, size_t len)
213 mmu_mapin(dest, len);
214 memcpy((void *)dest, src, len);
222 __elfN(exec)(struct preloaded_file *fp)
224 struct file_metadata *fmp;
230 if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == 0) {
233 e = (Elf_Ehdr *)&fmp->md_data;
235 if ((error = md_load(fp->f_args, &mdp)) != 0)
238 printf("jumping to kernel entry at %#lx.\n", e->e_entry);
246 OF_release(heapva, HEAPSZ);
248 ((kernel_entry_t *)entry)(mdp, 0, 0, 0, openfirmware);
250 panic("exec returned");
254 mmu_mapin(vm_offset_t va, vm_size_t len)
259 if (va + len > curkva)
262 pa = (vm_offset_t)-1;
263 len += va & PAGE_MASK_4M;
266 if (dtlb_va_to_pa(va) == (vm_offset_t)-1 ||
267 itlb_va_to_pa(va) == (vm_offset_t)-1) {
268 /* Allocate a physical page, claim the virtual area */
269 if (pa == (vm_offset_t)-1) {
270 pa = (vm_offset_t)OF_alloc_phys(PAGE_SIZE_4M,
272 if (pa == (vm_offset_t)-1)
273 panic("out of memory");
274 mva = (vm_offset_t)OF_claim_virt(va,
277 panic("can't claim virtual page "
278 "(wanted %#lx, got %#lx)",
281 /* The mappings may have changed, be paranoid. */
285 * Actually, we can only allocate two pages less at
286 * most (depending on the kernel TSB size).
288 if (dtlb_slot >= dtlb_slot_max)
289 panic("mmu_mapin: out of dtlb_slots");
290 if (itlb_slot >= itlb_slot_max)
291 panic("mmu_mapin: out of itlb_slots");
292 data = TD_V | TD_4M | TD_PA(pa) | TD_L | TD_CP |
294 dtlb_store[dtlb_slot].te_pa = pa;
295 dtlb_store[dtlb_slot].te_va = va;
296 itlb_store[itlb_slot].te_pa = pa;
297 itlb_store[itlb_slot].te_va = va;
300 dtlb_enter(va, data);
301 itlb_enter(va, data);
302 pa = (vm_offset_t)-1;
304 len -= len > PAGE_SIZE_4M ? PAGE_SIZE_4M : len;
307 if (pa != (vm_offset_t)-1)
308 OF_release_phys(pa, PAGE_SIZE_4M);
315 if ((pmemh = OF_finddevice("/memory")) == (phandle_t)-1)
317 if (OF_getprop(pmemh, "available", memslices, sizeof(memslices)) <= 0)
320 /* There is no need for continuous physical heap memory. */
321 heapva = (vm_offset_t)OF_claim((void *)HEAPVA, HEAPSZ, 32);
334 bootcpu = UPA_CR_GET_MID(ldxa(0, ASI_UPA_CONFIG_REG));
335 if ((root = OF_peer(0)) == -1)
336 panic("main: OF_peer");
337 for (child = OF_child(root); child != 0; child = OF_peer(child)) {
339 panic("main: OF_child");
340 if (OF_getprop(child, "device_type", buf, sizeof(buf)) > 0 &&
341 strcmp(buf, "cpu") == 0) {
342 if (OF_getprop(child, "upa-portid", &cpu,
343 sizeof(cpu)) == -1 && OF_getprop(child, "portid",
344 &cpu, sizeof(cpu)) == -1)
345 panic("main: OF_getprop");
351 panic("init_tlb: no node for bootcpu?!?!");
352 if (OF_getprop(child, "#dtlb-entries", &dtlb_slot_max,
353 sizeof(dtlb_slot_max)) == -1 ||
354 OF_getprop(child, "#itlb-entries", &itlb_slot_max,
355 sizeof(itlb_slot_max)) == -1)
356 panic("init_tlb: OF_getprop");
357 dtlb_store = malloc(dtlb_slot_max * sizeof(*dtlb_store));
358 itlb_store = malloc(itlb_slot_max * sizeof(*itlb_store));
359 if (dtlb_store == NULL || itlb_store == NULL)
360 panic("init_tlb: malloc");
364 main(int (*openfirm)(void *))
371 * Tell the OpenFirmware functions where they find the ofw gate.
375 archsw.arch_getdev = ofw_getdev;
376 archsw.arch_copyin = sparc64_copyin;
377 archsw.arch_copyout = ofw_copyout;
378 archsw.arch_readin = sparc64_readin;
379 archsw.arch_autoload = sparc64_autoload;
382 setheap((void *)heapva, (void *)(heapva + HEAPSZ));
385 * Probe for a console.
391 bcache_init(32, 512);
394 * Initialize devices.
396 for (dp = devsw; *dp != 0; dp++) {
397 if ((*dp)->dv_init != 0)
402 * Set up the current device.
404 chosenh = OF_finddevice("/chosen");
405 OF_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath));
408 * Sun compatible bootable CD-ROMs have a disk label placed
409 * before the cd9660 data, with the actual filesystem being
410 * in the first partition, while the other partitions contain
411 * pseudo disk labels with embedded boot blocks for different
412 * architectures, which may be followed by UFS filesystems.
413 * The firmware will set the boot path to the partition it
414 * boots from ('f' in the sun4u case), but we want the kernel
415 * to be loaded from the cd9660 fs ('a'), so the boot path
416 * needs to be altered.
418 if (bootpath[strlen(bootpath) - 2] == ':' &&
419 bootpath[strlen(bootpath) - 1] == 'f') {
420 bootpath[strlen(bootpath) - 1] = 'a';
421 printf("Boot path set to %s\n", bootpath);
424 env_setenv("currdev", EV_VOLATILE, bootpath,
425 ofw_setcurrdev, env_nounset);
426 env_setenv("loaddev", EV_VOLATILE, bootpath,
427 env_noset, env_nounset);
430 printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
431 printf("(%s, %s)\n", bootprog_maker, bootprog_date);
432 printf("bootpath=\"%s\"\n", bootpath);
434 /* Give control to the machine independent loader code. */
439 COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
442 command_reboot(int argc, char *argv[])
446 for (i = 0; devsw[i] != NULL; ++i)
447 if (devsw[i]->dv_cleanup != NULL)
448 (devsw[i]->dv_cleanup)();
450 printf("Rebooting...\n");
454 /* provide this for panic, as it's not in the startup code */
462 typedef u_int64_t tte_t;
464 const char *page_sizes[] = {
465 " 8k", " 64k", "512k", " 4m"
469 pmap_print_tte(tte_t tag, tte_t tte)
472 page_sizes[(tte & TD_SIZE_MASK) >> TD_SIZE_SHIFT],
473 tag & TD_G ? "G" : " ");
474 printf(tte & TD_W ? "W " : " ");
475 printf(tte & TD_P ? "\e[33mP\e[0m " : " ");
476 printf(tte & TD_E ? "E " : " ");
477 printf(tte & TD_CV ? "CV " : " ");
478 printf(tte & TD_CP ? "CP " : " ");
479 printf(tte & TD_L ? "\e[32mL\e[0m " : " ");
480 printf(tte & TD_IE ? "IE " : " ");
481 printf(tte & TD_NFO ? "NFO " : " ");
482 printf("tag=0x%lx pa=0x%lx va=0x%lx ctx=%ld\n", tag, TD_PA(tte),
483 TT_VA(tag), TT_CTX(tag));
486 pmap_print_tlb(char which)
491 for (i = 0; i < 64*8; i += 8) {
493 __asm__ __volatile__("ldxa [%1] %2, %0\n" :
494 "=r" (tag) : "r" (i),
495 "i" (ASI_ITLB_TAG_READ_REG));
496 __asm__ __volatile__("ldxa [%1] %2, %0\n" :
497 "=r" (tte) : "r" (i),
498 "i" (ASI_ITLB_DATA_ACCESS_REG));
501 __asm__ __volatile__("ldxa [%1] %2, %0\n" :
502 "=r" (tag) : "r" (i),
503 "i" (ASI_DTLB_TAG_READ_REG));
504 __asm__ __volatile__("ldxa [%1] %2, %0\n" :
505 "=r" (tte) : "r" (i),
506 "i" (ASI_DTLB_DATA_ACCESS_REG));
510 printf("%cTLB-%2u: ", which, i>>3);
511 pmap_print_tte(tag, tte);