xref: /openbsd-src/lib/libkvm/kvm_mips64.c (revision 0e64ee4c2b175b1ffc335440a90100bf53ad4596)
1*0e64ee4cSderaadt /*	$OpenBSD: kvm_mips64.c,v 1.17 2021/12/01 16:53:28 deraadt Exp $ */
2b618256dSderaadt /*	$NetBSD: kvm_mips.c,v 1.3 1996/03/18 22:33:44 thorpej Exp $	*/
3b618256dSderaadt 
4b618256dSderaadt /*-
5b618256dSderaadt  * Copyright (c) 1989, 1992, 1993
6b618256dSderaadt  *	The Regents of the University of California.  All rights reserved.
7b618256dSderaadt  *
8b618256dSderaadt  * This code is derived from software developed by the Computer Systems
9b618256dSderaadt  * Engineering group at Lawrence Berkeley Laboratory under DARPA contract
10b618256dSderaadt  * BG 91-66 and contributed to Berkeley. Modified for MIPS by Ralph Campbell.
11b618256dSderaadt  *
12b618256dSderaadt  * Redistribution and use in source and binary forms, with or without
13b618256dSderaadt  * modification, are permitted provided that the following conditions
14b618256dSderaadt  * are met:
15b618256dSderaadt  * 1. Redistributions of source code must retain the above copyright
16b618256dSderaadt  *    notice, this list of conditions and the following disclaimer.
17b618256dSderaadt  * 2. Redistributions in binary form must reproduce the above copyright
18b618256dSderaadt  *    notice, this list of conditions and the following disclaimer in the
19b618256dSderaadt  *    documentation and/or other materials provided with the distribution.
20ee74afa0Sderaadt  * 3. Neither the name of the University nor the names of its contributors
21b618256dSderaadt  *    may be used to endorse or promote products derived from this software
22b618256dSderaadt  *    without specific prior written permission.
23b618256dSderaadt  *
24b618256dSderaadt  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25b618256dSderaadt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26b618256dSderaadt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27b618256dSderaadt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28b618256dSderaadt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29b618256dSderaadt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30b618256dSderaadt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31b618256dSderaadt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32b618256dSderaadt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33b618256dSderaadt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34b618256dSderaadt  * SUCH DAMAGE.
35b618256dSderaadt  */
36b618256dSderaadt 
37b618256dSderaadt /*
38b618256dSderaadt  * MIPS machine dependent routines for kvm.  Hopefully, the forthcoming
39b618256dSderaadt  * vm code will one day obsolete this module.
40b618256dSderaadt  */
41b618256dSderaadt 
42*0e64ee4cSderaadt #include <sys/types.h>
43*0e64ee4cSderaadt #include <sys/signal.h>
44b618256dSderaadt #include <sys/proc.h>
45b618256dSderaadt #include <sys/stat.h>
4624c56fd5Sderaadt #include <sys/sysctl.h>
47b618256dSderaadt #include <unistd.h>
48b7e5637aSmiod #include <stdlib.h>
49b618256dSderaadt #include <nlist.h>
50b618256dSderaadt #include <kvm.h>
51b618256dSderaadt 
52b618256dSderaadt #include <limits.h>
53b618256dSderaadt #include <db.h>
54b618256dSderaadt 
55b618256dSderaadt #include "kvm_private.h"
56b618256dSderaadt 
57b618256dSderaadt #include <machine/cpu.h>
58b618256dSderaadt #include <machine/pte.h>
59b618256dSderaadt #include <machine/pmap.h>
60b618256dSderaadt 
618371f9d0Smiod #include <uvm/uvm_extern.h>
628371f9d0Smiod 
63b618256dSderaadt struct vmstate {
64b618256dSderaadt 	pt_entry_t	*Sysmap;
65b618256dSderaadt 	u_int		Sysmapsize;
668608c891Smiod 	vaddr_t		Sysmapbase;
678371f9d0Smiod 	int		pagesize;
688371f9d0Smiod 	int		pagemask;
698371f9d0Smiod 	int		pageshift;
70b618256dSderaadt };
71b618256dSderaadt 
72b618256dSderaadt void
_kvm_freevtop(kvm_t * kd)73b618256dSderaadt _kvm_freevtop(kvm_t *kd)
74b618256dSderaadt {
75b618256dSderaadt 	free(kd->vmst);
7632ac5daaSzhuk 	kd->vmst = NULL;
77b618256dSderaadt }
78b618256dSderaadt 
79b618256dSderaadt int
_kvm_initvtop(kvm_t * kd)80b618256dSderaadt _kvm_initvtop(kvm_t *kd)
81b618256dSderaadt {
82b618256dSderaadt 	struct vmstate *vm;
838371f9d0Smiod 	struct nlist nl[4];
848371f9d0Smiod 	struct uvmexp uvmexp;
85b618256dSderaadt 
86b618256dSderaadt 	vm = (struct vmstate *)_kvm_malloc(kd, sizeof(*vm));
87b618256dSderaadt 	if (vm == 0)
88b618256dSderaadt 		return (-1);
89b618256dSderaadt 	kd->vmst = vm;
90b618256dSderaadt 
918371f9d0Smiod 	nl[0].n_name = "Sysmap";
928371f9d0Smiod 	nl[1].n_name = "Sysmapsize";
938371f9d0Smiod 	nl[2].n_name = "uvmexp";
948371f9d0Smiod 	nl[3].n_name = 0;
95b618256dSderaadt 
968371f9d0Smiod 	if (kvm_nlist(kd, nl) != 0) {
97b618256dSderaadt 		_kvm_err(kd, kd->program, "bad namelist");
98b618256dSderaadt 		return (-1);
99b618256dSderaadt 	}
1008371f9d0Smiod 	if (KREAD(kd, (u_long)nl[0].n_value, &vm->Sysmap)) {
101b618256dSderaadt 		_kvm_err(kd, kd->program, "cannot read Sysmap");
102b618256dSderaadt 		return (-1);
103b618256dSderaadt 	}
1048371f9d0Smiod 	if (KREAD(kd, (u_long)nl[1].n_value, &vm->Sysmapsize)) {
1052f1ad4c7Smiod 		_kvm_err(kd, kd->program, "cannot read Sysmapsize");
106b618256dSderaadt 		return (-1);
107b618256dSderaadt 	}
1088371f9d0Smiod 	/*
1098371f9d0Smiod 	 * We are only interested in the first three fields of struct
1108371f9d0Smiod 	 * uvmexp, so do not try to read more than necessary (especially
1118371f9d0Smiod 	 * in case the layout changes).
1128371f9d0Smiod 	 */
1138371f9d0Smiod 	if (kvm_read(kd, (u_long)nl[2].n_value, &uvmexp,
1148371f9d0Smiod 	    3 * sizeof(int)) != 3 * sizeof(int)) {
1158371f9d0Smiod 		_kvm_err(kd, kd->program, "cannot read uvmexp");
1168371f9d0Smiod 		return (-1);
1178371f9d0Smiod 	}
1188371f9d0Smiod 	vm->pagesize = uvmexp.pagesize;
1198371f9d0Smiod 	vm->pagemask = uvmexp.pagemask;
1208371f9d0Smiod 	vm->pageshift = uvmexp.pageshift;
1218608c891Smiod 
1228608c891Smiod 	/*
1238608c891Smiod 	 * Older kernels might not have this symbol; in which case
1244da2d91aSmiod 	 * we use the value of VM_MIN_KERNEL_ADDRESS they must have.
1258608c891Smiod 	 */
1268371f9d0Smiod 
1278371f9d0Smiod 	nl[0].n_name = "Sysmapbase";
1288371f9d0Smiod 	nl[1].n_name = 0;
1298371f9d0Smiod 	if (kvm_nlist(kd, nl) != 0 ||
1308371f9d0Smiod 	    KREAD(kd, (u_long)nl[0].n_value, &vm->Sysmapbase))
131f0a1824eSmiod 		vm->Sysmapbase = (vaddr_t)CKSSEG_BASE;
1328608c891Smiod 
133b618256dSderaadt 	return (0);
134b618256dSderaadt }
135b618256dSderaadt 
136b618256dSderaadt /*
137b618256dSderaadt  * Translate a kernel virtual address to a physical address.
138b618256dSderaadt  */
139b618256dSderaadt int
_kvm_kvatop(kvm_t * kd,u_long va,paddr_t * pa)140fdd3f45bSmickey _kvm_kvatop(kvm_t *kd, u_long va, paddr_t *pa)
141b618256dSderaadt {
142b618256dSderaadt 	struct vmstate *vm;
14322899553Smiod 	pt_entry_t pte;
1448371f9d0Smiod 	u_long idx, addr;
1458371f9d0Smiod 	int offset;
146b618256dSderaadt 
147b618256dSderaadt 	if (ISALIVE(kd)) {
148b618256dSderaadt 		_kvm_err(kd, 0, "vatop called in live kernel!");
149b618256dSderaadt 		return((off_t)0);
150b618256dSderaadt 	}
151b618256dSderaadt 	vm = kd->vmst;
1528371f9d0Smiod 	offset = (int)va & vm->pagemask;
153b618256dSderaadt 	/*
154b618256dSderaadt 	 * If we are initializing (kernel segment table pointer not yet set)
155b618256dSderaadt 	 * then return pa == va to avoid infinite recursion.
156b618256dSderaadt 	 */
157b618256dSderaadt 	if (vm->Sysmap == 0) {
158b618256dSderaadt 		*pa = va;
1598371f9d0Smiod 		return vm->pagesize - offset;
160b618256dSderaadt 	}
161edb45030Smiod 	/*
162edb45030Smiod 	 * Check for direct-mapped segments
163edb45030Smiod 	 */
164edb45030Smiod 	if (IS_XKPHYS(va)) {
165edb45030Smiod 		*pa = XKPHYS_TO_PHYS(va);
1668371f9d0Smiod 		return vm->pagesize - offset;
167edb45030Smiod 	}
168f0a1824eSmiod 	if (va >= (vaddr_t)CKSEG0_BASE && va < (vaddr_t)CKSSEG_BASE) {
169f0a1824eSmiod 		*pa = CKSEG0_TO_PHYS(va);
1708371f9d0Smiod 		return vm->pagesize - offset;
171b618256dSderaadt 	}
1728608c891Smiod 	if (va < vm->Sysmapbase)
173edb45030Smiod 		goto invalid;
1748371f9d0Smiod 	idx = (va - vm->Sysmapbase) >> vm->pageshift;
175edb45030Smiod 	if (idx >= vm->Sysmapsize)
176edb45030Smiod 		goto invalid;
1778371f9d0Smiod 	addr = (u_long)vm->Sysmap + idx;
178b618256dSderaadt 	/*
179b618256dSderaadt 	 * Can't use KREAD to read kernel segment table entries.
180b618256dSderaadt 	 * Fortunately it is 1-to-1 mapped so we don't have to.
181b618256dSderaadt 	 */
182edb45030Smiod 	if (_kvm_pread(kd, kd->pmfd, (char *)&pte, sizeof(pte),
183edb45030Smiod 	    (off_t)addr) < 0)
184b618256dSderaadt 		goto invalid;
185b618256dSderaadt 	if (!(pte & PG_V))
186b618256dSderaadt 		goto invalid;
1878371f9d0Smiod 	*pa = (pte & PG_FRAME) | (paddr_t)offset;
1888371f9d0Smiod 	return vm->pagesize - offset;
189b618256dSderaadt 
190b618256dSderaadt invalid:
191b618256dSderaadt 	_kvm_err(kd, 0, "invalid address (%lx)", va);
192b618256dSderaadt 	return (0);
193b618256dSderaadt }
194b618256dSderaadt 
195b618256dSderaadt off_t
_kvm_pa2off(kvm_t * kd,paddr_t pa)196fdd3f45bSmickey _kvm_pa2off(kvm_t *kd, paddr_t pa)
197b618256dSderaadt {
198b618256dSderaadt 	_kvm_err(kd, 0, "pa2off going to be implemented!");
199b618256dSderaadt 	return 0;
200b618256dSderaadt }
201