Merge from vendor branch OPENSSH:
[dragonfly.git] / sys / boot / sparc64 / loader / main.c
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: 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 $
11  */
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
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>
36
37 #include "bootstrap.h"
38 #include "libofw.h"
39 #include "dev_net.h"
40
41 enum {
42         HEAPVA          = 0x800000,
43         HEAPSZ          = 0x1000000,
44         LOADSZ          = 0x1000000     /* for kernel and modules */
45 };
46
47 struct memory_slice {
48         vm_offset_t pstart;
49         vm_offset_t size;
50 };
51
52 typedef void kernel_entry_t(vm_offset_t mdp, u_long o1, u_long o2, u_long o3,
53                             void *openfirmware);
54
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);
63
64 extern char bootprog_name[], bootprog_rev[], bootprog_date[], bootprog_maker[];
65
66 struct tlb_entry *dtlb_store;
67 struct tlb_entry *itlb_store;
68
69 int dtlb_slot;
70 int itlb_slot;
71 int dtlb_slot_max;
72 int itlb_slot_max;
73
74 vm_offset_t curkva = 0;
75 vm_offset_t heapva;
76 phandle_t pmemh;        /* OFW memory handle */
77
78 struct memory_slice memslices[18];
79
80 /*
81  * Machine dependent structures that the machine independent
82  * loader part uses.
83  */
84 struct devsw *devsw[] = {
85 #ifdef LOADER_DISK_SUPPORT
86         &ofwdisk,
87 #endif
88 #ifdef LOADER_NET_SUPPORT
89         &netdev,
90 #endif
91         0
92 };
93 struct arch_switch archsw;
94
95 struct file_format sparc64_elf = {
96         __elfN(loadfile),
97         __elfN(exec)
98 };
99 struct file_format *file_formats[] = {
100         &sparc64_elf,
101         0
102 };
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
125         0
126 };
127 struct netif_driver *netif_drivers[] = {
128 #ifdef LOADER_NET_SUPPORT
129         &ofwnet,
130 #endif
131         0
132 };
133
134 extern struct console ofwconsole;
135 struct console *consoles[] = {
136         &ofwconsole,
137         0
138 };
139
140 #ifdef LOADER_DEBUG
141 static int
142 watch_phys_set_mask(vm_offset_t pa, u_long mask)
143 {
144         u_long lsucr;
145
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);
152 }
153
154 static int
155 watch_phys_set(vm_offset_t pa, int sz)
156 {
157         u_long off;
158
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));
164 }
165
166
167 static int
168 watch_virt_set_mask(vm_offset_t va, u_long mask)
169 {
170         u_long lsucr;
171
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);
178 }
179
180 static int
181 watch_virt_set(vm_offset_t va, int sz)
182 {
183         u_long off;
184
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));
190 }
191 #endif
192
193 /*
194  * archsw functions
195  */
196 static int
197 sparc64_autoload(void)
198 {
199         printf("nothing to autoload yet.\n");
200         return 0;
201 }
202
203 static ssize_t
204 sparc64_readin(const int fd, vm_offset_t va, const size_t len)
205 {
206         mmu_mapin(va, len);
207         return read(fd, (void *)va, len);
208 }
209
210 static ssize_t
211 sparc64_copyin(const void *src, vm_offset_t dest, size_t len)
212 {
213         mmu_mapin(dest, len);
214         memcpy((void *)dest, src, len);
215         return len;
216 }
217
218 /*
219  * other MD functions
220  */
221 static int
222 __elfN(exec)(struct preloaded_file *fp)
223 {
224         struct file_metadata *fmp;
225         vm_offset_t mdp;
226         Elf_Addr entry;
227         Elf_Ehdr *e;
228         int error;
229
230         if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == 0) {
231                 return EFTYPE;
232         }
233         e = (Elf_Ehdr *)&fmp->md_data;
234
235         if ((error = md_load(fp->f_args, &mdp)) != 0)
236                 return error;
237
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
243
244         entry = e->e_entry;
245
246         OF_release(heapva, HEAPSZ);
247
248         ((kernel_entry_t *)entry)(mdp, 0, 0, 0, openfirmware);
249
250         panic("exec returned");
251 }
252
253 static int
254 mmu_mapin(vm_offset_t va, vm_size_t len)
255 {
256         vm_offset_t pa, mva;
257         u_long data;
258
259         if (va + len > curkva)
260                 curkva = va + len;
261
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);
280                                 }
281                                 /* The mappings may have changed, be paranoid. */
282                                 continue;
283                         }
284                         /*
285                          * Actually, we can only allocate two pages less at
286                          * most (depending on the kernel TSB size).
287                          */
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;
303                 }
304                 len -= len > PAGE_SIZE_4M ? PAGE_SIZE_4M : len;
305                 va += PAGE_SIZE_4M;
306         }
307         if (pa != (vm_offset_t)-1)
308                 OF_release_phys(pa, PAGE_SIZE_4M);
309         return 0;
310 }
311
312 static vm_offset_t
313 init_heap(void)
314 {
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();
319
320         /* There is no need for continuous physical heap memory. */
321         heapva = (vm_offset_t)OF_claim((void *)HEAPVA, HEAPSZ, 32);
322         return heapva;
323 }
324
325 static void
326 tlb_init(void)
327 {
328         phandle_t child;
329         phandle_t root;
330         char buf[128];
331         u_int bootcpu;
332         u_int cpu;
333
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;
348                 }
349         }
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");
361 }
362
363 int
364 main(int (*openfirm)(void *))
365 {
366         char bootpath[64];
367         struct devsw **dp;
368         phandle_t chosenh;
369
370         /*
371          * Tell the OpenFirmware functions where they find the ofw gate.
372          */
373         OF_init(openfirm);
374
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;
380
381         init_heap();
382         setheap((void *)heapva, (void *)(heapva + HEAPSZ));
383
384         /*
385          * Probe for a console.
386          */
387         cons_probe();
388
389         tlb_init();
390
391         bcache_init(32, 512);
392
393         /*
394          * Initialize devices.
395          */
396         for (dp = devsw; *dp != 0; dp++) {
397                 if ((*dp)->dv_init != 0)
398                         (*dp)->dv_init();
399         }
400
401         /*
402          * Set up the current device.
403          */
404         chosenh = OF_finddevice("/chosen");
405         OF_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath));
406
407         /*
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.
417          */
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);
422         }
423
424         env_setenv("currdev", EV_VOLATILE, bootpath,
425             ofw_setcurrdev, env_nounset);
426         env_setenv("loaddev", EV_VOLATILE, bootpath,
427             env_noset, env_nounset);
428
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);
433
434         /* Give control to the machine independent loader code. */
435         interact();
436         return 1;
437 }
438
439 COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
440
441 static int
442 command_reboot(int argc, char *argv[])
443 {
444         int i;
445
446         for (i = 0; devsw[i] != NULL; ++i)
447                 if (devsw[i]->dv_cleanup != NULL)
448                         (devsw[i]->dv_cleanup)();
449
450         printf("Rebooting...\n");
451         OF_exit();
452 }
453
454 /* provide this for panic, as it's not in the startup code */
455 void
456 exit(int code)
457 {
458         OF_exit();
459 }
460
461 #ifdef LOADER_DEBUG
462 typedef u_int64_t tte_t;
463
464 const char *page_sizes[] = {
465         "  8k", " 64k", "512k", "  4m"
466 };
467
468 static void
469 pmap_print_tte(tte_t tag, tte_t tte)
470 {
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));
484 }
485 void
486 pmap_print_tlb(char which)
487 {
488         int i;
489         tte_t tte, tag;
490
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));
499                 }
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));
507                 }
508                 if (!(tte & TD_V))
509                         continue;
510                 printf("%cTLB-%2u: ", which, i>>3);
511                 pmap_print_tte(tag, tte);
512         }
513 }
514 #endif