Initial import from FreeBSD RELENG_4:
[games.git] / lib / libkvm / kvm_alpha.c
1 /* $FreeBSD: src/lib/libkvm/kvm_alpha.c,v 1.4 1999/12/27 07:14:56 peter Exp $ */
2 /*      $NetBSD: kvm_alpha.c,v 1.7.2.1 1997/11/02 20:34:26 mellon Exp $ */
3
4 /*
5  * Copyright (c) 1994, 1995 Carnegie-Mellon University.
6  * All rights reserved.
7  *
8  * Author: Chris G. Demetriou
9  * 
10  * Permission to use, copy, modify and distribute this software and
11  * its documentation is hereby granted, provided that both the copyright
12  * notice and this permission notice appear in all copies of the
13  * software, derivative works or modified versions, and any portions
14  * thereof, and that both notices appear in supporting documentation.
15  * 
16  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 
17  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 
18  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
19  * 
20  * Carnegie Mellon requests users of this software to return to
21  *
22  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
23  *  School of Computer Science
24  *  Carnegie Mellon University
25  *  Pittsburgh PA 15213-3890
26  *
27  * any improvements or extensions that they make and grant Carnegie the
28  * rights to redistribute these changes.
29  */
30
31 #include <sys/param.h>
32 #include <sys/user.h>
33 #include <sys/proc.h>
34 #include <sys/stat.h>
35 #include <sys/types.h>
36 #include <sys/uio.h>
37 #include <unistd.h>
38 #include <nlist.h>
39 #include <kvm.h>
40
41 #include <vm/vm.h>
42 #include <vm/vm_param.h>
43
44 #include <limits.h>
45 #include <stdlib.h>
46 #include <machine/pmap.h>
47 #include "kvm_private.h"
48
49 static off_t   _kvm_pa2off(kvm_t *kd, u_long pa);
50
51 struct vmstate {
52         u_int64_t       lev1map_pa;             /* PA of Lev1map */
53         u_int64_t       page_size;              /* Page size */
54         u_int64_t       nmemsegs;               /* Number of RAM segm */
55 };
56
57 void
58 _kvm_freevtop(kd)
59         kvm_t *kd;
60 {
61
62         /* Not actually used for anything right now, but safe. */
63         if (kd->vmst != 0)
64                 free(kd->vmst);
65 }
66
67 int
68 _kvm_initvtop(kd)
69         kvm_t *kd;
70 {
71         struct vmstate *vm;
72         struct nlist nlist[2];
73         u_long pa;
74
75         vm = (struct vmstate *)_kvm_malloc(kd, sizeof(*vm));
76         if (vm == 0) {
77                 _kvm_err(kd, kd->program, "cannot allocate vm");
78                 return (-1);
79         }
80         kd->vmst = vm;
81         vm->page_size = ALPHA_PGBYTES;
82
83         nlist[0].n_name = "_Lev1map";
84         nlist[1].n_name = 0;
85
86         if (kvm_nlist(kd, nlist) != 0) {
87                 _kvm_err(kd, kd->program, "bad namelist");
88                 return (-1);
89         }
90
91         if(!ISALIVE(kd)) {
92                 if (kvm_read(kd, (nlist[0].n_value), &pa, sizeof(pa)) != sizeof(pa)) {
93                         _kvm_err(kd, kd->program, "cannot read Lev1map");
94                         return (-1);
95                 }
96         } else 
97                 if (kvm_read(kd, (nlist[0].n_value), &pa, sizeof(pa)) != sizeof(pa)) {
98                         _kvm_err(kd, kd->program, "cannot read Lev1map");
99                         return (-1);
100                 }
101         vm->lev1map_pa = pa;
102         return (0);
103
104 }
105
106 int
107 _kvm_kvatop(kd, va, pa)
108         kvm_t *kd;
109         u_long va;
110         u_long *pa;
111 {
112         u_int64_t       lev1map_pa;             /* PA of Lev1map */
113         u_int64_t       page_size;
114         int rv, page_off;
115         alpha_pt_entry_t pte;
116         off_t pteoff;
117         struct vmstate *vm;
118         vm = kd->vmst ;
119         
120
121         if (ISALIVE(kd)) {
122                 _kvm_err(kd, 0, "vatop called in live kernel!");
123                 return(0);
124         }
125         lev1map_pa = vm->lev1map_pa;
126         page_size  = vm->page_size;
127
128         page_off = va & (page_size - 1);
129         if (va >= ALPHA_K0SEG_BASE && va <= ALPHA_K0SEG_END) {
130                 /*
131                  * Direct-mapped address: just convert it.
132                  */
133
134                 *pa = ALPHA_K0SEG_TO_PHYS(va);
135                 rv = page_size - page_off;
136         } else if (va >= ALPHA_K1SEG_BASE && va <= ALPHA_K1SEG_END) {
137                 /*
138                  * Real kernel virtual address: do the translation.
139                  */
140 #define PTMASK                  ((1 << ALPHA_PTSHIFT) - 1)
141 #define pmap_lev1_index(va)     (((va) >> ALPHA_L1SHIFT) & PTMASK)
142 #define pmap_lev2_index(va)     (((va) >> ALPHA_L2SHIFT) & PTMASK)
143 #define pmap_lev3_index(va)     (((va) >> ALPHA_L3SHIFT) & PTMASK)
144
145                 /* Find and read the L1 PTE. */
146                 pteoff = lev1map_pa +
147                         pmap_lev1_index(va)  * sizeof(alpha_pt_entry_t);
148                 if (lseek(kd->pmfd, _kvm_pa2off(kd, pteoff), 0) == -1 ||
149                     read(kd->pmfd, (char *)&pte, sizeof(pte)) != sizeof(pte)) {
150                         _kvm_syserr(kd, 0, "could not read L1 PTE");
151                         goto lose;
152                 }
153
154                 /* Find and read the L2 PTE. */
155                 if ((pte & ALPHA_PTE_VALID) == 0) {
156                         _kvm_err(kd, 0, "invalid translation (invalid L1 PTE)");
157                         goto lose;
158                 }
159                 pteoff = ALPHA_PTE_TO_PFN(pte) * page_size +
160                     pmap_lev2_index(va) * sizeof(alpha_pt_entry_t);
161                 if (lseek(kd->pmfd, _kvm_pa2off(kd, pteoff), 0) == -1 ||
162                     read(kd->pmfd, (char *)&pte, sizeof(pte)) != sizeof(pte)) {
163                         _kvm_syserr(kd, 0, "could not read L2 PTE");
164                         goto lose;
165                 }
166
167                 /* Find and read the L3 PTE. */
168                 if ((pte & ALPHA_PTE_VALID) == 0) {
169                         _kvm_err(kd, 0, "invalid translation (invalid L2 PTE)");
170                         goto lose;
171                 }
172                 pteoff = ALPHA_PTE_TO_PFN(pte) * page_size +
173                     pmap_lev3_index(va) * sizeof(alpha_pt_entry_t);
174                 if (lseek(kd->pmfd, _kvm_pa2off(kd, pteoff), 0) == -1 ||
175                     read(kd->pmfd, (char *)&pte, sizeof(pte)) != sizeof(pte)) {
176                         _kvm_syserr(kd, 0, "could not read L3 PTE");
177                         goto lose;
178                 }
179
180                 /* Fill in the PA. */
181                 if ((pte & ALPHA_PTE_VALID) == 0) {
182                         _kvm_err(kd, 0, "invalid translation (invalid L3 PTE)");
183                         goto lose;
184                 }
185                 *pa = ALPHA_PTE_TO_PFN(pte) * page_size + page_off;
186                 rv = page_size - page_off;
187         } else {
188                 /*
189                  * Bogus address (not in KV space): punt.
190                  */
191
192                 _kvm_err(kd, 0, "invalid kernel virtual address");
193 lose:
194                 *pa = -1;
195                 rv = 0;
196         }
197
198         return (rv);
199 }
200
201 /*
202  * Translate a physical address to a file-offset in the crash-dump.
203  */
204 off_t   
205 _kvm_pa2off(kd, pa)
206         kvm_t *kd;
207         u_long pa;
208 {
209         return ALPHA_K0SEG_TO_PHYS(pa);
210 }
211