Use mask instead of modulo, since bo->backoff is always power of 2
[dfdiff.git] / sys / boot / sparc64 / loader / main.c
blob2fa71564352547d005a0be1fb90000308ee25efc
1 /*
2 * Initial implementation:
3 * Copyright (c) 2001 Robert Drehmel
4 * All rights reserved.
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
19 * to me.
22 #include <stand.h>
23 #include <sys/exec.h>
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"
38 #include "libofw.h"
39 #include "dev_net.h"
41 enum {
42 HEAPVA = 0x800000,
43 HEAPSZ = 0x1000000,
44 LOADSZ = 0x1000000 /* for kernel and modules */
47 struct memory_slice {
48 vm_offset_t pstart;
49 vm_offset_t size;
52 typedef void kernel_entry_t(vm_offset_t mdp, u_long o1, u_long o2, u_long o3,
53 void *openfirmware);
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;
69 int dtlb_slot;
70 int itlb_slot;
71 int dtlb_slot_max;
72 int itlb_slot_max;
74 vm_offset_t curkva = 0;
75 vm_offset_t heapva;
76 phandle_t pmemh; /* OFW memory handle */
78 struct memory_slice memslices[18];
81 * Machine dependent structures that the machine independent
82 * loader part uses.
84 struct devsw *devsw[] = {
85 #ifdef LOADER_DISK_SUPPORT
86 &ofwdisk,
87 #endif
88 #ifdef LOADER_NET_SUPPORT
89 &netdev,
90 #endif
93 struct arch_switch archsw;
95 struct file_format sparc64_elf = {
96 __elfN(loadfile),
97 __elfN(exec)
99 struct file_format *file_formats[] = {
100 &sparc64_elf,
103 struct fs_ops *file_system[] = {
104 #ifdef LOADER_UFS_SUPPORT
105 &ufs_fsops,
106 #endif
107 #ifdef LOADER_CD9660_SUPPORT
108 &cd9660_fsops,
109 #endif
110 #ifdef LOADER_ZIP_SUPPORT
111 &zipfs_fsops,
112 #endif
113 #ifdef LOADER_GZIP_SUPPORT
114 &gzipfs_fsops,
115 #endif
116 #ifdef LOADER_BZIP2_SUPPORT
117 &bzipfs_fsops,
118 #endif
119 #ifdef LOADER_NFS_SUPPORT
120 &nfs_fsops,
121 #endif
122 #ifdef LOADER_TFTP_SUPPORT
123 &tftp_fsops,
124 #endif
127 struct netif_driver *netif_drivers[] = {
128 #ifdef LOADER_NET_SUPPORT
129 &ofwnet,
130 #endif
134 extern struct console ofwconsole;
135 struct console *consoles[] = {
136 &ofwconsole,
140 #ifdef LOADER_DEBUG
141 static int
142 watch_phys_set_mask(vm_offset_t pa, u_long mask)
144 u_long lsucr;
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);
151 return (0);
154 static int
155 watch_phys_set(vm_offset_t pa, int sz)
157 u_long off;
159 off = (u_long)pa & 7;
160 /* Test for misaligned watch points. */
161 if (off + sz > 8)
162 return (-1);
163 return (watch_phys_set_mask(pa, ((1 << sz) - 1) << off));
167 static int
168 watch_virt_set_mask(vm_offset_t va, u_long mask)
170 u_long lsucr;
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);
177 return (0);
180 static int
181 watch_virt_set(vm_offset_t va, int sz)
183 u_long off;
185 off = (u_long)va & 7;
186 /* Test for misaligned watch points. */
187 if (off + sz > 8)
188 return (-1);
189 return (watch_virt_set_mask(va, ((1 << sz) - 1) << off));
191 #endif
194 * archsw functions
196 static int
197 sparc64_autoload(void)
199 printf("nothing to autoload yet.\n");
200 return 0;
203 static ssize_t
204 sparc64_readin(const int fd, vm_offset_t va, const size_t len)
206 mmu_mapin(va, len);
207 return read(fd, (void *)va, len);
210 static ssize_t
211 sparc64_copyin(const void *src, vm_offset_t dest, size_t len)
213 mmu_mapin(dest, len);
214 memcpy((void *)dest, src, len);
215 return len;
219 * other MD functions
221 static int
222 __elfN(exec)(struct preloaded_file *fp)
224 struct file_metadata *fmp;
225 vm_offset_t mdp;
226 Elf_Addr entry;
227 Elf_Ehdr *e;
228 int error;
230 if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == 0) {
231 return EFTYPE;
233 e = (Elf_Ehdr *)&fmp->md_data;
235 if ((error = md_load(fp->f_args, &mdp)) != 0)
236 return error;
238 printf("jumping to kernel entry at %#lx.\n", e->e_entry);
239 #if 0
240 pmap_print_tlb('i');
241 pmap_print_tlb('d');
242 #endif
244 entry = e->e_entry;
246 OF_release(heapva, HEAPSZ);
248 ((kernel_entry_t *)entry)(mdp, 0, 0, 0, openfirmware);
250 panic("exec returned");
253 static int
254 mmu_mapin(vm_offset_t va, vm_size_t len)
256 vm_offset_t pa, mva;
257 u_long data;
259 if (va + len > curkva)
260 curkva = va + len;
262 pa = (vm_offset_t)-1;
263 len += va & PAGE_MASK_4M;
264 va &= ~PAGE_MASK_4M;
265 while (len) {
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,
271 PAGE_SIZE_4M);
272 if (pa == (vm_offset_t)-1)
273 panic("out of memory");
274 mva = (vm_offset_t)OF_claim_virt(va,
275 PAGE_SIZE_4M, 0);
276 if (mva != va) {
277 panic("can't claim virtual page "
278 "(wanted %#lx, got %#lx)",
279 va, mva);
281 /* The mappings may have changed, be paranoid. */
282 continue;
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 |
293 TD_CV | TD_P | TD_W;
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;
298 dtlb_slot++;
299 itlb_slot++;
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;
305 va += PAGE_SIZE_4M;
307 if (pa != (vm_offset_t)-1)
308 OF_release_phys(pa, PAGE_SIZE_4M);
309 return 0;
312 static vm_offset_t
313 init_heap(void)
315 if ((pmemh = OF_finddevice("/memory")) == (phandle_t)-1)
316 OF_exit();
317 if (OF_getprop(pmemh, "available", memslices, sizeof(memslices)) <= 0)
318 OF_exit();
320 /* There is no need for continuous physical heap memory. */
321 heapva = (vm_offset_t)OF_claim((void *)HEAPVA, HEAPSZ, 32);
322 return heapva;
325 static void
326 tlb_init(void)
328 phandle_t child;
329 phandle_t root;
330 char buf[128];
331 u_int bootcpu;
332 u_int cpu;
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)) {
338 if (child == -1)
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");
346 if (cpu == bootcpu)
347 break;
350 if (cpu != bootcpu)
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 *))
366 char bootpath[64];
367 struct devsw **dp;
368 phandle_t chosenh;
371 * Tell the OpenFirmware functions where they find the ofw gate.
373 OF_init(openfirm);
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;
381 init_heap();
382 setheap((void *)heapva, (void *)(heapva + HEAPSZ));
385 * Probe for a console.
387 cons_probe();
389 tlb_init();
391 bcache_init(32, 512);
394 * Initialize devices.
396 for (dp = devsw; *dp != 0; dp++) {
397 if ((*dp)->dv_init != 0)
398 (*dp)->dv_init();
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);
429 printf("\n");
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. */
435 interact();
436 return 1;
439 COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
441 static int
442 command_reboot(int argc, char *argv[])
444 int i;
446 for (i = 0; devsw[i] != NULL; ++i)
447 if (devsw[i]->dv_cleanup != NULL)
448 (devsw[i]->dv_cleanup)();
450 printf("Rebooting...\n");
451 OF_exit();
454 /* provide this for panic, as it's not in the startup code */
455 void
456 exit(int code)
458 OF_exit();
461 #ifdef LOADER_DEBUG
462 typedef u_int64_t tte_t;
464 const char *page_sizes[] = {
465 " 8k", " 64k", "512k", " 4m"
468 static void
469 pmap_print_tte(tte_t tag, tte_t tte)
471 printf("%s %s ",
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));
485 void
486 pmap_print_tlb(char which)
488 int i;
489 tte_t tte, tag;
491 for (i = 0; i < 64*8; i += 8) {
492 if (which == 'i') {
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));
500 else {
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));
508 if (!(tte & TD_V))
509 continue;
510 printf("%cTLB-%2u: ", which, i>>3);
511 pmap_print_tte(tag, tte);
514 #endif