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