main.c revision 105065
166458Sdfr/*
266458Sdfr * Initial implementation:
366458Sdfr * Copyright (c) 2001 Robert Drehmel
466458Sdfr * All rights reserved.
566458Sdfr *
666458Sdfr * As long as the above copyright statement and this notice remain
766458Sdfr * unchanged, you can do what ever you want with this file.
866458Sdfr *
966458Sdfr * $FreeBSD: head/sys/boot/sparc64/loader/main.c 105065 2002-10-13 18:52:46Z jake $
1066458Sdfr */
1166458Sdfr/*
1266458Sdfr * FreeBSD/sparc64 kernel loader - machine dependent part
1366458Sdfr *
1466458Sdfr *  - implements copyin and readin functions that map kernel
1566458Sdfr *    pages on demand.  The machine independent code does not
1666458Sdfr *    know the size of the kernel early enough to pre-enter
1766458Sdfr *    TTEs and install just one 4MB mapping seemed to limiting
1866458Sdfr *    to me.
1966458Sdfr */
2066458Sdfr
2166458Sdfr#include <stand.h>
2266458Sdfr#include <sys/exec.h>
2366458Sdfr#include <sys/param.h>
2466458Sdfr#include <sys/queue.h>
2566458Sdfr#include <sys/linker.h>
2666458Sdfr
2766458Sdfr#include <machine/asi.h>
2866458Sdfr#include <machine/atomic.h>
2966458Sdfr#include <machine/cpufunc.h>
3066458Sdfr#include <machine/elf.h>
3166458Sdfr#include <machine/lsu.h>
3266458Sdfr#include <machine/metadata.h>
3366458Sdfr#include <machine/tte.h>
3466458Sdfr#include <machine/upa.h>
3566458Sdfr
3666458Sdfr#include "bootstrap.h"
3766458Sdfr#include "libofw.h"
3866458Sdfr#include "dev_net.h"
3966458Sdfr
4066458Sdfrenum {
4166458Sdfr	HEAPVA		= 0x800000,
4266458Sdfr	HEAPSZ		= 0x1000000,
4366458Sdfr	LOADSZ		= 0x1000000	/* for kernel and modules */
4466458Sdfr};
4566458Sdfr
4666458Sdfrstruct memory_slice {
4766458Sdfr	vm_offset_t pstart;
4866458Sdfr	vm_offset_t size;
4966458Sdfr};
50117126Sscottl
51117126Sscottltypedef void kernel_entry_t(vm_offset_t mdp, u_long o1, u_long o2, u_long o3,
5266458Sdfr			    void *openfirmware);
5366458Sdfr
5466458Sdfrextern void itlb_enter(u_long vpn, u_long data);
5566458Sdfrextern void dtlb_enter(u_long vpn, u_long data);
5666458Sdfrextern vm_offset_t itlb_va_to_pa(vm_offset_t);
5766458Sdfrextern vm_offset_t dtlb_va_to_pa(vm_offset_t);
58146214Snyanextern vm_offset_t md_load(char *, vm_offset_t *);
5966458Sdfrstatic int elf_exec(struct preloaded_file *);
6066458Sdfrstatic int sparc64_autoload(void);
6166458Sdfrstatic int mmu_mapin(vm_offset_t, vm_size_t);
6266458Sdfr
6366458Sdfrextern char bootprog_name[], bootprog_rev[], bootprog_date[], bootprog_maker[];
6466458Sdfr
6566458Sdfrstruct tlb_entry *dtlb_store;
6666458Sdfrstruct tlb_entry *itlb_store;
6766458Sdfr
6866458Sdfrint dtlb_slot;
6966458Sdfrint itlb_slot;
7066458Sdfrint dtlb_slot_max;
7166458Sdfrint itlb_slot_max;
7266458Sdfr
7366458Sdfrvm_offset_t curkva = 0;
7466458Sdfrvm_offset_t heapva;
7566458Sdfrphandle_t pmemh;	/* OFW memory handle */
76135262Sphk
77135262Sphkstruct memory_slice memslices[18];
7866458Sdfrstruct ofw_devdesc bootdev;
7966458Sdfr
8066458Sdfr/*
8166458Sdfr * Machine dependent structures that the machine independent
8266458Sdfr * loader part uses.
8366458Sdfr */
8466458Sdfrstruct devsw *devsw[] = {
8566458Sdfr#ifdef LOADER_DISK_SUPPORT
8666458Sdfr	&ofwdisk,
8766458Sdfr#endif
8866458Sdfr#ifdef LOADER_NET_SUPPORT
8966458Sdfr	&netdev,
9066458Sdfr#endif
9166458Sdfr	0
9266458Sdfr};
9366458Sdfrstruct arch_switch archsw;
9466458Sdfr
95135262Sphkstruct file_format sparc64_elf = {
9666458Sdfr	elf_loadfile,
9766458Sdfr	elf_exec
98135262Sphk};
9966458Sdfrstruct file_format *file_formats[] = {
10066458Sdfr	&sparc64_elf,
10166458Sdfr	0
10266458Sdfr};
10366458Sdfrstruct fs_ops *file_system[] = {
10466458Sdfr#ifdef LOADER_UFS_SUPPORT
10566458Sdfr	&ufs_fsops,
10666458Sdfr#endif
10766458Sdfr#ifdef LOADER_CD9660_SUPPORT
10866458Sdfr	&cd9660_fsops,
109177215Simp#endif
110117126Sscottl#ifdef LOADER_GZIP_SUPPORT
111117126Sscottl	&zipfs_fsops,
11266458Sdfr#endif
113135262Sphk#ifdef LOADER_BZIP2_SUPPORT
11466458Sdfr	&bzipfs_fsops,
11566458Sdfr#endif
11666458Sdfr#ifdef LOADER_NET_SUPPORT
117135262Sphk	&nfs_fsops,
11866458Sdfr#endif
11966458Sdfr#ifdef LOADER_TFTP_SUPPORT
120135262Sphk	&tftp_fsops,
12166458Sdfr#endif
12266458Sdfr	0
12366458Sdfr};
12466458Sdfrstruct netif_driver *netif_drivers[] = {
12566458Sdfr#ifdef LOADER_NET_SUPPORT
12666458Sdfr	&ofwnet,
12766458Sdfr#endif
12866458Sdfr	0
12966458Sdfr};
13066458Sdfr
13166458Sdfrextern struct console ofwconsole;
13266458Sdfrstruct console *consoles[] = {
13366458Sdfr	&ofwconsole,
13466458Sdfr	0
13566458Sdfr};
13666458Sdfr
13766458Sdfr#ifdef LOADER_DEBUG
13866458Sdfrstatic int
13966458Sdfrwatch_phys_set_mask(vm_offset_t pa, u_long mask)
14066458Sdfr{
14166458Sdfr	u_long lsucr;
14266458Sdfr
14366458Sdfr	stxa(AA_DMMU_PWPR, ASI_DMMU, pa & (((2UL << 38) - 1) << 3));
14466458Sdfr	lsucr = ldxa(0, ASI_LSU_CTL_REG);
14566458Sdfr	lsucr = ((lsucr | LSU_PW) & ~LSU_PM_MASK) |
14666458Sdfr	    (mask << LSU_PM_SHIFT);
14766458Sdfr	stxa(0, ASI_LSU_CTL_REG, lsucr);
14866458Sdfr	return (0);
14966458Sdfr}
15066458Sdfr
15166458Sdfrstatic int
15266458Sdfrwatch_phys_set(vm_offset_t pa, int sz)
15366458Sdfr{
15466458Sdfr	u_long off;
15566458Sdfr
15666458Sdfr	off = (u_long)pa & 7;
15766458Sdfr	/* Test for misaligned watch points. */
15866458Sdfr	if (off + sz > 8)
15966458Sdfr		return (-1);
16066458Sdfr	return (watch_phys_set_mask(pa, ((1 << sz) - 1) << off));
16166458Sdfr}
16266458Sdfr
16366458Sdfr
16466458Sdfrstatic int
16566458Sdfrwatch_virt_set_mask(vm_offset_t va, u_long mask)
16666458Sdfr{
16766458Sdfr	u_long lsucr;
16866458Sdfr
16966458Sdfr	stxa(AA_DMMU_VWPR, ASI_DMMU, va & (((2UL << 41) - 1) << 3));
17066458Sdfr	lsucr = ldxa(0, ASI_LSU_CTL_REG);
17166458Sdfr	lsucr = ((lsucr | LSU_VW) & ~LSU_VM_MASK) |
17266458Sdfr	    (mask << LSU_VM_SHIFT);
17366458Sdfr	stxa(0, ASI_LSU_CTL_REG, lsucr);
17466458Sdfr	return (0);
17566458Sdfr}
17666458Sdfr
17766458Sdfrstatic int
17866458Sdfrwatch_virt_set(vm_offset_t va, int sz)
17966458Sdfr{
18066458Sdfr	u_long off;
18166458Sdfr
18266458Sdfr	off = (u_long)va & 7;
18366458Sdfr	/* Test for misaligned watch points. */
18466458Sdfr	if (off + sz > 8)
18566458Sdfr		return (-1);
18666458Sdfr	return (watch_virt_set_mask(va, ((1 << sz) - 1) << off));
18766458Sdfr}
18866458Sdfr#endif
18966458Sdfr
19066458Sdfr/*
19166458Sdfr * archsw functions
19266458Sdfr */
19366458Sdfrstatic int
19466458Sdfrsparc64_autoload(void)
19566458Sdfr{
19666458Sdfr	printf("nothing to autoload yet.\n");
19766458Sdfr	return 0;
19866458Sdfr}
19966458Sdfr
20066458Sdfrstatic ssize_t
20166458Sdfrsparc64_readin(const int fd, vm_offset_t va, const size_t len)
20266458Sdfr{
20366458Sdfr	mmu_mapin(va, len);
20466458Sdfr	return read(fd, (void *)va, len);
20566458Sdfr}
20666458Sdfr
20766458Sdfrstatic ssize_t
20866458Sdfrsparc64_copyin(const void *src, vm_offset_t dest, size_t len)
20966458Sdfr{
21066458Sdfr	mmu_mapin(dest, len);
21166458Sdfr	memcpy((void *)dest, src, len);
21292676Speter	return len;
21366458Sdfr}
21492676Speter
21566458Sdfr/*
21666458Sdfr * other MD functions
21766458Sdfr */
21866458Sdfrstatic int
21966458Sdfrelf_exec(struct preloaded_file *fp)
22066458Sdfr{
22166458Sdfr	struct file_metadata *fmp;
22266458Sdfr	vm_offset_t mdp;
22366458Sdfr	Elf_Ehdr *e;
22466458Sdfr	int error;
22566458Sdfr
22695710Speter	if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == 0) {
22766458Sdfr		return EFTYPE;
22866458Sdfr	}
22966458Sdfr	e = (Elf_Ehdr *)&fmp->md_data;
23066458Sdfr
23166458Sdfr	if ((error = md_load(fp->f_args, &mdp)) != 0)
23266458Sdfr		return error;
23366458Sdfr
23466458Sdfr	printf("jumping to kernel entry at %#lx.\n", e->e_entry);
23566458Sdfr#if 0
23666458Sdfr	pmap_print_tlb('i');
23766458Sdfr	pmap_print_tlb('d');
23866458Sdfr#endif
23966458Sdfr	((kernel_entry_t *)e->e_entry)(mdp, 0, 0, 0, openfirmware);
24066458Sdfr
24166458Sdfr	panic("exec returned");
24266458Sdfr}
24366458Sdfr
24466458Sdfrstatic int
24566458Sdfrmmu_mapin(vm_offset_t va, vm_size_t len)
24666458Sdfr{
24766458Sdfr	vm_offset_t pa, mva;
24866458Sdfr	u_long data;
24966458Sdfr
25066458Sdfr	if (va + len > curkva)
25166458Sdfr		curkva = va + len;
25266458Sdfr
25366458Sdfr	pa = (vm_offset_t)-1;
25466458Sdfr	len += va & PAGE_MASK_4M;
25566458Sdfr	va &= ~PAGE_MASK_4M;
25666458Sdfr	while (len) {
25766458Sdfr		if (dtlb_va_to_pa(va) == (vm_offset_t)-1 ||
25866458Sdfr		    itlb_va_to_pa(va) == (vm_offset_t)-1) {
25966458Sdfr			/* Allocate a physical page, claim the virtual area */
26066458Sdfr			if (pa == (vm_offset_t)-1) {
26166458Sdfr				pa = (vm_offset_t)OF_alloc_phys(PAGE_SIZE_4M,
26266458Sdfr				    PAGE_SIZE_4M);
26366458Sdfr				if (pa == (vm_offset_t)-1)
26466458Sdfr					panic("out of memory");
26566458Sdfr				mva = (vm_offset_t)OF_claim_virt(va,
26666458Sdfr				    PAGE_SIZE_4M, 0);
26766458Sdfr				if (mva != va) {
26866458Sdfr					panic("can't claim virtual page "
26966458Sdfr					    "(wanted %#lx, got %#lx)",
27066458Sdfr					    va, mva);
27166458Sdfr				}
27266458Sdfr				/* The mappings may have changed, be paranoid. */
27366458Sdfr				continue;
27466458Sdfr			}
27566458Sdfr			/*
27666458Sdfr			 * Actually, we can only allocate two pages less at
27766458Sdfr			 * most (depending on the kernel TSB size).
27866458Sdfr			 */
27966458Sdfr			if (dtlb_slot >= dtlb_slot_max)
28066458Sdfr				panic("mmu_mapin: out of dtlb_slots");
28166458Sdfr			if (itlb_slot >= itlb_slot_max)
28266458Sdfr				panic("mmu_mapin: out of itlb_slots");
28366458Sdfr			data = TD_V | TD_4M | TD_PA(pa) | TD_L | TD_CP |
28466458Sdfr			    TD_CV | TD_P | TD_W;
28566458Sdfr			dtlb_store[dtlb_slot].te_pa = pa;
28666458Sdfr			dtlb_store[dtlb_slot].te_va = va;
28766458Sdfr			itlb_store[itlb_slot].te_pa = pa;
28866458Sdfr			itlb_store[itlb_slot].te_va = va;
28966458Sdfr			dtlb_slot++;
29066458Sdfr			itlb_slot++;
29166458Sdfr			dtlb_enter(va, data);
29266458Sdfr			itlb_enter(va, data);
29366458Sdfr			pa = (vm_offset_t)-1;
29466458Sdfr		}
29566458Sdfr		len -= len > PAGE_SIZE_4M ? PAGE_SIZE_4M : len;
29666458Sdfr		va += PAGE_SIZE_4M;
29766458Sdfr	}
29866458Sdfr	if (pa != (vm_offset_t)-1)
29966458Sdfr		OF_release_phys(pa, PAGE_SIZE_4M);
30066458Sdfr	return 0;
30166458Sdfr}
30266458Sdfr
30366458Sdfrstatic vm_offset_t
30466458Sdfrinit_heap(void)
30566458Sdfr{
30666458Sdfr	if ((pmemh = OF_finddevice("/memory")) == (phandle_t)-1)
30766458Sdfr		OF_exit();
30866458Sdfr	if (OF_getprop(pmemh, "available", memslices, sizeof(memslices)) <= 0)
30966458Sdfr		OF_exit();
31066458Sdfr
31166458Sdfr	/* There is no need for continuous physical heap memory. */
31266458Sdfr	heapva = (vm_offset_t)OF_claim((void *)HEAPVA, HEAPSZ, 32);
31366458Sdfr	return heapva;
31466458Sdfr}
31566458Sdfr
31666458Sdfrstatic void
31766458Sdfrtlb_init(void)
31866458Sdfr{
31966458Sdfr	phandle_t child;
32066458Sdfr	phandle_t root;
32166458Sdfr	char buf[128];
32266458Sdfr	u_int bootcpu;
32366458Sdfr	u_int cpu;
32466458Sdfr
32566458Sdfr	bootcpu = UPA_CR_GET_MID(ldxa(0, ASI_UPA_CONFIG_REG));
32666458Sdfr	if ((root = OF_peer(0)) == -1)
32766458Sdfr		panic("main: OF_peer");
32866458Sdfr	for (child = OF_child(root); child != 0; child = OF_peer(child)) {
32966458Sdfr		if (child == -1)
33066458Sdfr			panic("main: OF_child");
33166458Sdfr		if (OF_getprop(child, "device_type", buf, sizeof(buf)) > 0 &&
33266458Sdfr		    strcmp(buf, "cpu") == 0) {
33366458Sdfr			if (OF_getprop(child, "upa-portid", &cpu,
334171312Smarcel			    sizeof(cpu)) == -1 && OF_getprop(child, "portid",
335135262Sphk			    &cpu, sizeof(cpu)) == -1)
33666458Sdfr				panic("main: OF_getprop");
33766458Sdfr			if (cpu == bootcpu)
33866458Sdfr				break;
33966458Sdfr		}
34066458Sdfr	}
34166458Sdfr	if (cpu != bootcpu)
34266458Sdfr		panic("init_tlb: no node for bootcpu?!?!");
34366458Sdfr	if (OF_getprop(child, "#dtlb-entries", &dtlb_slot_max,
34466458Sdfr	    sizeof(dtlb_slot_max)) == -1 ||
34566458Sdfr	    OF_getprop(child, "#itlb-entries", &itlb_slot_max,
34666458Sdfr	    sizeof(itlb_slot_max)) == -1)
34766458Sdfr		panic("init_tlb: OF_getprop");
34866458Sdfr	dtlb_store = malloc(dtlb_slot_max * sizeof(*dtlb_store));
34966458Sdfr	itlb_store = malloc(itlb_slot_max * sizeof(*itlb_store));
35066458Sdfr	if (dtlb_store == NULL || itlb_store == NULL)
35166458Sdfr		panic("init_tlb: malloc");
35266458Sdfr}
35366458Sdfr
35466458Sdfrint
35566458Sdfrmain(int (*openfirm)(void *))
35666458Sdfr{
35766458Sdfr	char bootpath[64];
35866458Sdfr	struct devsw **dp;
35966458Sdfr	phandle_t chosenh;
36066458Sdfr
36166458Sdfr	/*
36266458Sdfr	 * Tell the OpenFirmware functions where they find the ofw gate.
36366458Sdfr	 */
36466458Sdfr	OF_init(openfirm);
36566458Sdfr
36666458Sdfr	archsw.arch_getdev = ofw_getdev;
36766458Sdfr	archsw.arch_copyin = sparc64_copyin;
36866458Sdfr	archsw.arch_copyout = ofw_copyout;
36966458Sdfr	archsw.arch_readin = sparc64_readin;
37066458Sdfr	archsw.arch_autoload = sparc64_autoload;
37166458Sdfr#ifdef ELF_CRC32
37266458Sdfr	archsw.arch_crc32 = sparc64_crc32;
37366458Sdfr#endif
37466458Sdfr
37566458Sdfr	init_heap();
37666458Sdfr	setheap((void *)heapva, (void *)(heapva + HEAPSZ));
37766458Sdfr
37866458Sdfr	/*
37966458Sdfr	 * Probe for a console.
38066458Sdfr	 */
38166458Sdfr	cons_probe();
38266458Sdfr
38366458Sdfr	tlb_init();
38466458Sdfr
38566458Sdfr	bcache_init(32, 512);
38666458Sdfr
38766458Sdfr	/*
38866458Sdfr	 * Initialize devices.
38966458Sdfr	 */
39066458Sdfr	for (dp = devsw; *dp != 0; dp++) {
39166458Sdfr		if ((*dp)->dv_init != 0)
39266458Sdfr			(*dp)->dv_init();
39366458Sdfr	}
39466458Sdfr
39566458Sdfr	/*
39666458Sdfr	 * Set up the current device.
39766458Sdfr	 */
39866458Sdfr	chosenh = OF_finddevice("/chosen");
39966458Sdfr	OF_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath));
40066458Sdfr
40166458Sdfr	bootdev.d_type = ofw_devicetype(bootpath);
40266458Sdfr	switch (bootdev.d_type) {
40366458Sdfr	case DEVT_DISK:
40466458Sdfr		bootdev.d_dev = &ofwdisk;
40566458Sdfr		/*
40666458Sdfr		 * Sun compatible bootable CD-ROMs have a disk label placed
40766458Sdfr		 * before the cd9660 data, with the actual filesystem being
40866458Sdfr		 * in the first partition, while the other partitions contain
40966458Sdfr		 * pseudo disk labels with embedded boot blocks for different
41066458Sdfr		 * architectures, which may be followed by UFS filesystems.
41166458Sdfr		 * The firmware will set the boot path to the partition it
41266458Sdfr		 * boots from ('f' in the sun4u case), but we want the kernel
41366458Sdfr		 * to be loaded from the cd9660 fs ('a'), so the boot path
41466458Sdfr		 * needs to be altered.
41566458Sdfr		 */
41666458Sdfr		if (strstr(bootpath, "cdrom") != NULL &&
41766458Sdfr		    bootpath[strlen(bootpath) - 2] == ':') {
41866458Sdfr			bootpath[strlen(bootpath) - 1] = 'a';
41966458Sdfr			printf("Boot path set to %s\n", bootpath);
42066458Sdfr		}
42166458Sdfr		strncpy(bootdev.d_kind.ofwdisk.path, bootpath, 64);
42266458Sdfr		ofw_parseofwdev(&bootdev, bootpath);
42366458Sdfr		break;
42466458Sdfr	case DEVT_NET:
42566458Sdfr		bootdev.d_dev = &netdev;
42666458Sdfr		strncpy(bootdev.d_kind.netif.path, bootpath, 64);
42766458Sdfr		bootdev.d_kind.netif.unit = 0;
42866458Sdfr		break;
42966458Sdfr	}
43066458Sdfr
43166458Sdfr	env_setenv("currdev", EV_VOLATILE, ofw_fmtdev(&bootdev),
43266458Sdfr	    ofw_setcurrdev, env_nounset);
43366458Sdfr	env_setenv("loaddev", EV_VOLATILE, ofw_fmtdev(&bootdev),
43466458Sdfr	    env_noset, env_nounset);
43566458Sdfr
43666458Sdfr	printf("\n");
43766458Sdfr	printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
43866458Sdfr	printf("(%s, %s)\n", bootprog_maker, bootprog_date);
43966458Sdfr	printf("bootpath=\"%s\"\n", bootpath);
44066458Sdfr	printf("loaddev=%s\n", getenv("loaddev"));
44166458Sdfr
44266458Sdfr	/* Give control to the machine independent loader code. */
44366458Sdfr	interact();
44466458Sdfr	return 1;
44566458Sdfr}
44666458Sdfr
44766458SdfrCOMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
44866458Sdfr
44966458Sdfrstatic int
45066458Sdfrcommand_reboot(int argc, char *argv[])
45166458Sdfr{
45266458Sdfr	int i;
45366458Sdfr
45466458Sdfr	for (i = 0; devsw[i] != NULL; ++i)
45566458Sdfr		if (devsw[i]->dv_cleanup != NULL)
45666458Sdfr			(devsw[i]->dv_cleanup)();
45766458Sdfr
45866458Sdfr	printf("Rebooting...\n");
45966458Sdfr	OF_exit();
46066458Sdfr}
46166458Sdfr
46266458Sdfr/* provide this for panic, as it's not in the startup code */
46366458Sdfrvoid
46466458Sdfrexit(int code)
46566458Sdfr{
46666458Sdfr	OF_exit();
46766458Sdfr}
46866458Sdfr
46966458Sdfr#ifdef LOADER_DEBUG
47066458Sdfrtypedef u_int64_t tte_t;
47166458Sdfr
47266458Sdfrconst char *page_sizes[] = {
47366458Sdfr	"  8k", " 64k", "512k", "  4m"
47466458Sdfr};
475141391Sphk
476141391Sphkstatic void
477141391Sphkpmap_print_tte(tte_t tag, tte_t tte)
478141391Sphk{
479141391Sphk	printf("%s %s ",
480141391Sphk	    page_sizes[(tte & TD_SIZE_MASK) >> TD_SIZE_SHIFT],
481141391Sphk	    tag & TD_G ? "G" : " ");
482141391Sphk	printf(tte & TD_W ? "W " : "  ");
483141391Sphk	printf(tte & TD_P ? "\e[33mP\e[0m " : "  ");
484141391Sphk	printf(tte & TD_E ? "E " : "  ");
485141391Sphk	printf(tte & TD_CV ? "CV " : "   ");
486141391Sphk	printf(tte & TD_CP ? "CP " : "   ");
487141391Sphk	printf(tte & TD_L ? "\e[32mL\e[0m " : "  ");
48866458Sdfr	printf(tte & TD_IE ? "IE " : "   ");
48966458Sdfr	printf(tte & TD_NFO ? "NFO " : "    ");
49066458Sdfr	printf("tag=0x%lx pa=0x%lx va=0x%lx ctx=%ld\n", tag, TD_PA(tte),
49166458Sdfr	    TT_VA(tag), TT_CTX(tag));
49266458Sdfr}
49366458Sdfrvoid
49466458Sdfrpmap_print_tlb(char which)
49566458Sdfr{
49666458Sdfr	int i;
49766458Sdfr	tte_t tte, tag;
49866458Sdfr
49966458Sdfr	for (i = 0; i < 64*8; i += 8) {
50066458Sdfr		if (which == 'i') {
50166458Sdfr			__asm__ __volatile__("ldxa	[%1] %2, %0\n" :
50266458Sdfr			    "=r" (tag) : "r" (i),
50366458Sdfr			    "i" (ASI_ITLB_TAG_READ_REG));
50466458Sdfr			__asm__ __volatile__("ldxa	[%1] %2, %0\n" :
50566458Sdfr			    "=r" (tte) : "r" (i),
50666458Sdfr			    "i" (ASI_ITLB_DATA_ACCESS_REG));
50766458Sdfr		}
50866458Sdfr		else {
509			__asm__ __volatile__("ldxa	[%1] %2, %0\n" :
510			    "=r" (tag) : "r" (i),
511			    "i" (ASI_DTLB_TAG_READ_REG));
512			__asm__ __volatile__("ldxa	[%1] %2, %0\n" :
513			    "=r" (tte) : "r" (i),
514			    "i" (ASI_DTLB_DATA_ACCESS_REG));
515		}
516		if (!(tte & TD_V))
517			continue;
518		printf("%cTLB-%2u: ", which, i>>3);
519		pmap_print_tte(tag, tte);
520	}
521}
522#endif
523