1/*- 2 * Copyright (c) 1989, 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software developed by the Computer Systems 6 * Engineering group at Lawrence Berkeley Laboratory under DARPA contract 7 * BG 91-66 and contributed to Berkeley. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * from: FreeBSD: src/lib/libkvm/kvm_i386.c,v 1.15 2001/10/10 17:48:43 34 */ 35 36#include <sys/cdefs.h> 37__FBSDID("$FreeBSD$"); 38 39#if defined(LIBC_SCCS) && !defined(lint) 40#if 0 41static char sccsid[] = "@(#)kvm_hp300.c 8.1 (Berkeley) 6/4/93"; 42#endif 43#endif /* LIBC_SCCS and not lint */ 44 45/* 46 * sparc64 machine dependent routines for kvm. 47 */ 48 49#include <sys/param.h> 50#include <sys/user.h> 51#include <sys/proc.h> 52#include <sys/stat.h> 53#include <stdlib.h> 54#include <unistd.h> 55#include <nlist.h> 56#include <kvm.h> 57 58#include <vm/vm.h> 59#include <vm/vm_param.h> 60 61#include <machine/kerneldump.h> 62#include <machine/tte.h> 63#include <machine/tlb.h> 64#include <machine/tsb.h> 65 66#include <limits.h> 67 68#include "kvm_private.h" 69 70#ifndef btop 71#define btop(x) (sparc64_btop(x)) 72#define ptob(x) (sparc64_ptob(x)) 73#endif 74 75struct vmstate { 76 off_t vm_tsb_off; 77 vm_size_t vm_tsb_mask; 78 int vm_nregions; 79 struct sparc64_dump_reg *vm_regions; 80}; 81 82void 83_kvm_freevtop(kvm_t *kd) 84{ 85 if (kd->vmst != 0) { 86 free(kd->vmst->vm_regions); 87 free(kd->vmst); 88 } 89} 90 91static int 92_kvm_read_phys(kvm_t *kd, off_t pos, void *buf, size_t size) 93{ 94 95 /* XXX This has to be a raw file read, kvm_read is virtual. */ 96 if (lseek(kd->pmfd, pos, SEEK_SET) == -1) { 97 _kvm_syserr(kd, kd->program, "_kvm_read_phys: lseek"); 98 return (0); 99 } 100 if (read(kd->pmfd, buf, size) != (ssize_t)size) { 101 _kvm_syserr(kd, kd->program, "_kvm_read_phys: read"); 102 return (0); 103 } 104 return (1); 105} 106 107static int 108_kvm_reg_cmp(const void *a, const void *b) 109{ 110 const struct sparc64_dump_reg *ra, *rb; 111 112 ra = a; 113 rb = b; 114 if (ra->dr_pa < rb->dr_pa) 115 return (-1); 116 else if (ra->dr_pa >= rb->dr_pa + rb->dr_size) 117 return (1); 118 else 119 return (0); 120} 121 122#define KVM_OFF_NOTFOUND 0 123 124static off_t 125_kvm_find_off(struct vmstate *vm, vm_offset_t pa, vm_size_t size) 126{ 127 struct sparc64_dump_reg *reg, key; 128 vm_offset_t o; 129 130 key.dr_pa = pa; 131 reg = bsearch(&key, vm->vm_regions, vm->vm_nregions, 132 sizeof(*vm->vm_regions), _kvm_reg_cmp); 133 if (reg == NULL) 134 return (KVM_OFF_NOTFOUND); 135 o = pa - reg->dr_pa; 136 if (o + size > reg->dr_size) 137 return (KVM_OFF_NOTFOUND); 138 return (reg->dr_offs + o); 139} 140 141int 142_kvm_initvtop(kvm_t *kd) 143{ 144 struct sparc64_dump_hdr hdr; 145 struct sparc64_dump_reg *regs; 146 struct vmstate *vm; 147 size_t regsz; 148 vm_offset_t pa; 149 150 vm = (struct vmstate *)_kvm_malloc(kd, sizeof(*vm)); 151 if (vm == NULL) { 152 _kvm_err(kd, kd->program, "cannot allocate vm"); 153 return (-1); 154 } 155 kd->vmst = vm; 156 157 if (!_kvm_read_phys(kd, 0, &hdr, sizeof(hdr))) 158 goto fail_vm; 159 pa = hdr.dh_tsb_pa; 160 161 regsz = hdr.dh_nregions * sizeof(*regs); 162 regs = _kvm_malloc(kd, regsz); 163 if (regs == NULL) { 164 _kvm_err(kd, kd->program, "cannot allocate regions"); 165 goto fail_vm; 166 } 167 if (!_kvm_read_phys(kd, sizeof(hdr), regs, regsz)) 168 goto fail_regs; 169 qsort(regs, hdr.dh_nregions, sizeof(*regs), _kvm_reg_cmp); 170 171 vm->vm_tsb_mask = hdr.dh_tsb_mask; 172 vm->vm_regions = regs; 173 vm->vm_nregions = hdr.dh_nregions; 174 vm->vm_tsb_off = _kvm_find_off(vm, hdr.dh_tsb_pa, hdr.dh_tsb_size); 175 if (vm->vm_tsb_off == KVM_OFF_NOTFOUND) { 176 _kvm_err(kd, kd->program, "tsb not found in dump"); 177 goto fail_regs; 178 } 179 return (0); 180 181fail_regs: 182 free(regs); 183fail_vm: 184 free(vm); 185 return (-1); 186} 187 188int 189_kvm_kvatop(kvm_t *kd, u_long va, off_t *pa) 190{ 191 struct tte tte; 192 off_t tte_off; 193 u_long vpn; 194 off_t pa_off; 195 u_long pg_off; 196 int rest; 197 198 pg_off = va & PAGE_MASK; 199 if (va >= VM_MIN_DIRECT_ADDRESS) 200 pa_off = TLB_DIRECT_TO_PHYS(va) & ~PAGE_MASK; 201 else { 202 vpn = btop(va); 203 tte_off = kd->vmst->vm_tsb_off + 204 ((vpn & kd->vmst->vm_tsb_mask) << TTE_SHIFT); 205 if (!_kvm_read_phys(kd, tte_off, &tte, sizeof(tte))) 206 goto invalid; 207 if (!tte_match(&tte, va)) 208 goto invalid; 209 pa_off = TTE_GET_PA(&tte); 210 } 211 rest = PAGE_SIZE - pg_off; 212 pa_off = _kvm_find_off(kd->vmst, pa_off, rest); 213 if (pa_off == KVM_OFF_NOTFOUND) 214 goto invalid; 215 *pa = pa_off + pg_off; 216 return (rest); 217 218invalid: 219 _kvm_err(kd, 0, "invalid address (%lx)", va); 220 return (0); 221} 222