kvm_sparc64.c revision 147672
186560Sjake/*- 286560Sjake * Copyright (c) 1989, 1992, 1993 386560Sjake * The Regents of the University of California. All rights reserved. 486560Sjake * 586560Sjake * This code is derived from software developed by the Computer Systems 686560Sjake * Engineering group at Lawrence Berkeley Laboratory under DARPA contract 786560Sjake * BG 91-66 and contributed to Berkeley. 886560Sjake * 986560Sjake * Redistribution and use in source and binary forms, with or without 1086560Sjake * modification, are permitted provided that the following conditions 1186560Sjake * are met: 1286560Sjake * 1. Redistributions of source code must retain the above copyright 1386560Sjake * notice, this list of conditions and the following disclaimer. 1486560Sjake * 2. Redistributions in binary form must reproduce the above copyright 1586560Sjake * notice, this list of conditions and the following disclaimer in the 1686560Sjake * documentation and/or other materials provided with the distribution. 1786560Sjake * 3. All advertising materials mentioning features or use of this software 1886560Sjake * must display the following acknowledgement: 1986560Sjake * This product includes software developed by the University of 2086560Sjake * California, Berkeley and its contributors. 2186560Sjake * 4. Neither the name of the University nor the names of its contributors 2286560Sjake * may be used to endorse or promote products derived from this software 2386560Sjake * without specific prior written permission. 2486560Sjake * 2586560Sjake * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2686560Sjake * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2786560Sjake * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2886560Sjake * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2986560Sjake * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3086560Sjake * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3186560Sjake * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3286560Sjake * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3386560Sjake * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3486560Sjake * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3586560Sjake * SUCH DAMAGE. 3686560Sjake * 3786560Sjake * from: FreeBSD: src/lib/libkvm/kvm_i386.c,v 1.15 2001/10/10 17:48:43 3886560Sjake */ 3986560Sjake 4086560Sjake#include <sys/cdefs.h> 4186560Sjake__FBSDID("$FreeBSD: head/lib/libkvm/kvm_sparc64.c 147672 2005-06-29 22:39:41Z peter $"); 4286560Sjake 4386560Sjake#if defined(LIBC_SCCS) && !defined(lint) 4486560Sjake#if 0 4586560Sjakestatic char sccsid[] = "@(#)kvm_hp300.c 8.1 (Berkeley) 6/4/93"; 4686560Sjake#endif 4786560Sjake#endif /* LIBC_SCCS and not lint */ 4886560Sjake 4986560Sjake/* 5086560Sjake * sparc64 machine dependent routines for kvm. 5186560Sjake */ 5286560Sjake 5386560Sjake#include <sys/param.h> 5486560Sjake#include <sys/user.h> 5586560Sjake#include <sys/proc.h> 5686560Sjake#include <sys/stat.h> 5786560Sjake#include <stdlib.h> 5886560Sjake#include <unistd.h> 5986560Sjake#include <nlist.h> 6086560Sjake#include <kvm.h> 6186560Sjake 6286560Sjake#include <vm/vm.h> 6386560Sjake#include <vm/vm_param.h> 6486560Sjake 65105532Stmm#include <machine/kerneldump.h> 6686560Sjake#include <machine/tte.h> 67108300Sjake#include <machine/tlb.h> 6886560Sjake#include <machine/tsb.h> 6986560Sjake 7086560Sjake#include <limits.h> 7186560Sjake 7286560Sjake#include "kvm_private.h" 7386560Sjake 7486560Sjake#ifndef btop 7586560Sjake#define btop(x) (sparc64_btop(x)) 7686560Sjake#define ptob(x) (sparc64_ptob(x)) 7786560Sjake#endif 7886560Sjake 7986560Sjakestruct vmstate { 80105532Stmm off_t vm_tsb_off; 81101653Sjake vm_size_t vm_tsb_mask; 82105532Stmm int vm_nregions; 83105532Stmm struct sparc64_dump_reg *vm_regions; 8486560Sjake}; 8586560Sjake 8686560Sjakevoid 8786560Sjake_kvm_freevtop(kvm_t *kd) 8886560Sjake{ 8986560Sjake if (kd->vmst != 0) { 90105532Stmm free(kd->vmst->vm_regions); 9186560Sjake free(kd->vmst); 9286560Sjake } 9386560Sjake} 9486560Sjake 95105532Stmmstatic int 96105532Stmm_kvm_read_phys(kvm_t *kd, off_t pos, void *buf, size_t size) 97105532Stmm{ 98105532Stmm 99105532Stmm /* XXX This has to be a raw file read, kvm_read is virtual. */ 100105532Stmm if (lseek(kd->pmfd, pos, SEEK_SET) == -1) { 101105532Stmm _kvm_syserr(kd, kd->program, "_kvm_read_phys: lseek"); 102105532Stmm return (0); 103105532Stmm } 104105532Stmm if (read(kd->pmfd, buf, size) != size) { 105105532Stmm _kvm_syserr(kd, kd->program, "_kvm_read_phys: read"); 106105532Stmm return (0); 107105532Stmm } 108105532Stmm return (1); 109105532Stmm} 110105532Stmm 111105532Stmmstatic int 112105532Stmm_kvm_reg_cmp(const void *a, const void *b) 113105532Stmm{ 114105532Stmm const struct sparc64_dump_reg *ra, *rb; 115105532Stmm 116105532Stmm ra = a; 117105532Stmm rb = b; 118105532Stmm if (ra->dr_pa < rb->dr_pa) 119105532Stmm return (-1); 120105532Stmm else if (ra->dr_pa >= rb->dr_pa + rb->dr_size) 121105532Stmm return (1); 122105532Stmm else 123105532Stmm return (0); 124105532Stmm} 125105532Stmm 126105532Stmm#define KVM_OFF_NOTFOUND 0 127105532Stmm 128105532Stmmstatic off_t 129105532Stmm_kvm_find_off(struct vmstate *vm, vm_offset_t pa, vm_size_t size) 130105532Stmm{ 131105532Stmm struct sparc64_dump_reg *reg, key; 132105532Stmm vm_offset_t o; 133105532Stmm 134105532Stmm key.dr_pa = pa; 135105532Stmm reg = bsearch(&key, vm->vm_regions, vm->vm_nregions, 136105532Stmm sizeof(*vm->vm_regions), _kvm_reg_cmp); 137105532Stmm if (reg == NULL) 138105532Stmm return (KVM_OFF_NOTFOUND); 139105532Stmm o = pa - reg->dr_pa; 140105532Stmm if (o + size > reg->dr_size) 141105532Stmm return (KVM_OFF_NOTFOUND); 142105532Stmm return (reg->dr_offs + o); 143105532Stmm} 144105532Stmm 14586560Sjakeint 14686560Sjake_kvm_initvtop(kvm_t *kd) 14786560Sjake{ 148105532Stmm struct sparc64_dump_hdr hdr; 149105532Stmm struct sparc64_dump_reg *regs; 15086560Sjake struct vmstate *vm; 151105532Stmm size_t regsz; 152101653Sjake vm_offset_t pa; 153101653Sjake vm_size_t mask; 15486560Sjake 15586560Sjake vm = (struct vmstate *)_kvm_malloc(kd, sizeof(*vm)); 15686560Sjake if (vm == NULL) { 15786560Sjake _kvm_err(kd, kd->program, "cannot allocate vm"); 15886560Sjake return (-1); 15986560Sjake } 16086560Sjake kd->vmst = vm; 16186560Sjake 162105532Stmm if (!_kvm_read_phys(kd, 0, &hdr, sizeof(hdr))) 163105532Stmm goto fail_vm; 164105532Stmm pa = hdr.dh_tsb_pa; 16586560Sjake 166105532Stmm regsz = hdr.dh_nregions * sizeof(*regs); 167105532Stmm regs = _kvm_malloc(kd, regsz); 168105532Stmm if (regs == NULL) { 169105532Stmm _kvm_err(kd, kd->program, "cannot allocate regions"); 170105532Stmm goto fail_vm; 17186560Sjake } 172105532Stmm if (!_kvm_read_phys(kd, sizeof(hdr), regs, regsz)) 173105532Stmm goto fail_regs; 174105532Stmm qsort(regs, hdr.dh_nregions, sizeof(*regs), _kvm_reg_cmp); 175105532Stmm 176105532Stmm vm->vm_tsb_mask = hdr.dh_tsb_mask; 177105532Stmm vm->vm_regions = regs; 178105532Stmm vm->vm_nregions = hdr.dh_nregions; 179105532Stmm vm->vm_tsb_off = _kvm_find_off(vm, hdr.dh_tsb_pa, hdr.dh_tsb_size); 180105532Stmm if (vm->vm_tsb_off == KVM_OFF_NOTFOUND) { 181105532Stmm _kvm_err(kd, kd->program, "tsb not found in dump"); 182105532Stmm goto fail_regs; 18386560Sjake } 18486560Sjake return (0); 185105532Stmm 186105532Stmmfail_regs: 187105532Stmm free(regs); 188105532Stmmfail_vm: 189105532Stmm free(vm); 190105532Stmm return (-1); 19186560Sjake} 19286560Sjake 19388615Sjakeint 194147672Speter_kvm_kvatop(kvm_t *kd, u_long va, off_t *pa) 19586560Sjake{ 19686560Sjake struct vmstate *vm; 19788615Sjake struct tte tte; 198105532Stmm off_t tte_off, pa_off; 199105532Stmm u_long pg_off, vpn; 200105532Stmm int rest; 20186560Sjake 202105532Stmm pg_off = va & PAGE_MASK; 203108300Sjake if (va >= VM_MIN_DIRECT_ADDRESS) 204108300Sjake pa_off = TLB_DIRECT_TO_PHYS(va) & ~PAGE_MASK; 205108300Sjake else { 206108300Sjake vpn = btop(va); 207108300Sjake tte_off = kd->vmst->vm_tsb_off + 208108300Sjake ((vpn & kd->vmst->vm_tsb_mask) << TTE_SHIFT); 209108300Sjake if (!_kvm_read_phys(kd, tte_off, &tte, sizeof(tte))) 210108300Sjake goto invalid; 211108300Sjake if (!tte_match(&tte, va)) 212108300Sjake goto invalid; 213108300Sjake pa_off = TTE_GET_PA(&tte); 214108300Sjake } 215105532Stmm rest = PAGE_SIZE - pg_off; 216108300Sjake pa_off = _kvm_find_off(kd->vmst, pa_off, rest); 217105532Stmm if (pa_off == KVM_OFF_NOTFOUND) 218105532Stmm goto invalid; 219105532Stmm *pa = pa_off + pg_off; 220105532Stmm return (rest); 22186560Sjake 22286560Sjakeinvalid: 22386560Sjake _kvm_err(kd, 0, "invalid address (%x)", va); 22486560Sjake return (0); 22586560Sjake} 226