xref: /original-bsd/lib/libkvm/kvm_mips.c (revision c3e32dec)
1 /*-
2  * Copyright (c) 1989, 1992, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software developed by the Computer Systems
6  * Engineering group at Lawrence Berkeley Laboratory under DARPA contract
7  * BG 91-66 and contributed to Berkeley. Modified for MIPS by Ralph Campbell.
8  *
9  * %sccs.include.redist.c%
10  */
11 
12 #if defined(LIBC_SCCS) && !defined(lint)
13 static char sccsid[] = "@(#)kvm_mips.c	8.1 (Berkeley) 06/04/93";
14 #endif /* LIBC_SCCS and not lint */
15 /*
16  * MIPS machine dependent routines for kvm.  Hopefully, the forthcoming
17  * vm code will one day obsolete this module.
18  */
19 
20 #include <sys/param.h>
21 #include <sys/user.h>
22 #include <sys/proc.h>
23 #include <sys/stat.h>
24 #include <unistd.h>
25 #include <nlist.h>
26 #include <kvm.h>
27 
28 #include <vm/vm.h>
29 #include <vm/vm_param.h>
30 
31 #include <limits.h>
32 #include <db.h>
33 
34 #include "kvm_private.h"
35 
36 #include <machine/machConst.h>
37 #include <machine/pte.h>
38 #include <machine/pmap.h>
39 
40 struct vmstate {
41 	pt_entry_t	*Sysmap;
42 	u_int		Sysmapsize;
43 };
44 
45 #define KREAD(kd, addr, p)\
46 	(kvm_read(kd, addr, (char *)(p), sizeof(*(p))) != sizeof(*(p)))
47 
48 void
49 _kvm_freevtop(kd)
50 	kvm_t *kd;
51 {
52 	if (kd->vmst != 0)
53 		free(kd->vmst);
54 }
55 
56 int
57 _kvm_initvtop(kd)
58 	kvm_t *kd;
59 {
60 	struct vmstate *vm;
61 	struct nlist nlist[3];
62 
63 	vm = (struct vmstate *)_kvm_malloc(kd, sizeof(*vm));
64 	if (vm == 0)
65 		return (-1);
66 	kd->vmst = vm;
67 
68 	nlist[0].n_name = "Sysmap";
69 	nlist[1].n_name = "Sysmapsize";
70 	nlist[2].n_name = 0;
71 
72 	if (kvm_nlist(kd, nlist) != 0) {
73 		_kvm_err(kd, kd->program, "bad namelist");
74 		return (-1);
75 	}
76 	if (KREAD(kd, (u_long)nlist[0].n_value, &vm->Sysmap)) {
77 		_kvm_err(kd, kd->program, "cannot read Sysmap");
78 		return (-1);
79 	}
80 	if (KREAD(kd, (u_long)nlist[1].n_value, &vm->Sysmapsize)) {
81 		_kvm_err(kd, kd->program, "cannot read mmutype");
82 		return (-1);
83 	}
84 	return (0);
85 }
86 
87 /*
88  * Translate a kernel virtual address to a physical address.
89  */
90 int
91 _kvm_kvatop(kd, va, pa)
92 	kvm_t *kd;
93 	u_long va;
94 	u_long *pa;
95 {
96 	register struct vmstate *vm;
97 	u_long pte, addr, offset;
98 
99 	if (ISALIVE(kd)) {
100 		_kvm_err(kd, 0, "vatop called in live kernel!");
101 		return((off_t)0);
102 	}
103 	vm = kd->vmst;
104 	offset = va & PGOFSET;
105 	/*
106 	 * If we are initializing (kernel segment table pointer not yet set)
107 	 * then return pa == va to avoid infinite recursion.
108 	 */
109 	if (vm->Sysmap == 0) {
110 		*pa = va;
111 		return (NBPG - offset);
112 	}
113 	if (va < KERNBASE ||
114 	    va >= VM_MIN_KERNEL_ADDRESS + vm->Sysmapsize * NBPG)
115 		goto invalid;
116 	if (va < VM_MIN_KERNEL_ADDRESS) {
117 		*pa = MACH_CACHED_TO_PHYS(va);
118 		return (NBPG - offset);
119 	}
120 	addr = (u_long)(vm->Sysmap + ((va - VM_MIN_KERNEL_ADDRESS) >> PGSHIFT));
121 	/*
122 	 * Can't use KREAD to read kernel segment table entries.
123 	 * Fortunately it is 1-to-1 mapped so we don't have to.
124 	 */
125 	if (lseek(kd->pmfd, (off_t)addr, 0) < 0 ||
126 	    read(kd->pmfd, (char *)&pte, sizeof(pte)) < 0)
127 		goto invalid;
128 	if (!(pte & PG_V))
129 		goto invalid;
130 	*pa = (pte & PG_FRAME) | offset;
131 	return (NBPG - offset);
132 
133 invalid:
134 	_kvm_err(kd, 0, "invalid address (%x)", va);
135 	return (0);
136 }
137 
138 /*
139  * Translate a user virtual address to a physical address.
140  */
141 int
142 _kvm_uvatop(kd, p, va, pa)
143 	kvm_t *kd;
144 	const struct proc *p;
145 	u_long va;
146 	u_long *pa;
147 {
148 	register struct vmspace *vms = p->p_vmspace;
149 	u_long kva, offset;
150 
151 	if (va >= KERNBASE)
152 		goto invalid;
153 
154 	/* read the address of the first level table */
155 	kva = (u_long)&vms->vm_pmap.pm_segtab;
156 	if (kvm_read(kd, kva, (char *)&kva, sizeof(kva)) != sizeof(kva))
157 		goto invalid;
158 	if (kva == 0)
159 		goto invalid;
160 
161 	/* read the address of the second level table */
162 	kva += (va >> SEGSHIFT) * sizeof(caddr_t);
163 	if (kvm_read(kd, kva, (char *)&kva, sizeof(kva)) != sizeof(kva))
164 		goto invalid;
165 	if (kva == 0)
166 		goto invalid;
167 
168 	/* read the pte from the second level table */
169 	kva += (va >> PGSHIFT) & (NPTEPG - 1);
170 	if (kvm_read(kd, kva, (char *)&kva, sizeof(kva)) != sizeof(kva))
171 		goto invalid;
172 	if (!(kva & PG_V))
173 		goto invalid;
174 	offset = va & PGOFSET;
175 	*pa = (kva & PG_FRAME) | offset;
176 	return (NBPG - offset);
177 
178 invalid:
179 	_kvm_err(kd, 0, "invalid address (%x)", va);
180 	return (0);
181 }
182