xref: /openbsd-src/lib/libkvm/kvm_sh.c (revision d415763e8eca6b33134cd1c48e0bb3880267a548)
1*d415763eSderaadt /*	$OpenBSD: kvm_sh.c,v 1.9 2021/12/01 21:45:19 deraadt Exp $	*/
2cf252584Smiod 
3cf252584Smiod /*
4cc73efa7Smiod  * Copyright (c) 2007 Miodrag Vallat.
5cf252584Smiod  *
6cc73efa7Smiod  * Permission to use, copy, modify, and distribute this software for any
7cc73efa7Smiod  * purpose with or without fee is hereby granted, provided that the above
8cc73efa7Smiod  * copyright notice, this permission notice, and the disclaimer below
9cc73efa7Smiod  * appear in all copies.
10cf252584Smiod  *
11cc73efa7Smiod  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12cc73efa7Smiod  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13cc73efa7Smiod  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14cc73efa7Smiod  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15cc73efa7Smiod  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16cc73efa7Smiod  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17cc73efa7Smiod  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18cf252584Smiod  */
19cf252584Smiod 
200e64ee4cSderaadt #include <sys/types.h>
21cc73efa7Smiod #include <sys/kcore.h>
22cf252584Smiod 
23cf252584Smiod #include <unistd.h>
24cf252584Smiod #include <stdlib.h>
25cc73efa7Smiod #include <nlist.h>
26cf252584Smiod #include <kvm.h>
27cf252584Smiod 
28cf252584Smiod #include <db.h>
29cf252584Smiod 
30cf252584Smiod #include "kvm_private.h"
31cf252584Smiod 
32cc73efa7Smiod #include <machine/cpu.h>
33cc73efa7Smiod #include <machine/kcore.h>
34cc73efa7Smiod #include <machine/pte.h>
35cc73efa7Smiod #include <machine/vmparam.h>
36cc73efa7Smiod 
37cf252584Smiod void
_kvm_freevtop(kvm_t * kd)38cf252584Smiod _kvm_freevtop(kvm_t *kd)
39cf252584Smiod {
40cf252584Smiod }
41cf252584Smiod 
42cf252584Smiod int
_kvm_initvtop(kvm_t * kd)43cf252584Smiod _kvm_initvtop(kvm_t *kd)
44cf252584Smiod {
45cf252584Smiod 	return (0);
46cf252584Smiod }
47cf252584Smiod 
48cc73efa7Smiod /*
49cc73efa7Smiod  * Translate a kernel virtual address to a physical address by walking
50fd50b86cSkettenis  * the kernel page tables.
51cc73efa7Smiod  */
52cc73efa7Smiod 
53cc73efa7Smiod /* Stolen from sys/arch/sh/include/pmap.h we can't really include */
54cc73efa7Smiod #define	__PMAP_PTP_N		512	/* # of page table page maps 2GB. */
55cc73efa7Smiod /* Stolen from sys/arch/sh/sh/pmap.c */
56cc73efa7Smiod #define	__PMAP_PTP_SHIFT	22
577468fac6Sderaadt #define	__PMAP_PTP_PG_N		(kd->nbpg / sizeof(pt_entry_t))
58cc73efa7Smiod #define	__PMAP_PTP_INDEX(va)	(((va) >> __PMAP_PTP_SHIFT) & (__PMAP_PTP_N - 1))
597468fac6Sderaadt #define	__PMAP_PTP_OFSET(va)	((va / kd->nbpg) & (__PMAP_PTP_PG_N - 1))
60cc73efa7Smiod 
61cf252584Smiod int
_kvm_kvatop(kvm_t * kd,u_long va,paddr_t * pa)62cf252584Smiod _kvm_kvatop(kvm_t *kd, u_long va, paddr_t *pa)
63cf252584Smiod {
64cc73efa7Smiod 	cpu_kcore_hdr_t *h = kd->cpu_data;
65cc73efa7Smiod 	u_int l1idx, l2idx;
66cc73efa7Smiod 	vaddr_t l2va;
67cc73efa7Smiod 	pt_entry_t l1pte, l2pte;
68cc73efa7Smiod 	off_t pteoffset;
69cf252584Smiod 
70cf252584Smiod 	if (ISALIVE(kd)) {
71cf252584Smiod 		_kvm_err(kd, 0, "vatop called in live kernel!");
72cf252584Smiod 		return (0);
73cf252584Smiod 	}
74cf252584Smiod 
75cc73efa7Smiod 	/*
76cc73efa7Smiod 	 * P1 and P2 segments addresses are trivial.
77cc73efa7Smiod 	 */
78cc73efa7Smiod 	if (va >= SH3_P1SEG_BASE && va <= SH3_P1SEG_END) {
79cc73efa7Smiod 		*pa = SH3_P1SEG_TO_PHYS(va);
80cc73efa7Smiod 		return (int)((vaddr_t)SH3_P1SEG_END + 1 - va);
81cc73efa7Smiod 	}
82cc73efa7Smiod 	if (va >= SH3_P2SEG_BASE && va <= SH3_P2SEG_END) {
83cc73efa7Smiod 		*pa = SH3_P2SEG_TO_PHYS(va);
84cc73efa7Smiod 		return (int)((vaddr_t)SH3_P2SEG_END + 1 - va);
85cc73efa7Smiod 	}
86cc73efa7Smiod 
87cc73efa7Smiod 	/*
88cc73efa7Smiod 	 * P3 segment addresses need kernel page table walk.
89cc73efa7Smiod 	 */
90cc73efa7Smiod 	if (va >= SH3_P3SEG_BASE && va < SH3_P3SEG_END) {
91cc73efa7Smiod 		l1idx = __PMAP_PTP_INDEX(va - VM_MIN_KERNEL_ADDRESS);
92cc73efa7Smiod 		l2idx = __PMAP_PTP_OFSET(va);
93cc73efa7Smiod 
94cc73efa7Smiod 		/* read level 1 pte */
95cc73efa7Smiod 		pteoffset = h->kcore_kptp + sizeof(pt_entry_t) * l1idx;
96cc73efa7Smiod 		if (_kvm_pread(kd, kd->pmfd, (char *)&l1pte, sizeof(l1pte),
97cc73efa7Smiod 		    _kvm_pa2off(kd, pteoffset)) != sizeof(l1pte)) {
98cc73efa7Smiod 			_kvm_syserr(kd, 0, "could not read level 1 pte");
99cc73efa7Smiod 			goto bad;
100cc73efa7Smiod 		}
101cc73efa7Smiod 
102cc73efa7Smiod 		/* check pte for validity */
103cc73efa7Smiod 		if ((l1pte & PG_V) == 0) {
104cc73efa7Smiod 			_kvm_err(kd, 0, "invalid level 1 pte: no valid bit");
105cc73efa7Smiod 			goto bad;
106cc73efa7Smiod 		}
107cc73efa7Smiod 
108cc73efa7Smiod 		l2va = l1pte & PG_PPN;
109cc73efa7Smiod 		if (l2va < SH3_P1SEG_BASE || l2va > SH3_P1SEG_END) {
110cc73efa7Smiod 			_kvm_err(kd, 0, "invalid level 1 pte: out of P1");
111cc73efa7Smiod 			goto bad;
112cc73efa7Smiod 		}
113cc73efa7Smiod 
114cc73efa7Smiod 		/* read level 2 pte */
115cc73efa7Smiod 		pteoffset = SH3_P1SEG_TO_PHYS(l2va) +
116cc73efa7Smiod 		    sizeof(pt_entry_t) * l2idx;
117cc73efa7Smiod 		if (_kvm_pread(kd, kd->pmfd, (char *)&l2pte, sizeof(l2pte),
118cc73efa7Smiod 		    _kvm_pa2off(kd, pteoffset)) != sizeof(l2pte)) {
119cc73efa7Smiod 			_kvm_syserr(kd, 0, "could not read level 2 pte");
120cc73efa7Smiod 			goto bad;
121cc73efa7Smiod 		}
122cc73efa7Smiod 
123cc73efa7Smiod 		/* check pte for validity */
124cc73efa7Smiod 		if ((l2pte & PG_V) == 0) {
125cc73efa7Smiod 			_kvm_err(kd, 0, "invalid level 2 pte: no valid bit");
126cc73efa7Smiod 			goto bad;
127cc73efa7Smiod 		}
128cc73efa7Smiod 
1297468fac6Sderaadt 		*pa = (l2pte & PG_PPN) | (va & (kd->nbpg - 1));
1307468fac6Sderaadt 		return (kd->nbpg - (va & (kd->nbpg - 1)));
131cc73efa7Smiod 	}
132cc73efa7Smiod 
133cc73efa7Smiod 	/*
134cc73efa7Smiod 	 * All other addresses are incorrect.
135cc73efa7Smiod 	 */
136cc73efa7Smiod 	_kvm_err(kd, 0, "not a kernel virtual address");
137cc73efa7Smiod bad:
138cc73efa7Smiod 	*pa = (paddr_t)-1;
139cf252584Smiod 	return (0);
140cf252584Smiod }
141cf252584Smiod 
142cf252584Smiod /*
143cf252584Smiod  * Translate a physical address to a file offset in the crash dump.
144cf252584Smiod  */
145cf252584Smiod off_t
_kvm_pa2off(kvm_t * kd,paddr_t pa)146cf252584Smiod _kvm_pa2off(kvm_t *kd, paddr_t pa)
147cf252584Smiod {
148cc73efa7Smiod 	cpu_kcore_hdr_t *h = kd->cpu_data;
149cc73efa7Smiod 	phys_ram_seg_t *seg = h->kcore_segs;
150cc73efa7Smiod 	off_t off = kd->dump_off;
151cc73efa7Smiod 	u_int i;
152cc73efa7Smiod 
153cc73efa7Smiod 	for (i = h->kcore_nsegs; i != 0; i--) {
154cc73efa7Smiod 		if (pa >= seg->start && pa < seg->start + seg->size)
155cc73efa7Smiod 			return (off + (pa - seg->start));
156cc73efa7Smiod 		off += seg->size;
157cf252584Smiod 	}
158cf252584Smiod 
159cc73efa7Smiod 	_kvm_err(kd, 0, "physical address out of the image (%lx)", pa);
160cc73efa7Smiod 	return (0);
161cc73efa7Smiod }
162