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