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