xref: /openbsd-src/lib/libkvm/kvm_alpha.c (revision 0e64ee4c2b175b1ffc335440a90100bf53ad4596)
1*0e64ee4cSderaadt /*	$OpenBSD: kvm_alpha.c,v 1.17 2021/12/01 16:53:28 deraadt Exp $	*/
203f48ff6Sniklas /*	$NetBSD: kvm_alpha.c,v 1.5 1996/10/01 21:12:05 cgd Exp $	*/
3df930be7Sderaadt 
4df930be7Sderaadt /*
5df930be7Sderaadt  * Copyright (c) 1994, 1995 Carnegie-Mellon University.
6df930be7Sderaadt  * All rights reserved.
7df930be7Sderaadt  *
8df930be7Sderaadt  * Author: Chris G. Demetriou
9df930be7Sderaadt  *
10df930be7Sderaadt  * Permission to use, copy, modify and distribute this software and
11df930be7Sderaadt  * its documentation is hereby granted, provided that both the copyright
12df930be7Sderaadt  * notice and this permission notice appear in all copies of the
13df930be7Sderaadt  * software, derivative works or modified versions, and any portions
14df930be7Sderaadt  * thereof, and that both notices appear in supporting documentation.
15df930be7Sderaadt  *
16df930be7Sderaadt  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
17df930be7Sderaadt  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
18df930be7Sderaadt  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
19df930be7Sderaadt  *
20df930be7Sderaadt  * Carnegie Mellon requests users of this software to return to
21df930be7Sderaadt  *
22df930be7Sderaadt  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
23df930be7Sderaadt  *  School of Computer Science
24df930be7Sderaadt  *  Carnegie Mellon University
25df930be7Sderaadt  *  Pittsburgh PA 15213-3890
26df930be7Sderaadt  *
27df930be7Sderaadt  * any improvements or extensions that they make and grant Carnegie the
28df930be7Sderaadt  * rights to redistribute these changes.
29df930be7Sderaadt  */
30df930be7Sderaadt 
3185207a7fSericj #define __KVM_ALPHA_PRIVATE	     /* see <machine/pte.h> */
3285207a7fSericj 
33*0e64ee4cSderaadt #include <sys/types.h>
34*0e64ee4cSderaadt #include <sys/signal.h>
35df930be7Sderaadt #include <sys/proc.h>
36df930be7Sderaadt #include <sys/stat.h>
3703f48ff6Sniklas #include <sys/kcore.h>
3803f48ff6Sniklas #include <machine/kcore.h>
39df930be7Sderaadt #include <unistd.h>
40b7e5637aSmiod #include <stdlib.h>
41df930be7Sderaadt #include <nlist.h>
42df930be7Sderaadt #include <kvm.h>
43df930be7Sderaadt 
4479f7dc0bSart #include <uvm/uvm_extern.h>
4571007b88Sart #include <machine/vmparam.h>
4671007b88Sart #include <machine/pmap.h>
47df930be7Sderaadt 
48df930be7Sderaadt #include <limits.h>
49df930be7Sderaadt #include <db.h>
50df930be7Sderaadt 
51df930be7Sderaadt #include "kvm_private.h"
52df930be7Sderaadt 
5385207a7fSericj struct vmstate {
5485207a7fSericj 	vsize_t	page_shift;
5585207a7fSericj };
5685207a7fSericj 
57df930be7Sderaadt void
_kvm_freevtop(kvm_t * kd)58551fad64Sderaadt _kvm_freevtop(kvm_t *kd)
59df930be7Sderaadt {
60df930be7Sderaadt 
6103f48ff6Sniklas 	/* Not actually used for anything right now, but safe. */
6203f48ff6Sniklas 	free(kd->vmst);
63551fad64Sderaadt 	kd->vmst = NULL;
64551fad64Sderaadt }
65df930be7Sderaadt 
66df930be7Sderaadt int
_kvm_initvtop(kvm_t * kd)67551fad64Sderaadt _kvm_initvtop(kvm_t *kd)
68df930be7Sderaadt {
6985207a7fSericj 	cpu_kcore_hdr_t *cpu_kh;
7085207a7fSericj 	struct vmstate *vm;
71df930be7Sderaadt 
7285207a7fSericj 	vm = (struct vmstate *)_kvm_malloc(kd, sizeof(*vm));
7385207a7fSericj 	if (vm == NULL)
7485207a7fSericj 		return (-1);
7585207a7fSericj 
7685207a7fSericj 	cpu_kh = kd->cpu_data;
7785207a7fSericj 
7885207a7fSericj 	/* Compute page_shift. */
7985207a7fSericj 	for (vm->page_shift = 0; (1L << vm->page_shift) < cpu_kh->page_size;
8085207a7fSericj 	    vm->page_shift++)
8185207a7fSericj 		/* nothing */ ;
8285207a7fSericj 	if ((1L << vm->page_shift) != cpu_kh->page_size) {
8385207a7fSericj 		free(vm);
8485207a7fSericj 		return (-1);
8585207a7fSericj 	}
8685207a7fSericj 
8785207a7fSericj 	kd->vmst = vm;
88df930be7Sderaadt 	return (0);
89df930be7Sderaadt }
90df930be7Sderaadt 
91df930be7Sderaadt int
_kvm_kvatop(kvm_t * kd,u_long va,paddr_t * pa)92fdd3f45bSmickey _kvm_kvatop(kvm_t *kd, u_long va, paddr_t *pa)
93df930be7Sderaadt {
9403f48ff6Sniklas 	cpu_kcore_hdr_t *cpu_kh;
9585207a7fSericj 	struct vmstate *vm;
9603f48ff6Sniklas 	int rv, page_off;
9703f48ff6Sniklas 	alpha_pt_entry_t pte;
9803f48ff6Sniklas 	off_t pteoff;
99df930be7Sderaadt 
1003ad56321Smickey 	if (!kd->vmst) {
1013ad56321Smickey 		_kvm_err(kd, 0, "vatop called before initvtop");
1023ad56321Smickey 		return (0);
1033ad56321Smickey 	}
1043ad56321Smickey 
10503f48ff6Sniklas 	if (ISALIVE(kd)) {
10603f48ff6Sniklas 		_kvm_err(kd, 0, "vatop called in live kernel!");
107df930be7Sderaadt 		return (0);
108df930be7Sderaadt 	}
10903f48ff6Sniklas 
11003f48ff6Sniklas 	cpu_kh = kd->cpu_data;
11185207a7fSericj 	vm = kd->vmst;
11203f48ff6Sniklas 	page_off = va & (cpu_kh->page_size - 1);
11303f48ff6Sniklas 
1147bfdd76bSart #ifndef PAGE_SHIFT
11585207a7fSericj #define	PAGE_SHIFT      vm->page_shift
1167bfdd76bSart #endif
11785207a7fSericj 
11803f48ff6Sniklas 	if (va >= ALPHA_K0SEG_BASE && va <= ALPHA_K0SEG_END) {
11903f48ff6Sniklas 		/*
12003f48ff6Sniklas 		 * Direct-mapped address: just convert it.
12103f48ff6Sniklas 		 */
12203f48ff6Sniklas 
12303f48ff6Sniklas 		*pa = ALPHA_K0SEG_TO_PHYS(va);
12403f48ff6Sniklas 		rv = cpu_kh->page_size - page_off;
12503f48ff6Sniklas 	} else if (va >= ALPHA_K1SEG_BASE && va <= ALPHA_K1SEG_END) {
12603f48ff6Sniklas 		/*
12703f48ff6Sniklas 		 * Real kernel virtual address: do the translation.
12803f48ff6Sniklas 		 */
12903f48ff6Sniklas 
13003f48ff6Sniklas 		/* Find and read the L1 PTE. */
13103f48ff6Sniklas 		pteoff = cpu_kh->lev1map_pa +
13285207a7fSericj 		    l1pte_index(va) * sizeof(alpha_pt_entry_t);
133551fad64Sderaadt 		if (_kvm_pread(kd, kd->pmfd, (char *)&pte, sizeof(pte),
134551fad64Sderaadt 		    (off_t)_kvm_pa2off(kd, pteoff)) != sizeof(pte)) {
13503f48ff6Sniklas 			_kvm_syserr(kd, 0, "could not read L1 PTE");
13603f48ff6Sniklas 			goto lose;
13703f48ff6Sniklas 		}
13803f48ff6Sniklas 
13903f48ff6Sniklas 		/* Find and read the L2 PTE. */
14003f48ff6Sniklas 		if ((pte & ALPHA_PTE_VALID) == 0) {
14103f48ff6Sniklas 			_kvm_err(kd, 0, "invalid translation (invalid L1 PTE)");
14203f48ff6Sniklas 			goto lose;
14303f48ff6Sniklas 		}
14403f48ff6Sniklas 		pteoff = ALPHA_PTE_TO_PFN(pte) * cpu_kh->page_size +
14585207a7fSericj 		    l2pte_index(va) * sizeof(alpha_pt_entry_t);
146551fad64Sderaadt 		if (_kvm_pread(kd, kd->pmfd, (char *)&pte, sizeof(pte),
147551fad64Sderaadt 		    (off_t)_kvm_pa2off(kd, pteoff)) != sizeof(pte)) {
14803f48ff6Sniklas 			_kvm_syserr(kd, 0, "could not read L2 PTE");
14903f48ff6Sniklas 			goto lose;
15003f48ff6Sniklas 		}
15103f48ff6Sniklas 
15203f48ff6Sniklas 		/* Find and read the L3 PTE. */
15303f48ff6Sniklas 		if ((pte & ALPHA_PTE_VALID) == 0) {
15403f48ff6Sniklas 			_kvm_err(kd, 0, "invalid translation (invalid L2 PTE)");
15503f48ff6Sniklas 			goto lose;
15603f48ff6Sniklas 		}
15703f48ff6Sniklas 		pteoff = ALPHA_PTE_TO_PFN(pte) * cpu_kh->page_size +
15885207a7fSericj 		    l3pte_index(va) * sizeof(alpha_pt_entry_t);
159551fad64Sderaadt 		if (_kvm_pread(kd, kd->pmfd, (char *)&pte, sizeof(pte),
160551fad64Sderaadt 		    (off_t)_kvm_pa2off(kd, pteoff)) != sizeof(pte)) {
16103f48ff6Sniklas 			_kvm_syserr(kd, 0, "could not read L3 PTE");
16203f48ff6Sniklas 			goto lose;
16303f48ff6Sniklas 		}
16403f48ff6Sniklas 
16503f48ff6Sniklas 		/* Fill in the PA. */
16603f48ff6Sniklas 		if ((pte & ALPHA_PTE_VALID) == 0) {
16703f48ff6Sniklas 			_kvm_err(kd, 0, "invalid translation (invalid L3 PTE)");
16803f48ff6Sniklas 			goto lose;
16903f48ff6Sniklas 		}
17003f48ff6Sniklas 		*pa = ALPHA_PTE_TO_PFN(pte) * cpu_kh->page_size + page_off;
17103f48ff6Sniklas 		rv = cpu_kh->page_size - page_off;
17203f48ff6Sniklas 	} else {
17303f48ff6Sniklas 		/*
17403f48ff6Sniklas 		 * Bogus address (not in KV space): punt.
17503f48ff6Sniklas 		 */
17603f48ff6Sniklas 
17703f48ff6Sniklas 		_kvm_err(kd, 0, "invalid kernel virtual address");
17803f48ff6Sniklas lose:
17903f48ff6Sniklas 		*pa = -1;
18003f48ff6Sniklas 		rv = 0;
18103f48ff6Sniklas 	}
18203f48ff6Sniklas 
18303f48ff6Sniklas 	return (rv);
18403f48ff6Sniklas }
18503f48ff6Sniklas 
18603f48ff6Sniklas /*
18703f48ff6Sniklas  * Translate a physical address to a file-offset in the crash-dump.
18803f48ff6Sniklas  */
18903f48ff6Sniklas off_t
_kvm_pa2off(kvm_t * kd,paddr_t pa)190fdd3f45bSmickey _kvm_pa2off(kvm_t *kd, paddr_t pa)
19103f48ff6Sniklas {
19203f48ff6Sniklas 	cpu_kcore_hdr_t *cpu_kh;
19385207a7fSericj 	phys_ram_seg_t *ramsegs;
19485207a7fSericj 	off_t off;
19585207a7fSericj 	int i;
19603f48ff6Sniklas 
19703f48ff6Sniklas 	cpu_kh = kd->cpu_data;
198*0e64ee4cSderaadt 	ramsegs = (phys_ram_seg_t *)((char *)cpu_kh + _ALIGN(sizeof *cpu_kh));
19903f48ff6Sniklas 
20003f48ff6Sniklas 	off = 0;
20185207a7fSericj 	for (i = 0; i < cpu_kh->nmemsegs; i++) {
20285207a7fSericj 		if (pa >= ramsegs[i].start &&
20385207a7fSericj 		   (pa - ramsegs[i].start) < ramsegs[i].size) {
20485207a7fSericj 			off += (pa - ramsegs[i].start);
20585207a7fSericj 			break;
20685207a7fSericj 		}
20785207a7fSericj 		off += ramsegs[i].size;
20885207a7fSericj 	}
20985207a7fSericj 	return (kd->dump_off + off);
21003f48ff6Sniklas }
211