xref: /original-bsd/old/adb/adb.hp300/access.c (revision c3e32dec)
1 #ifndef lint
2 static	char sccsid[] = "@(#)access.c	4.8 10/13/84";
3 #endif
4 /*
5  * Adb: access data in file/process address space.
6  *
7  * The routines in this file access referenced data using
8  * the maps to access files, ptrace to access subprocesses,
9  * or the system page tables when debugging the kernel,
10  * to translate virtual to physical addresses.
11  */
12 
13 #include "defs.h"
14 
15 
16 MAP		txtmap;
17 MAP		datmap;
18 INT		wtflag;
19 STRING		errflg;
20 int		errno;
21 
22 INT		pid;
23 
24 /*
25  * Primitives: put a value in a space, get a value from a space
26  * and get a word or byte not returning if an error occurred.
27  */
28 put(addr, space, value)
29     off_t addr; { (void) access(WT, addr, space, value); }
30 
31 #if vax || pdp11
32 u_int
33 get(addr, space)
34     off_t addr; { return (access(RD, addr, space, 0)); }
35 
36 u_int
37 lchkget(addr, space)
38     off_t addr; { u_int w = get(addr, space); chkerr(); return(w); }
39 #endif
40 
41 #ifdef mc68000
42 /*
43  * 68000 Unices don't like odd addresses.
44  */
45 u_int
46 get(addr, space)
47     off_t addr;
48 {
49     u_int data;
50 
51     if (addr & 1) {
52 	data = access(RD, addr - 1, space, 0);
53 	return ((data >> 8) & 0xffff);
54     }
55     data = access(RD, addr, space, 0);
56     return ((data >> 16) & 0xffff);
57 }
58 
59 u_int
60 lget(addr, space)
61     off_t addr;
62 {
63     if (addr & 1) {
64 	u_int data = get(addr, space);
65 	return (get(addr + 2, space) | (data << 16));
66     }
67     return (access(RD, addr, space, 0));
68 }
69 
70 u_int
71 lchkget(addr, space)
72     off_t addr; { u_int w = lget(addr, space); chkerr(); return(w); }
73 #endif
74 
75 #if !pdp11 && !vax && !mc68000
76 help!
77 #endif
78 
79 u_int
80 chkget(addr, space)
81     off_t addr; { u_int w = get(addr, space); chkerr(); return(w); }
82 
83 u_int
84 bchkget(addr, space)
85     off_t addr; { return(lobyte(chkget(addr, space))); }
86 
87 /*
88  * Read/write according to mode at address addr in i/d space.
89  * Value is quantity to be written, if write.
90  *
91  * This routine decides whether to get the data from the subprocess
92  * address space with ptrace, or to get it from the files being
93  * debugged.
94  *
95  * When the kernel is being debugged with the -k flag we interpret
96  * the system page tables for data space, mapping p0 and p1 addresses
97  * relative to the ``current'' process (as specified by its p_addr in
98  * <p) and mapping system space addresses through the system page tables.
99  */
100 access(mode, addr, space, value)
101 	int mode, space, value;
102 	off_t addr;
103 {
104 	int rd = mode == RD;
105 	int file, w;
106 
107 	if (space == NSP)
108 		return(0);
109 	if (pid) {
110 		int pmode = (space&DSP ?
111 		    (rd ? PT_READ_D : PT_WRITE_D) :
112 		    (rd ? PT_READ_I : PT_WRITE_I));
113 
114 		w = ptrace(pmode, pid, addr, value);
115 		if (errno)
116 			rwerr(space);
117 		return (w);
118 	}
119 	w = 0;
120 	if (mode==WT && wtflag==0)
121 		error("not in write mode");
122 	if (!chkmap(&addr, space))
123 		return (0);
124 	file = mapptr(space)->ufd;
125 	if (kernel && space == DSP) {
126 		addr = vtophys(addr);
127 		if (addr == -1)
128 			return (0);
129 	}
130 	if (physrw(file, addr, rd ? &w : &value, rd) < 0)
131 		rwerr(space);
132 	return (w);
133 }
134 
135 #ifdef vax
136 /*
137  * When looking at kernel data space through /dev/mem or
138  * with a core file, do virtual memory mapping.
139  */
140 vtophys(addr)
141 	off_t addr;
142 {
143 	int oldaddr = addr;
144 	int v;
145 	struct pte pte;
146 
147 	addr &= ~0xc0000000;
148 	v = btop(addr);
149 	switch (oldaddr&0xc0000000) {
150 
151 	case 0xc0000000:
152 	case 0x80000000:
153 		/*
154 		 * In system space get system pte.  If
155 		 * valid or reclaimable then physical address
156 		 * is combination of its page number and the page
157 		 * offset of the original address.
158 		 */
159 		if (v >= slr)
160 			goto oor;
161 		addr = ((long)(sbr+v)) &~ 0x80000000;
162 		goto simple;
163 
164 	case 0x40000000:
165 		/*
166 		 * In p1 space must not be in shadow region.
167 		 */
168 		if (v < pcb.pcb_p1lr)
169 			goto oor;
170 		addr = pcb.pcb_p1br+v;
171 		break;
172 
173 	case 0x00000000:
174 		/*
175 		 * In p0 space must not be off end of region.
176 		 */
177 		if (v >= pcb.pcb_p0lr)
178 			goto oor;
179 		addr = pcb.pcb_p0br+v;
180 		break;
181 	oor:
182 		errflg = "address out of segment";
183 		return (-1);
184 	}
185 	/*
186 	 * For p0/p1 address, user-level page table should
187 	 * be in kernel vm.  Do second-level indirect by recursing.
188 	 */
189 	if ((addr & 0x80000000) == 0) {
190 		errflg = "bad p0br or p1br in pcb";
191 		return (-1);
192 	}
193 	addr = vtophys(addr);
194 simple:
195 	/*
196 	 * Addr is now address of the pte of the page we
197 	 * are interested in; get the pte and paste up the
198 	 * physical address.
199 	 */
200 	if (physrw(fcor, addr, (int *)&pte, 1) < 0) {
201 		errflg = "page table botch";
202 		return (-1);
203 	}
204 	/* SHOULD CHECK NOT I/O ADDRESS; NEED CPU TYPE! */
205 	if (pte.pg_v == 0 && (pte.pg_fod || pte.pg_pfnum == 0)) {
206 		errflg = "page not valid/reclaimable";
207 		return (-1);
208 	}
209 	return (ptob(pte.pg_pfnum) + (oldaddr & PGOFSET));
210 }
211 #endif
212 
213 #ifdef hp300
214 
215 #ifdef NEWVM
216 #ifndef btop
217 #define btop	hp300_btop
218 #endif
219 #ifndef ptob
220 #define ptob	hp300_ptob
221 #endif
222 #endif
223 
224 int is68040 = 0;
225 
226 /*
227  * When looking at kernel data space through /dev/mem or
228  * with a core file, do virtual memory mapping.
229  */
230 vtophys(addr)
231 	off_t addr;
232 {
233 	int v;
234 	struct pte pte;
235 	int oldaddr = addr;
236 
237 	if (INKERNEL(addr)) {
238 		/*
239 		 * In system space get system pte.  If
240 		 * valid or reclaimable then physical address
241 		 * is combination of its page number and the page
242 		 * offset of the original address.
243 		 */
244 #ifdef NEWVM
245 		/* locate PTE page in segtab */
246 		if (is68040) {
247 			int steaddr;
248 
249 			steaddr = KVTOPH((int)(sbr+(addr>>SG4_SHIFT1)));
250 			lseek(fcor, (off_t)steaddr, 0);
251 			read(fcor, &pte, sizeof pte);
252 #if 0
253 			printf("va %X: ste1 %X@%X",
254 			       addr, *(int *)&pte, steaddr);
255 #endif
256 			if (*(int *)&pte == SG_NV)
257 				goto bad;
258 			steaddr = (int)(((int *)(*(int *)&pte & SG4_ADDR1)) +
259 					((addr & SG4_MASK2) >> SG4_SHIFT2));
260 			physrw(fcor, steaddr, (int *)&pte, 1);
261 #if 0
262 			printf(" ste2 %X@%X", *(int *)&pte, steaddr);
263 #endif
264 		} else {
265 			lseek(fcor,
266 			      (off_t)KVTOPH((int)(sbr+(addr>>SG_ISHIFT))), 0);
267 			read(fcor, &pte, sizeof pte);
268 #if 0
269 			printf("va %X: ste %X@%X",
270 			       addr, *(int *)&pte, sbr+(addr>>SG_ISHIFT));
271 #endif
272 		}
273 		/* see if STE is valid */
274 		if (*(int *)&pte == SG_NV) {
275 bad:
276 			errflg = "address out of segment";
277 			return(-1);
278 		}
279 		/* desired PTE is within that page */
280 		v = btop(addr & SG_PMASK);
281 		addr = (pte.pg_pfnum << PGSHIFT) + (v * sizeof pte);
282 #else
283 		v = btop(addr - KERNOFF);
284 		addr = (long)(sbr+v) + lowram;
285 #endif
286 	}
287 	else if (INUDOT(addr)) {
288 		addr -= kernudot;
289 		addr += masterpcbb;
290 		return(vtophys(addr));
291 	}
292 	else /* user space */ {
293 #ifdef NEWVM
294 		errflg = "cannot translate user addresses";
295 		return (-1);
296 #else
297 		v = btop(addr);
298 		/*
299 		 * Must be within bounds of p0 or p1 regions.
300 		 */
301 		if (v < pcb.pcb_p0lr)
302 			addr = pcb.pcb_p0br+v;
303 		else if (v >= pcb.pcb_p1lr)
304 			addr = pcb.pcb_p1br+v;
305 		else {
306 			errflg = "address out of segment";
307 			return (-1);
308 		}
309 		/*
310 		 * For p0/p1 address, user-level page table should
311 		 * be in kernel vm.  Do second-level indirect by recursing.
312 		 */
313 		if (!INKERNEL(addr)) {
314 			errflg = "bad p0br or p1br in pcb";
315 			return (-1);
316 		}
317 		addr = vtophys(addr);
318 #endif
319 	}
320 	/*
321 	 * Addr is now address of the pte of the page we
322 	 * are interested in; get the pte and paste up the
323 	 * physical address.
324 	 */
325 	if (physrw(fcor, addr, (int *)&pte, 1) < 0) {
326 		errflg = "page table botch";
327 		return (-1);
328 	}
329 	if (pte.pg_v == 0 &&
330 #ifdef NEWVM
331 	    pte.pg_pfnum == 0
332 #else
333 	    (pte.pg_fod || pte.pg_pfnum == 0)
334 #endif
335 	) {
336 		errflg = "page not valid/reclaimable";
337 		return (-1);
338 	}
339 #if 0
340 	printf(" -> pte %X@%X -> addr %X\n",
341 	       *(int *)&pte, addr, ptob(pte.pg_pfnum) + (oldaddr & PGOFSET));
342 #endif
343 	return (ptob(pte.pg_pfnum) + (oldaddr & PGOFSET));
344 }
345 #endif
346 
347 #if !vax && !hp300
348 help!
349 #endif
350 
351 rwerr(space)
352 	int space;
353 {
354 
355 	if (space & DSP)
356 		errflg = "data address not found";
357 	else if (space & PSP)
358 		errflg = "physical address not found";
359 	else
360 		errflg = "text address not found";
361 }
362 
363 physrw(file, addr, aw, rd)
364 	off_t addr;
365 	int *aw, rd;
366 {
367 
368 #ifdef hp300
369 	if (kcore && !kmem && file == fcor)
370 		addr -= lowram;
371 #endif
372 	if (longseek(file,addr)==0 ||
373 	    (rd ? read(file,aw,sizeof(int)) : write(file,aw,sizeof(int))) < 1)
374 		return (-1);
375 	return (0);
376 }
377 
378 chkmap(addr,space)
379 	REG L_INT	*addr;
380 	REG INT		space;
381 {
382 	REG MAPPTR amap;
383 	amap = mapptr(space);
384 	IF space&STAR ORF !within(*addr,amap->b1,amap->e1)
385 	THEN IF within(*addr,amap->b2,amap->e2)
386 	     THEN *addr += (amap->f2)-(amap->b2);
387 	     ELSE rwerr(space); return(0);
388 	     FI
389 	ELSE *addr += (amap->f1)-(amap->b1);
390 	FI
391 	return(1);
392 }
393 
394 within(addr,lbd,ubd)
395     u_int addr, lbd, ubd; { return(addr>=lbd && addr<ubd); }
396 
397 longseek(f, a)
398     off_t a; { return(lseek(f, a, 0) != -1); }
399 
400 #ifdef NEWVM
401 #undef lseek
402 #undef off_t
403 Lseek(f, o, w)
404     int f, w; Ooff_t o; { return(lseek(f, (off_t)o, w)); }
405 #endif
406