1 /* $OpenBSD: kvm_sh.c,v 1.2 2007/03/03 21:37:27 miod 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 24 #include <unistd.h> 25 #include <stdlib.h> 26 #include <nlist.h> 27 #include <kvm.h> 28 29 #include <db.h> 30 31 #include "kvm_private.h" 32 33 #include <machine/cpu.h> 34 #include <machine/kcore.h> 35 #include <machine/pte.h> 36 #include <machine/vmparam.h> 37 38 void 39 _kvm_freevtop(kvm_t *kd) 40 { 41 } 42 43 int 44 _kvm_initvtop(kvm_t *kd) 45 { 46 return (0); 47 } 48 49 /* 50 * Translate a kernel virtual address to a physical address by walking 51 * the kernels page table. 52 */ 53 54 /* Stolen from sys/arch/sh/include/pmap.h we can't really include */ 55 #define __PMAP_PTP_N 512 /* # of page table page maps 2GB. */ 56 /* Stolen from sys/arch/sh/sh/pmap.c */ 57 #define __PMAP_PTP_SHIFT 22 58 #define __PMAP_PTP_PG_N (PAGE_SIZE / sizeof(pt_entry_t)) 59 #define __PMAP_PTP_INDEX(va) (((va) >> __PMAP_PTP_SHIFT) & (__PMAP_PTP_N - 1)) 60 #define __PMAP_PTP_OFSET(va) ((va >> PGSHIFT) & (__PMAP_PTP_PG_N - 1)) 61 62 int 63 _kvm_kvatop(kvm_t *kd, u_long va, paddr_t *pa) 64 { 65 cpu_kcore_hdr_t *h = kd->cpu_data; 66 u_int l1idx, l2idx; 67 vaddr_t l2va; 68 pt_entry_t l1pte, l2pte; 69 off_t pteoffset; 70 71 if (ISALIVE(kd)) { 72 _kvm_err(kd, 0, "vatop called in live kernel!"); 73 return (0); 74 } 75 76 /* 77 * P1 and P2 segments addresses are trivial. 78 */ 79 if (va >= SH3_P1SEG_BASE && va <= SH3_P1SEG_END) { 80 *pa = SH3_P1SEG_TO_PHYS(va); 81 return (int)((vaddr_t)SH3_P1SEG_END + 1 - va); 82 } 83 if (va >= SH3_P2SEG_BASE && va <= SH3_P2SEG_END) { 84 *pa = SH3_P2SEG_TO_PHYS(va); 85 return (int)((vaddr_t)SH3_P2SEG_END + 1 - va); 86 } 87 88 /* 89 * P3 segment addresses need kernel page table walk. 90 */ 91 if (va >= SH3_P3SEG_BASE && va < SH3_P3SEG_END) { 92 l1idx = __PMAP_PTP_INDEX(va - VM_MIN_KERNEL_ADDRESS); 93 l2idx = __PMAP_PTP_OFSET(va); 94 95 /* read level 1 pte */ 96 pteoffset = h->kcore_kptp + sizeof(pt_entry_t) * l1idx; 97 if (_kvm_pread(kd, kd->pmfd, (char *)&l1pte, sizeof(l1pte), 98 _kvm_pa2off(kd, pteoffset)) != sizeof(l1pte)) { 99 _kvm_syserr(kd, 0, "could not read level 1 pte"); 100 goto bad; 101 } 102 103 /* check pte for validity */ 104 if ((l1pte & PG_V) == 0) { 105 _kvm_err(kd, 0, "invalid level 1 pte: no valid bit"); 106 goto bad; 107 } 108 109 l2va = l1pte & PG_PPN; 110 if (l2va < SH3_P1SEG_BASE || l2va > SH3_P1SEG_END) { 111 _kvm_err(kd, 0, "invalid level 1 pte: out of P1"); 112 goto bad; 113 } 114 115 /* read level 2 pte */ 116 pteoffset = SH3_P1SEG_TO_PHYS(l2va) + 117 sizeof(pt_entry_t) * l2idx; 118 if (_kvm_pread(kd, kd->pmfd, (char *)&l2pte, sizeof(l2pte), 119 _kvm_pa2off(kd, pteoffset)) != sizeof(l2pte)) { 120 _kvm_syserr(kd, 0, "could not read level 2 pte"); 121 goto bad; 122 } 123 124 /* check pte for validity */ 125 if ((l2pte & PG_V) == 0) { 126 _kvm_err(kd, 0, "invalid level 2 pte: no valid bit"); 127 goto bad; 128 } 129 130 *pa = (l2pte & PG_PPN) | (va & PAGE_MASK); 131 return (PAGE_SIZE - (va & PAGE_MASK)); 132 } 133 134 /* 135 * All other addresses are incorrect. 136 */ 137 _kvm_err(kd, 0, "not a kernel virtual address"); 138 bad: 139 *pa = (paddr_t)-1; 140 return (0); 141 } 142 143 /* 144 * Translate a physical address to a file offset in the crash dump. 145 */ 146 off_t 147 _kvm_pa2off(kvm_t *kd, paddr_t pa) 148 { 149 cpu_kcore_hdr_t *h = kd->cpu_data; 150 phys_ram_seg_t *seg = h->kcore_segs; 151 off_t off = kd->dump_off; 152 u_int i; 153 154 for (i = h->kcore_nsegs; i != 0; i--) { 155 if (pa >= seg->start && pa < seg->start + seg->size) 156 return (off + (pa - seg->start)); 157 off += seg->size; 158 } 159 160 _kvm_err(kd, 0, "physical address out of the image (%lx)", pa); 161 return (0); 162 } 163