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
);