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