kvm_ia64.c revision 169760
185361Sdfr/* $FreeBSD: head/lib/libkvm/kvm_ia64.c 169760 2007-05-19 13:11:27Z marcel $ */ 285361Sdfr/* $NetBSD: kvm_alpha.c,v 1.7.2.1 1997/11/02 20:34:26 mellon Exp $ */ 385361Sdfr 485361Sdfr/* 585361Sdfr * Copyright (c) 1994, 1995 Carnegie-Mellon University. 685361Sdfr * All rights reserved. 785361Sdfr * 885361Sdfr * Author: Chris G. Demetriou 985361Sdfr * 1085361Sdfr * Permission to use, copy, modify and distribute this software and 1185361Sdfr * its documentation is hereby granted, provided that both the copyright 1285361Sdfr * notice and this permission notice appear in all copies of the 1385361Sdfr * software, derivative works or modified versions, and any portions 1485361Sdfr * thereof, and that both notices appear in supporting documentation. 1585361Sdfr * 1685361Sdfr * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 1785361Sdfr * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 1885361Sdfr * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 1985361Sdfr * 2085361Sdfr * Carnegie Mellon requests users of this software to return to 2185361Sdfr * 2285361Sdfr * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 2385361Sdfr * School of Computer Science 2485361Sdfr * Carnegie Mellon University 2585361Sdfr * Pittsburgh PA 15213-3890 2685361Sdfr * 2785361Sdfr * any improvements or extensions that they make and grant Carnegie the 2885361Sdfr * rights to redistribute these changes. 2985361Sdfr */ 3085361Sdfr 3185361Sdfr#include <sys/types.h> 32105607Smarcel#include <sys/elf64.h> 33105607Smarcel#include <sys/mman.h> 3485361Sdfr 35105607Smarcel#include <machine/pte.h> 3685361Sdfr 37105607Smarcel#include <kvm.h> 3885361Sdfr#include <limits.h> 3985361Sdfr#include <stdlib.h> 40105607Smarcel#include <unistd.h> 41105607Smarcel 4285361Sdfr#include "kvm_private.h" 4385361Sdfr 44105607Smarcel#define REGION_BASE(n) (((uint64_t)(n)) << 61) 45105607Smarcel#define REGION_ADDR(x) ((x) & ((1LL<<61)-1LL)) 4685361Sdfr 47105607Smarcel#define NKPTEPG(ps) ((ps) / sizeof(struct ia64_lpte)) 48169760Smarcel#define NKPTEDIR(ps) ((ps) >> 3) 49105607Smarcel#define KPTE_PTE_INDEX(va,ps) (((va)/(ps)) % NKPTEPG(ps)) 50169760Smarcel#define KPTE_DIR0_INDEX(va,ps) ((((va)/(ps)) / NKPTEPG(ps)) / NKPTEDIR(ps)) 51169760Smarcel#define KPTE_DIR1_INDEX(va,ps) ((((va)/(ps)) / NKPTEPG(ps)) % NKPTEDIR(ps)) 52105607Smarcel 5385361Sdfrstruct vmstate { 54105607Smarcel void *mmapbase; 55105607Smarcel size_t mmapsize; 56105607Smarcel size_t pagesize; 57105607Smarcel u_long kptdir; 5885361Sdfr}; 5985361Sdfr 60105607Smarcel/* 61105607Smarcel * Map the ELF headers into the process' address space. We do this in two 62105607Smarcel * steps: first the ELF header itself and using that information the whole 63105607Smarcel * set of headers. 64105607Smarcel */ 65105607Smarcelstatic int 66105607Smarcel_kvm_maphdrs(kvm_t *kd, size_t sz) 67105607Smarcel{ 68105607Smarcel struct vmstate *vm = kd->vmst; 69105607Smarcel 70105607Smarcel /* munmap() previous mmap(). */ 71105607Smarcel if (vm->mmapbase != NULL) { 72105607Smarcel munmap(vm->mmapbase, vm->mmapsize); 73105607Smarcel vm->mmapbase = NULL; 74105607Smarcel } 75105607Smarcel 76105607Smarcel vm->mmapsize = sz; 77135585Smarcel vm->mmapbase = mmap(NULL, sz, PROT_READ, MAP_PRIVATE, kd->pmfd, 0); 78105607Smarcel if (vm->mmapbase == MAP_FAILED) { 79105607Smarcel _kvm_err(kd, kd->program, "cannot mmap corefile"); 80105607Smarcel return (-1); 81105607Smarcel } 82105607Smarcel 83105607Smarcel return (0); 84105607Smarcel} 85105607Smarcel 86105607Smarcel/* 87105607Smarcel * Translate a physical memory address to a file-offset in the crash-dump. 88105607Smarcel */ 89105607Smarcelstatic size_t 90147672Speter_kvm_pa2off(kvm_t *kd, uint64_t pa, off_t *ofs, size_t pgsz) 91105607Smarcel{ 92105607Smarcel Elf64_Ehdr *e = kd->vmst->mmapbase; 93105607Smarcel Elf64_Phdr *p = (Elf64_Phdr*)((char*)e + e->e_phoff); 94105607Smarcel int n = e->e_phnum; 95105607Smarcel 96105607Smarcel if (pa != REGION_ADDR(pa)) { 97105607Smarcel _kvm_err(kd, kd->program, "internal error"); 98105607Smarcel return (0); 99105607Smarcel } 100105607Smarcel 101105607Smarcel while (n && (pa < p->p_paddr || pa >= p->p_paddr + p->p_memsz)) 102105607Smarcel p++, n--; 103105607Smarcel if (n == 0) 104105607Smarcel return (0); 105105607Smarcel 106105607Smarcel *ofs = (pa - p->p_paddr) + p->p_offset; 107105607Smarcel if (pgsz == 0) 108105607Smarcel return (p->p_memsz - (pa - p->p_paddr)); 109105607Smarcel return (pgsz - ((size_t)pa & (pgsz - 1))); 110105607Smarcel} 111105607Smarcel 11285361Sdfrvoid 11385478Sdfr_kvm_freevtop(kvm_t *kd) 11485361Sdfr{ 115105607Smarcel struct vmstate *vm = kd->vmst; 11685361Sdfr 117105607Smarcel if (vm->mmapbase != NULL) 118105607Smarcel munmap(vm->mmapbase, vm->mmapsize); 119105607Smarcel free(vm); 120105607Smarcel kd->vmst = NULL; 12185361Sdfr} 12285361Sdfr 12385361Sdfrint 12485478Sdfr_kvm_initvtop(kvm_t *kd) 12585361Sdfr{ 12685361Sdfr struct nlist nlist[2]; 127105607Smarcel uint64_t va; 128105607Smarcel Elf64_Ehdr *ehdr; 129105607Smarcel size_t hdrsz; 13085361Sdfr 131105607Smarcel kd->vmst = (struct vmstate *)_kvm_malloc(kd, sizeof(*kd->vmst)); 132105607Smarcel if (kd->vmst == NULL) { 13385361Sdfr _kvm_err(kd, kd->program, "cannot allocate vm"); 13485361Sdfr return (-1); 13585361Sdfr } 13685361Sdfr 137105607Smarcel kd->vmst->pagesize = getpagesize(); 138105607Smarcel 139105607Smarcel if (_kvm_maphdrs(kd, sizeof(Elf64_Ehdr)) == -1) 140105607Smarcel return (-1); 141105607Smarcel 142105607Smarcel ehdr = kd->vmst->mmapbase; 143105607Smarcel hdrsz = ehdr->e_phoff + ehdr->e_phentsize * ehdr->e_phnum; 144105607Smarcel if (_kvm_maphdrs(kd, hdrsz) == -1) 145105607Smarcel return (-1); 146105607Smarcel 147105607Smarcel /* 148105607Smarcel * At this point we've got enough information to use kvm_read() for 149105607Smarcel * direct mapped (ie region 6 and region 7) address, such as symbol 150105607Smarcel * addresses/values. 151105607Smarcel */ 152105607Smarcel 153115084Smarcel nlist[0].n_name = "ia64_kptdir"; 15485361Sdfr nlist[1].n_name = 0; 15585361Sdfr 15685361Sdfr if (kvm_nlist(kd, nlist) != 0) { 15785361Sdfr _kvm_err(kd, kd->program, "bad namelist"); 15885361Sdfr return (-1); 15985361Sdfr } 16085361Sdfr 161105607Smarcel if (kvm_read(kd, (nlist[0].n_value), &va, sizeof(va)) != sizeof(va)) { 162105607Smarcel _kvm_err(kd, kd->program, "cannot read kptdir"); 163105607Smarcel return (-1); 164105607Smarcel } 165105607Smarcel 166105607Smarcel if (va < REGION_BASE(6)) { 167105607Smarcel _kvm_err(kd, kd->program, "kptdir is itself virtual"); 168105607Smarcel return (-1); 169105607Smarcel } 170105607Smarcel 171105607Smarcel kd->vmst->kptdir = va; 17285361Sdfr return (0); 17385361Sdfr} 17485361Sdfr 17585361Sdfrint 176147672Speter_kvm_kvatop(kvm_t *kd, u_long va, off_t *pa) 17785361Sdfr{ 17885478Sdfr struct ia64_lpte pte; 179169760Smarcel uint64_t pgaddr, pt0addr, pt1addr; 180169760Smarcel size_t pgno, pgsz, pt0no, pt1no; 18185478Sdfr 182105607Smarcel if (va >= REGION_BASE(6)) { 183105607Smarcel /* Regions 6 and 7: direct mapped. */ 184105607Smarcel return (_kvm_pa2off(kd, REGION_ADDR(va), pa, 0)); 185105607Smarcel } else if (va >= REGION_BASE(5)) { 186105607Smarcel /* Region 5: virtual. */ 187105607Smarcel va = REGION_ADDR(va); 188105607Smarcel pgsz = kd->vmst->pagesize; 189169760Smarcel pt0no = KPTE_DIR0_INDEX(va, pgsz); 190169760Smarcel pt1no = KPTE_DIR1_INDEX(va, pgsz); 191105607Smarcel pgno = KPTE_PTE_INDEX(va, pgsz); 192169760Smarcel if (pt0no >= NKPTEDIR(pgsz)) 193105607Smarcel goto fail; 194169760Smarcel pt0addr = kd->vmst->kptdir + (pt0no << 3); 195169760Smarcel if (kvm_read(kd, pt0addr, &pt1addr, 8) != 8) 196105607Smarcel goto fail; 197169760Smarcel if (pt1addr == 0) 198169760Smarcel goto fail; 199169760Smarcel pt1addr += pt1no << 3; 200169760Smarcel if (kvm_read(kd, pt1addr, &pgaddr, 8) != 8) 201169760Smarcel goto fail; 202105607Smarcel if (pgaddr == 0) 203105607Smarcel goto fail; 204169760Smarcel pgaddr += pgno * sizeof(pte); 205105607Smarcel if (kvm_read(kd, pgaddr, &pte, sizeof(pte)) != sizeof(pte)) 206105607Smarcel goto fail; 207135590Smarcel if (!(pte.pte & PTE_PRESENT)) 208105607Smarcel goto fail; 209135590Smarcel va = (pte.pte & PTE_PPN_MASK) + (va & (pgsz - 1)); 210105607Smarcel return (_kvm_pa2off(kd, va, pa, pgsz)); 21185361Sdfr } 21285361Sdfr 213105607Smarcel fail: 214105607Smarcel _kvm_err(kd, kd->program, "invalid kernel virtual address"); 215105607Smarcel *pa = ~0UL; 216105607Smarcel return (0); 21785361Sdfr} 218