]>
Commit | Line | Data |
---|---|---|
fb1415ae JG |
1 | /* Machine-dependent code which would otherwise be in inflow.c and core.c, |
2 | for GDB, the GNU debugger. This code is for the HP PA-RISC cpu. | |
3 | Copyright 1986, 1987, 1989, 1990, 1991, 1992 Free Software Foundation, Inc. | |
4 | ||
5 | Contributed by the Center for Software Science at the | |
6 | University of Utah ([email protected]). | |
7 | ||
8 | This file is part of GDB. | |
9 | ||
10 | This program is free software; you can redistribute it and/or modify | |
11 | it under the terms of the GNU General Public License as published by | |
12 | the Free Software Foundation; either version 2 of the License, or | |
13 | (at your option) any later version. | |
14 | ||
15 | This program is distributed in the hope that it will be useful, | |
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | GNU General Public License for more details. | |
19 | ||
20 | You should have received a copy of the GNU General Public License | |
21 | along with this program; if not, write to the Free Software | |
22 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
23 | ||
24 | #include "defs.h" | |
25 | #include "frame.h" | |
26 | #include "inferior.h" | |
27 | #include "value.h" | |
28 | ||
29 | /* For argument passing to the inferior */ | |
30 | #include "symtab.h" | |
31 | ||
32 | #ifdef USG | |
33 | #include <sys/types.h> | |
34 | #endif | |
35 | ||
36 | #include <sys/param.h> | |
37 | #include <sys/dir.h> | |
38 | #include <signal.h> | |
39 | #include <sys/ioctl.h> | |
40 | ||
41 | #ifdef COFF_ENCAPSULATE | |
42 | #include "a.out.encap.h" | |
43 | #else | |
44 | #include <a.out.h> | |
45 | #endif | |
46 | #ifndef N_SET_MAGIC | |
47 | #define N_SET_MAGIC(exec, val) ((exec).a_magic = (val)) | |
48 | #endif | |
49 | ||
50 | /*#include <sys/user.h> After a.out.h */ | |
51 | #include <sys/file.h> | |
52 | #include <sys/stat.h> | |
fb1415ae JG |
53 | #include <machine/psl.h> |
54 | ||
55 | #ifdef KERNELDEBUG | |
56 | #include <sys/vmmac.h> | |
57 | #include <machine/machparam.h> | |
58 | #include <machine/vmparam.h> | |
59 | #include <machine/pde.h> | |
60 | #include <machine/cpu.h> | |
61 | #include <machine/iomod.h> | |
62 | #include <machine/pcb.h> | |
63 | #include <machine/rpb.h> | |
64 | #include <ctype.h> | |
65 | ||
66 | extern int kernel_debugging; | |
67 | extern CORE_ADDR startup_file_start; | |
68 | extern CORE_ADDR startup_file_end; | |
69 | ||
70 | #define KERNOFF ((unsigned)KERNBASE) | |
71 | #define INKERNEL(x) ((x) >= KERNOFF && (x) < KERNOFF + ctob(slr)) | |
72 | ||
73 | static int ok_to_cache(); | |
74 | static void set_kernel_boundaries(); | |
75 | ||
76 | int devmem = 0; | |
77 | int vtophys_ready = 0; | |
78 | int kerneltype; | |
79 | #define OS_BSD 1 | |
80 | #define OS_MACH 2 | |
81 | #endif | |
82 | ||
83 | #include "gdbcore.h" | |
84 | #include "gdbcmd.h" | |
85 | ||
86 | extern int errno; | |
87 | \f | |
88 | ||
89 | ||
90 | ||
91 | ||
92 | ||
93 | /* Last modification time of executable file. | |
94 | Also used in source.c to compare against mtime of a source file. */ | |
95 | ||
96 | extern int exec_mtime; | |
97 | ||
98 | /* Virtual addresses of bounds of the two areas of memory in the core file. */ | |
99 | ||
100 | /* extern CORE_ADDR data_start; */ | |
101 | extern CORE_ADDR data_end; | |
102 | extern CORE_ADDR stack_start; | |
103 | extern CORE_ADDR stack_end; | |
104 | ||
105 | /* Virtual addresses of bounds of two areas of memory in the exec file. | |
106 | Note that the data area in the exec file is used only when there is no core file. */ | |
107 | ||
108 | extern CORE_ADDR text_start; | |
109 | extern CORE_ADDR text_end; | |
110 | ||
111 | extern CORE_ADDR exec_data_start; | |
112 | extern CORE_ADDR exec_data_end; | |
113 | ||
114 | /* Address in executable file of start of text area data. */ | |
115 | ||
116 | extern int text_offset; | |
117 | ||
118 | /* Address in executable file of start of data area data. */ | |
119 | ||
120 | extern int exec_data_offset; | |
121 | ||
122 | /* Address in core file of start of data area data. */ | |
123 | ||
124 | extern int data_offset; | |
125 | ||
126 | /* Address in core file of start of stack area data. */ | |
127 | ||
128 | extern int stack_offset; | |
129 | ||
130 | struct header file_hdr; | |
131 | struct som_exec_auxhdr exec_hdr; | |
132 | \f | |
133 | #ifdef KERNELDEBUG | |
134 | /* | |
135 | * Kernel debugging routines. | |
136 | */ | |
137 | ||
138 | static struct pcb pcb; | |
139 | static struct pde *pdir; | |
140 | static struct hte *htbl; | |
141 | static u_int npdir, nhtbl; | |
142 | ||
143 | static CORE_ADDR | |
144 | ksym_lookup(name) | |
145 | char *name; | |
146 | { | |
147 | struct symbol *sym; | |
148 | int i; | |
149 | ||
150 | if ((i = lookup_misc_func(name)) < 0) | |
151 | error("kernel symbol `%s' not found.", name); | |
152 | ||
153 | return (misc_function_vector[i].address); | |
154 | } | |
155 | ||
156 | /* | |
157 | * (re-)set the variables that tell "inside_entry_file" where to end | |
158 | * a stack backtrace. | |
159 | */ | |
160 | void | |
161 | set_kernel_boundaries() | |
162 | { | |
163 | switch (kerneltype) { | |
164 | case OS_MACH: | |
165 | startup_file_start = ksym_lookup("$syscall"); | |
166 | startup_file_end = ksym_lookup("trap"); | |
167 | break; | |
168 | case OS_BSD: | |
169 | startup_file_start = ksym_lookup("syscallinit"); | |
170 | startup_file_end = ksym_lookup("$syscallexit"); | |
171 | break; | |
172 | } | |
173 | } | |
174 | ||
175 | /* | |
176 | * return true if 'len' bytes starting at 'addr' can be read out as | |
177 | * longwords and/or locally cached (this is mostly for memory mapped | |
178 | * i/o register access when debugging remote kernels). | |
179 | */ | |
180 | static int | |
181 | ok_to_cache(addr, len) | |
182 | { | |
183 | static CORE_ADDR ioptr; | |
184 | ||
185 | if (! ioptr) | |
186 | ioptr = ksym_lookup("ioptr"); | |
187 | ||
188 | if (addr >= ioptr && addr < SPA_HIGH) | |
189 | return (0); | |
190 | ||
191 | return (1); | |
192 | } | |
193 | ||
194 | static | |
195 | physrd(addr, dat, len) | |
196 | u_int addr; | |
197 | char *dat; | |
198 | { | |
199 | if (lseek(corechan, addr, L_SET) == -1) | |
200 | return (-1); | |
201 | if (read(corechan, dat, len) != len) | |
202 | return (-1); | |
203 | ||
204 | return (0); | |
205 | } | |
206 | ||
207 | /* | |
208 | * When looking at kernel data space through /dev/mem or with a core file, do | |
209 | * virtual memory mapping. | |
210 | */ | |
211 | static CORE_ADDR | |
212 | vtophys(space, addr) | |
213 | unsigned space; | |
214 | CORE_ADDR addr; | |
215 | { | |
216 | struct pde *pptr; | |
217 | u_int hindx, vpageno, ppageno; | |
218 | CORE_ADDR phys = ~0; | |
219 | ||
220 | if (!vtophys_ready) { | |
221 | phys = addr; /* XXX for kvread */ | |
222 | } else if (kerneltype == OS_BSD) { | |
223 | /* make offset into a virtual page no */ | |
224 | vpageno = btop(addr); | |
225 | /* | |
226 | * Determine index into hash table, initialize pptr to this | |
227 | * entry (since first word of pte & hte are same), and set | |
228 | * physical page number for first entry in chain. | |
229 | */ | |
230 | hindx = pdirhash(space, addr) & (nhtbl-1); | |
231 | pptr = (struct pde *) &htbl[hindx]; | |
232 | ppageno = pptr->pde_next; | |
233 | while (1) { | |
234 | if (pptr->pde_end) | |
235 | break; | |
236 | pptr = &pdir[ppageno]; | |
237 | /* | |
238 | * If space id & virtual page number match, return | |
239 | * "next PDIR entry of previous PDIR entry" as the | |
240 | * physical page or'd with offset into page. | |
241 | */ | |
242 | if (pptr->pde_space == space && | |
243 | pptr->pde_page == vpageno) { | |
244 | phys = (CORE_ADDR) ((u_int)ptob(ppageno) | | |
245 | (addr & PGOFSET)); | |
246 | break; | |
247 | } | |
248 | ppageno = pptr->pde_next; | |
249 | } | |
250 | } | |
251 | #ifdef MACHKERNELDEBUG | |
252 | else if (kerneltype == OS_MACH) { | |
253 | mach_vtophys(space, addr, &phys); | |
254 | } | |
255 | #endif | |
256 | #if 0 | |
257 | printf("vtophys(%x.%x) -> %x\n", space, addr, phys); | |
258 | #endif | |
259 | return (phys); | |
260 | } | |
261 | ||
262 | static | |
263 | kvread(addr) | |
264 | CORE_ADDR addr; | |
265 | { | |
266 | CORE_ADDR paddr; | |
267 | ||
268 | paddr = vtophys(0, addr); | |
269 | if (paddr != ~0) | |
270 | if (physrd(paddr, (char *)&addr, sizeof(addr)) == 0) | |
271 | return (addr); | |
272 | ||
273 | return (~0); | |
274 | } | |
275 | ||
276 | static void | |
277 | read_pcb(addr) | |
278 | u_int addr; | |
279 | { | |
280 | int i, off; | |
281 | extern char registers[]; | |
282 | static int reg2pcb[] = { | |
283 | /* RPB */ | |
284 | -1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, | |
285 | 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, | |
286 | 45, 52, 51, 75, 74, 49, 53, 54, 55, 56, -1, 70, 66, 67, 68, 69, | |
287 | 71, 72, 73, 34, 42, 43, 44, 46, 47, 58, 59, 60, -1, -1, -1, -1, | |
288 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
289 | -1, -1, -1, -1, | |
290 | /* BSD */ | |
291 | -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, | |
292 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, | |
293 | 43, 64, 67, 68, 67, 47, 51, 52, 53, 54, -1, 35, 31, 32, 33, 34, | |
294 | 36, 37, 38, 39, 40, 41, 42, 44, 45, 56, 57, 58,102,103,104, -1, | |
295 | 70, 71, 72, 73, 74, 75, 76, 77, 78, 80, 82, 84, 86, 88, 90, 92, | |
296 | 94, 96, 98, 100, | |
297 | /* Mach */ | |
298 | -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, | |
299 | 14, 15, 16, -1, -1, -1, -1, -1, -1, -1, -1, 17, -1, -1, 18, -1, | |
300 | 25, -1, -1, -1, -1, 30, -1, -1, -1, -1, -1, 20, -1, -1, -1, 19, | |
301 | 21, 22, 23, 24, 26, 27, -1, 28, 29, -1, -1, -1, -1, -1, -1, -1, | |
302 | 34, 35, 36, 37, 38, 39, 40, 41, -1, -1, -1, -1, -1, -1, -1, -1, | |
303 | 42, 44, 46, 48 | |
304 | }; | |
305 | static struct rpb *rpbaddr = (struct rpb *) 0; | |
306 | static u_int rpbpcbaddr = 0; | |
307 | ||
308 | if (!remote_debugging) { | |
309 | /* | |
310 | * If we are debugging a post-mortem and this is the first | |
311 | * call of read_pcb, read the RPB. Also assoicate the | |
312 | * thread/proc running at the time with the RPB. | |
313 | */ | |
314 | if (!devmem && rpbpcbaddr == 0) { | |
315 | CORE_ADDR raddr = ksym_lookup("rpb"); | |
316 | int usepcb = 1; | |
317 | ||
318 | if (raddr != ~0) { | |
319 | rpbaddr = (struct rpb *) malloc(sizeof *rpbaddr); | |
320 | if (!physrd(raddr, (char *)rpbaddr, sizeof *rpbaddr)) { | |
321 | rpbpcbaddr = addr; | |
322 | usepcb = 0; | |
323 | } | |
324 | } | |
325 | if (usepcb) { | |
326 | error("cannot read rpb, using pcb for registers\n"); | |
327 | if (rpbaddr) | |
328 | free((char *)rpbaddr); | |
329 | rpbpcbaddr = ~0; | |
330 | } | |
331 | } | |
332 | if (physrd (addr, (char *)&pcb, sizeof pcb)) | |
333 | error ("cannot read pcb at %x.\n", addr); | |
334 | } else { | |
335 | if (remote_read_inferior_memory(addr, (char *)&pcb, sizeof pcb)) | |
336 | error ("cannot read pcb at %x.\n", addr); | |
337 | } | |
338 | ||
339 | if (kerneltype == OS_BSD) { | |
340 | printf("p0br %lx p0lr %lx p1br %lx p1lr %lx\n", | |
341 | pcb.pcb_p0br, pcb.pcb_p0lr, pcb.pcb_p1br, pcb.pcb_p1lr); | |
342 | off = NUM_REGS; | |
343 | } else { | |
344 | printf("pcb %lx psw %lx ksp %lx\n", | |
345 | addr, ((int *)&pcb)[31], ((int *)&pcb)[32]); | |
346 | off = NUM_REGS * 2; | |
347 | } | |
348 | /* | |
349 | * get the register values out of the sys pcb and | |
350 | * store them where `read_register' will find them. | |
351 | */ | |
352 | bzero(registers, REGISTER_BYTES); | |
353 | for (i = 0; i < NUM_REGS; ++i) | |
354 | if (reg2pcb[i+off] != -1) | |
355 | supply_register(i, &((int *)&pcb)[reg2pcb[i+off]]); | |
356 | /* | |
357 | * If the RPB is valid for this thread/proc use the register values | |
358 | * contained there. | |
359 | */ | |
360 | if (addr == rpbpcbaddr) { | |
361 | off = 0; | |
362 | for (i = 0; i < NUM_REGS; ++i) | |
363 | if (reg2pcb[i+off] != -1) | |
364 | supply_register(i, &((int *)rpbaddr)[reg2pcb[i+off]]); | |
365 | } | |
366 | } | |
367 | ||
368 | void | |
369 | setup_kernel_debugging() | |
370 | { | |
371 | struct stat stb; | |
372 | CORE_ADDR addr; | |
373 | ||
374 | fstat(corechan, &stb); | |
375 | devmem = 0; | |
376 | if ((stb.st_mode & S_IFMT) == S_IFCHR && stb.st_rdev == makedev(2, 0)) | |
377 | devmem = 1; | |
378 | ||
379 | /* XXX */ | |
380 | if (lookup_misc_func("Sysmap") < 0) | |
381 | kerneltype = OS_MACH; | |
382 | else | |
383 | kerneltype = OS_BSD; | |
384 | ||
385 | if (kerneltype == OS_BSD) { | |
386 | int len, err = 0; | |
387 | ||
388 | /* | |
389 | * Hash table and PDIR are equivalently mapped | |
390 | */ | |
391 | nhtbl = kvread(ksym_lookup("nhtbl")); | |
392 | if (nhtbl != ~0) { | |
393 | len = nhtbl * sizeof(*htbl); | |
394 | htbl = (struct hte *) malloc(len); | |
395 | if (htbl) { | |
396 | addr = kvread(ksym_lookup("htbl")); | |
397 | if (physrd(addr, (char *)htbl, len)) | |
398 | err++; | |
399 | } else | |
400 | err++; | |
401 | } else | |
402 | err++; | |
403 | npdir = kvread(ksym_lookup("npdir")); | |
404 | if (npdir != ~0) { | |
405 | len = npdir * sizeof(*pdir); | |
406 | pdir = (struct pde *) malloc(len); | |
407 | if (pdir) { | |
408 | addr = kvread(ksym_lookup("pdir")); | |
409 | if (physrd(addr, (char *)pdir, len)) | |
410 | err++; | |
411 | } else | |
412 | err++; | |
413 | } else | |
414 | err++; | |
415 | if (err) { | |
416 | error("cannot read PDIR/HTBL"); | |
417 | return; | |
418 | } | |
419 | vtophys_ready = 1; | |
420 | ||
421 | /* | |
422 | * pcb where "panic" saved registers in first thing in | |
423 | * current u-area. The current u-area is pointed to by | |
424 | * "uptr". | |
425 | */ | |
426 | addr = kvread(ksym_lookup("uptr")); | |
427 | if (addr == ~0) { | |
428 | error("cannot read current u-area address"); | |
429 | return; | |
430 | } | |
431 | read_pcb(vtophys(0, addr)); /* XXX space */ | |
432 | if (!devmem) { | |
433 | /* find stack frame */ | |
434 | CORE_ADDR panicstr; | |
435 | char buf[256]; | |
436 | register char *cp; | |
437 | ||
438 | panicstr = kvread(ksym_lookup("panicstr")); | |
439 | if (panicstr == ~0) | |
440 | return; | |
441 | kernel_core_file_hook(panicstr, buf, sizeof(buf)); | |
442 | for (cp = buf; cp < &buf[sizeof(buf)] && *cp; cp++) | |
443 | if (!isascii(*cp) || (!isprint(*cp) && !isspace(*cp))) | |
444 | *cp = '?'; | |
445 | if (*cp) | |
446 | *cp = '\0'; | |
447 | printf("panic: %s\n", buf); | |
448 | } | |
449 | } | |
450 | #ifdef MACHKERNELDEBUG | |
451 | else { | |
452 | int *thread; | |
453 | ||
454 | /* | |
455 | * Set up address translation | |
456 | */ | |
457 | if (mach_vtophys_init() == 0) { | |
458 | error("cannot initialize vtophys for Mach"); | |
459 | return; | |
460 | } | |
461 | vtophys_ready = 1; | |
462 | ||
463 | /* | |
464 | * Locate active thread and read PCB | |
465 | * XXX MAJOR HACK | |
466 | * - assumes uni-processor | |
467 | * - assumes position of pcb to avoid mach includes | |
468 | */ | |
469 | thread = (int *)kvread(ksym_lookup("active_threads")); | |
470 | addr = kvread(&thread[9]); /* XXX: pcb addr */ | |
471 | read_pcb(vtophys(0, addr)); | |
472 | } | |
473 | #endif | |
474 | } | |
475 | ||
476 | vtop_command(arg) | |
477 | char *arg; | |
478 | { | |
479 | u_int sp, off, pa; | |
480 | ||
481 | if (!arg) | |
482 | error_no_arg("kernel virtual address"); | |
483 | if (!kernel_debugging) | |
484 | error("not debugging kernel"); | |
485 | ||
486 | sp = 0; /* XXX */ | |
487 | off = (u_int) parse_and_eval_address(arg); | |
488 | pa = vtophys(sp, off); | |
489 | printf("%lx.%lx -> ", sp, off); | |
490 | if (pa == ~0) | |
491 | printf("<invalid>\n"); | |
492 | else | |
493 | printf("%lx\n", pa); | |
494 | } | |
495 | ||
496 | set_paddr_command(arg) | |
497 | char *arg; | |
498 | { | |
499 | u_int addr; | |
500 | ||
501 | if (!arg) { | |
502 | if (kerneltype == OS_BSD) | |
503 | error_no_arg("ps-style address for new process"); | |
504 | else | |
505 | error_no_arg("thread structure virtual address"); | |
506 | } | |
507 | if (!kernel_debugging) | |
508 | error("not debugging kernel"); | |
509 | ||
510 | addr = (u_int) parse_and_eval_address(arg); | |
511 | if (kerneltype == OS_BSD) | |
512 | addr = ctob(addr); | |
513 | else { | |
514 | addr = kvread(&(((int *)addr)[9])); /* XXX: pcb addr */ | |
515 | addr = vtophys(0, addr); /* XXX space */ | |
516 | } | |
517 | read_pcb(addr); | |
518 | ||
519 | flush_cached_frames(); | |
520 | set_current_frame(create_new_frame(read_register(FP_REGNUM), read_pc())); | |
521 | select_frame(get_current_frame(), 0); | |
522 | } | |
523 | ||
524 | /* | |
525 | * read len bytes from kernel virtual address 'addr' into local | |
526 | * buffer 'buf'. Return 0 if read ok, 1 otherwise. On read | |
527 | * errors, portion of buffer not read is zeroed. | |
528 | */ | |
529 | kernel_core_file_hook(addr, buf, len) | |
530 | CORE_ADDR addr; | |
531 | char *buf; | |
532 | int len; | |
533 | { | |
534 | int i; | |
535 | CORE_ADDR paddr; | |
536 | ||
537 | while (len > 0) { | |
538 | paddr = vtophys(0, addr); /* XXX space */ | |
539 | if (paddr == ~0) { | |
540 | bzero(buf, len); | |
541 | return (1); | |
542 | } | |
543 | /* we can't read across a page boundary */ | |
544 | i = min(len, NBPG - (addr & PGOFSET)); | |
545 | if (physrd(paddr, buf, i)) { | |
546 | bzero(buf, len); | |
547 | return (1); | |
548 | } | |
549 | buf += i; | |
550 | addr += i; | |
551 | len -= i; | |
552 | } | |
553 | return (0); | |
554 | } | |
555 | #endif | |
556 | ||
557 | ||
558 | \f | |
559 | ||
560 | ||
561 | /* Routines to extract various sized constants out of hppa | |
562 | instructions. */ | |
563 | ||
564 | /* This assumes that no garbage lies outside of the lower bits of | |
565 | value. */ | |
566 | ||
567 | int | |
568 | sign_extend (val, bits) | |
569 | unsigned val, bits; | |
570 | { | |
571 | return (int)(val >> bits - 1 ? (-1 << bits) | val : val); | |
572 | } | |
573 | ||
574 | /* For many immediate values the sign bit is the low bit! */ | |
575 | ||
576 | int | |
577 | low_sign_extend (val, bits) | |
578 | unsigned val, bits; | |
579 | { | |
580 | return (int)((val & 0x1 ? (-1 << (bits - 1)) : 0) | val >> 1); | |
581 | } | |
582 | /* extract the immediate field from a ld{bhw}s instruction */ | |
583 | ||
584 | ||
585 | ||
586 | unsigned | |
587 | get_field (val, from, to) | |
588 | unsigned val, from, to; | |
589 | { | |
590 | val = val >> 31 - to; | |
591 | return val & ((1 << 32 - from) - 1); | |
592 | } | |
593 | ||
594 | unsigned | |
595 | set_field (val, from, to, new_val) | |
596 | unsigned *val, from, to; | |
597 | { | |
598 | unsigned mask = ~((1 << (to - from + 1)) << (31 - from)); | |
599 | return *val = *val & mask | (new_val << (31 - from)); | |
600 | } | |
601 | ||
602 | /* extract a 3-bit space register number from a be, ble, mtsp or mfsp */ | |
603 | ||
604 | extract_3 (word) | |
605 | unsigned word; | |
606 | { | |
607 | return GET_FIELD (word, 18, 18) << 2 | GET_FIELD (word, 16, 17); | |
608 | } | |
609 | ||
610 | extract_5_load (word) | |
611 | unsigned word; | |
612 | { | |
613 | return low_sign_extend (word >> 16 & MASK_5, 5); | |
614 | } | |
615 | ||
616 | /* extract the immediate field from a st{bhw}s instruction */ | |
617 | ||
618 | int | |
619 | extract_5_store (word) | |
620 | unsigned word; | |
621 | { | |
622 | return low_sign_extend (word & MASK_5, 5); | |
623 | } | |
624 | ||
625 | /* extract an 11 bit immediate field */ | |
626 | ||
627 | int | |
628 | extract_11 (word) | |
629 | unsigned word; | |
630 | { | |
631 | return low_sign_extend (word & MASK_11, 11); | |
632 | } | |
633 | ||
634 | /* extract a 14 bit immediate field */ | |
635 | ||
636 | int | |
637 | extract_14 (word) | |
638 | unsigned word; | |
639 | { | |
640 | return low_sign_extend (word & MASK_14, 14); | |
641 | } | |
642 | ||
643 | /* deposit a 14 bit constant in a word */ | |
644 | ||
645 | unsigned | |
646 | deposit_14 (opnd, word) | |
647 | int opnd; | |
648 | unsigned word; | |
649 | { | |
650 | unsigned sign = (opnd < 0 ? 1 : 0); | |
651 | ||
652 | return word | ((unsigned)opnd << 1 & MASK_14) | sign; | |
653 | } | |
654 | ||
655 | /* extract a 21 bit constant */ | |
656 | ||
657 | int | |
658 | extract_21 (word) | |
659 | unsigned word; | |
660 | { | |
661 | int val; | |
662 | ||
663 | word &= MASK_21; | |
664 | word <<= 11; | |
665 | val = GET_FIELD (word, 20, 20); | |
666 | val <<= 11; | |
667 | val |= GET_FIELD (word, 9, 19); | |
668 | val <<= 2; | |
669 | val |= GET_FIELD (word, 5, 6); | |
670 | val <<= 5; | |
671 | val |= GET_FIELD (word, 0, 4); | |
672 | val <<= 2; | |
673 | val |= GET_FIELD (word, 7, 8); | |
674 | return sign_extend (val, 21) << 11; | |
675 | } | |
676 | ||
677 | /* deposit a 21 bit constant in a word. Although 21 bit constants are | |
678 | usually the top 21 bits of a 32 bit constant, we assume that only | |
679 | the low 21 bits of opnd are relevant */ | |
680 | ||
681 | unsigned | |
682 | deposit_21 (opnd, word) | |
683 | unsigned opnd, word; | |
684 | { | |
685 | unsigned val = 0; | |
686 | ||
687 | val |= GET_FIELD (opnd, 11 + 14, 11 + 18); | |
688 | val <<= 2; | |
689 | val |= GET_FIELD (opnd, 11 + 12, 11 + 13); | |
690 | val <<= 2; | |
691 | val |= GET_FIELD (opnd, 11 + 19, 11 + 20); | |
692 | val <<= 11; | |
693 | val |= GET_FIELD (opnd, 11 + 1, 11 + 11); | |
694 | val <<= 1; | |
695 | val |= GET_FIELD (opnd, 11 + 0, 11 + 0); | |
696 | return word | val; | |
697 | } | |
698 | ||
699 | /* extract a 12 bit constant from branch instructions */ | |
700 | ||
701 | int | |
702 | extract_12 (word) | |
703 | unsigned word; | |
704 | { | |
705 | return sign_extend (GET_FIELD (word, 19, 28) | | |
706 | GET_FIELD (word, 29, 29) << 10 | | |
707 | (word & 0x1) << 11, 12) << 2; | |
708 | } | |
709 | ||
710 | /* extract a 17 bit constant from branch instructions, returning the | |
711 | 19 bit signed value. */ | |
712 | ||
713 | int | |
714 | extract_17 (word) | |
715 | unsigned word; | |
716 | { | |
717 | return sign_extend (GET_FIELD (word, 19, 28) | | |
718 | GET_FIELD (word, 29, 29) << 10 | | |
719 | GET_FIELD (word, 11, 15) << 11 | | |
720 | (word & 0x1) << 16, 17) << 2; | |
721 | } | |
722 | ||
723 | ||
724 | CORE_ADDR | |
725 | frame_saved_pc (frame) | |
726 | FRAME frame; | |
727 | { | |
728 | if (get_current_frame () == frame) | |
729 | { | |
730 | struct frame_saved_regs saved_regs; | |
731 | ||
732 | get_frame_saved_regs (frame, &saved_regs); | |
733 | if (saved_regs.regs[RP_REGNUM]) | |
734 | return read_memory_integer (saved_regs.regs[RP_REGNUM], 4); | |
735 | else | |
736 | return read_register (RP_REGNUM); | |
737 | } | |
738 | return read_memory_integer (frame->frame - 20, 4) & ~0x3; | |
739 | } | |
740 | ||
741 | /* To see if a frame chain is valid, see if the caller looks like it | |
742 | was compiled with gcc. */ | |
743 | ||
744 | int frame_chain_valid (chain, thisframe) | |
745 | FRAME_ADDR chain; | |
746 | FRAME thisframe; | |
747 | { | |
748 | if (chain && (chain > 0x60000000 | |
749 | /* || remote_debugging -this is no longer used */ | |
750 | #ifdef KERNELDEBUG | |
751 | || kernel_debugging | |
752 | #endif | |
753 | )) | |
754 | { | |
755 | CORE_ADDR pc = get_pc_function_start (FRAME_SAVED_PC (thisframe)); | |
756 | ||
757 | if (!inside_entry_file (pc)) | |
758 | return 0; | |
759 | /* look for stw rp, -20(0,sp); copy 4,1; copy sp, 4 */ | |
760 | if (read_memory_integer (pc, 4) == 0x6BC23FD9) | |
761 | pc = pc + 4; | |
762 | ||
763 | if (read_memory_integer (pc, 4) == 0x8040241 && | |
764 | read_memory_integer (pc + 4, 4) == 0x81E0244) | |
765 | return 1; | |
766 | else | |
767 | return 0; | |
768 | } | |
769 | else | |
770 | return 0; | |
771 | } | |
772 | ||
773 | /* Some helper functions. gcc_p returns 1 if the function beginning at | |
774 | pc appears to have been compiled with gcc. hpux_cc_p returns 1 if | |
775 | fn was compiled with hpux cc. gcc functions look like : | |
776 | ||
777 | stw rp,-0x14(sp) ; optional | |
778 | or r4,r0,r1 | |
779 | or sp,r0,r4 | |
780 | stwm r1,framesize(sp) | |
781 | ||
782 | hpux cc functions look like: | |
783 | ||
784 | stw rp,-0x14(sp) ; optional. | |
785 | stwm r3,framesiz(sp) | |
786 | */ | |
787 | ||
788 | gcc_p (pc) | |
789 | CORE_ADDR pc; | |
790 | { | |
791 | if (read_memory_integer (pc, 4) == 0x6BC23FD9) | |
792 | pc = pc + 4; | |
793 | ||
794 | if (read_memory_integer (pc, 4) == 0x8040241 && | |
795 | read_memory_integer (pc + 4, 4) == 0x81E0244) | |
796 | return 1; | |
797 | return 0; | |
798 | } | |
799 | ||
800 | ||
801 | find_dummy_frame_regs (frame, frame_saved_regs) | |
802 | struct frame_info *frame; | |
803 | struct frame_saved_regs *frame_saved_regs; | |
804 | { | |
805 | CORE_ADDR fp = frame->frame; | |
806 | int i; | |
807 | ||
808 | frame_saved_regs->regs[RP_REGNUM] = fp - 20 & ~0x3; | |
809 | frame_saved_regs->regs[FP_REGNUM] = fp; | |
810 | frame_saved_regs->regs[1] = fp + 8; | |
811 | frame_saved_regs->regs[3] = fp + 12; | |
812 | for (fp += 16, i = 3; i < 30; fp += 4, i++) | |
813 | frame_saved_regs->regs[i] = fp; | |
814 | frame_saved_regs->regs[31] = fp; | |
815 | fp += 4; | |
816 | for (i = FP0_REGNUM; i < NUM_REGS; i++, fp += 8) | |
817 | frame_saved_regs->regs[i] = fp; | |
818 | /* depend on last increment of fp */ | |
819 | frame_saved_regs->regs[IPSW_REGNUM] = fp - 4; | |
820 | frame_saved_regs->regs[SAR_REGNUM] = fp; | |
821 | fp += 4; | |
822 | frame_saved_regs->regs[PCOQ_TAIL_REGNUM] = fp; | |
823 | frame_saved_regs->regs[PCSQ_TAIL_REGNUM] = fp; | |
824 | } | |
825 | ||
826 | CORE_ADDR | |
827 | hp_push_arguments (nargs, args, sp, struct_return, struct_addr) | |
828 | int nargs; | |
829 | value *args; | |
830 | CORE_ADDR sp; | |
831 | int struct_return; | |
832 | CORE_ADDR struct_addr; | |
833 | { | |
834 | /* array of arguments' offsets */ | |
835 | int *offset = (int *)alloca(nargs); | |
836 | int cum = 0; | |
837 | int i, alignment; | |
838 | ||
839 | for (i = 0; i < nargs; i++) | |
840 | { | |
841 | cum += TYPE_LENGTH (VALUE_TYPE (args[i])); | |
842 | /* value must go at proper alignment. Assume alignment is a | |
843 | power of two.*/ | |
844 | alignment = hp_alignof (VALUE_TYPE (args[i])); | |
845 | if (cum % alignment) | |
846 | cum = (cum + alignment) & -alignment; | |
847 | offset[i] = -cum; | |
848 | } | |
849 | for (i == 0; i < nargs; i++) | |
850 | { | |
851 | write_memory (sp + offset[i], VALUE_CONTENTS (args[i]), sizeof(int)); | |
852 | } | |
853 | sp += min ((cum + 7) & -8, 48); | |
854 | if (struct_return) | |
855 | write_register (28, struct_addr); | |
856 | return sp + 48; | |
857 | } | |
858 | ||
859 | /* return the alignment of a type in bytes. Structures have the maximum | |
860 | alignment required by their fields. */ | |
861 | ||
862 | int | |
863 | hp_alignof (arg) | |
864 | struct type *arg; | |
865 | { | |
866 | int max_align, align, i; | |
867 | switch (TYPE_CODE (arg)) | |
868 | { | |
869 | case TYPE_CODE_PTR: | |
870 | case TYPE_CODE_INT: | |
871 | case TYPE_CODE_FLT: | |
872 | return TYPE_LENGTH (arg); | |
873 | case TYPE_CODE_ARRAY: | |
874 | return hp_alignof (TYPE_FIELD_TYPE (arg, 0)); | |
875 | case TYPE_CODE_STRUCT: | |
876 | case TYPE_CODE_UNION: | |
877 | max_align = 2; | |
878 | for (i = 0; i < TYPE_NFIELDS (arg); i++) | |
879 | { | |
880 | /* Bit fields have no real alignment. */ | |
881 | if (!TYPE_FIELD_BITPOS (arg, i)) | |
882 | { | |
883 | align = hp_alignof (TYPE_FIELD_TYPE (arg, i)); | |
884 | max_align = max (max_align, align); | |
885 | } | |
886 | } | |
887 | return max_align; | |
888 | default: | |
889 | return 4; | |
890 | } | |
891 | } | |
892 | ||
893 | /* Print the register regnum, or all registers if regnum is -1 */ | |
894 | ||
895 | pa_do_registers_info (regnum, fpregs) | |
896 | int regnum; | |
897 | int fpregs; | |
898 | { | |
899 | char raw_regs [REGISTER_BYTES]; | |
900 | int i; | |
901 | ||
902 | for (i = 0; i < NUM_REGS; i++) | |
903 | read_relative_register_raw_bytes (i, raw_regs + REGISTER_BYTE (i)); | |
904 | if (regnum = -1) | |
905 | pa_print_registers (raw_regs, regnum); | |
906 | else if (regnum < FP0_REGNUM) | |
907 | { | |
908 | printf ("%s %x\n", reg_names[regnum], *(long *)(raw_regs + | |
909 | REGISTER_BYTE (regnum))); | |
910 | } | |
911 | else | |
912 | pa_print_fp_reg (regnum); | |
913 | } | |
914 | ||
915 | pa_print_registers (raw_regs, regnum) | |
916 | char *raw_regs; | |
917 | int regnum; | |
918 | { | |
919 | int i; | |
920 | ||
921 | for (i = 0; i < 18; i++) | |
922 | printf ("%8.8s: %8x %8.8s: %8x %8.8s: %8x %8.8s: %8x\n", | |
923 | reg_names[i], | |
924 | *(int *)(raw_regs + REGISTER_BYTE (i)), | |
925 | reg_names[i + 18], | |
926 | *(int *)(raw_regs + REGISTER_BYTE (i + 18)), | |
927 | reg_names[i + 36], | |
928 | *(int *)(raw_regs + REGISTER_BYTE (i + 36)), | |
929 | reg_names[i + 54], | |
930 | *(int *)(raw_regs + REGISTER_BYTE (i + 54))); | |
931 | for (i = 72; i < NUM_REGS; i++) | |
932 | pa_print_fp_reg (i); | |
933 | } | |
934 | ||
935 | pa_print_fp_reg (i) | |
936 | int i; | |
937 | { | |
938 | unsigned char raw_buffer[MAX_REGISTER_RAW_SIZE]; | |
939 | unsigned char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE]; | |
940 | REGISTER_TYPE val; | |
941 | ||
942 | /* Get the data in raw format, then convert also to virtual format. */ | |
943 | read_relative_register_raw_bytes (i, raw_buffer); | |
944 | REGISTER_CONVERT_TO_VIRTUAL (i, raw_buffer, virtual_buffer); | |
945 | ||
946 | fputs_filtered (reg_names[i], stdout); | |
947 | print_spaces_filtered (15 - strlen (reg_names[i]), stdout); | |
948 | ||
949 | val_print (REGISTER_VIRTUAL_TYPE (i), virtual_buffer, 0, stdout, 0, | |
950 | 1, 0, Val_pretty_default); | |
951 | printf_filtered ("\n"); | |
952 | ||
953 | } | |
954 | ||
955 | /* | |
956 | * Virtual to physical translation routines for Utah's Mach 3.0 | |
957 | */ | |
958 | #ifdef MACHKERNELDEBUG | |
959 | ||
960 | #define STATIC | |
961 | ||
962 | #if 0 /* too many includes to resolve, too much crap */ | |
963 | #include <kern/queue.h> | |
964 | #include <vm/pmap.h> | |
965 | #include <mach/vm_prot.h> | |
966 | #else | |
967 | /* queue.h */ | |
968 | struct queue_entry { | |
969 | struct queue_entry *next; /* next element */ | |
970 | struct queue_entry *prev; /* previous element */ | |
971 | }; | |
972 | ||
973 | typedef struct queue_entry *queue_t; | |
974 | typedef struct queue_entry queue_head_t; | |
975 | typedef struct queue_entry queue_chain_t; | |
976 | typedef struct queue_entry *queue_entry_t; | |
977 | ||
978 | /* pmap.h */ | |
979 | #define HP800_HASHSIZE 1024 | |
980 | #define HP800_HASHSIZE_LOG2 10 | |
981 | ||
982 | #define pmap_hash(space, offset) \ | |
983 | (((unsigned) (space) << 5 ^ \ | |
984 | ((unsigned) (offset) >> 19 | (unsigned) (space) << 13) ^ \ | |
985 | (unsigned) (offset) >> 11) & (HP800_HASHSIZE-1)) | |
986 | ||
987 | struct mapping { | |
988 | queue_head_t hash_link; /* hash table links */ | |
989 | queue_head_t phys_link; /* for mappings of a given PA */ | |
990 | space_t space; /* virtual space */ | |
991 | unsigned offset; /* virtual page number */ | |
992 | unsigned tlbpage; /* physical page (for TLB load) */ | |
993 | unsigned tlbprot; /* prot/access rights (for TLB load) */ | |
994 | struct pmap *pmap; /* pmap mapping belongs to */ | |
995 | }; | |
996 | ||
997 | struct phys_entry { | |
998 | queue_head_t phys_link; /* head of mappings of a given PA */ | |
999 | struct mapping *writer; /* mapping with R/W access */ | |
1000 | unsigned tlbprot; /* TLB format protection */ | |
1001 | }; | |
1002 | ||
1003 | #endif | |
1004 | ||
1005 | #define atop(a) ((unsigned)(a) >> 11) | |
1006 | #define ptoa(p) ((unsigned)(p) << 11) | |
1007 | #define trunc_page(a) ((unsigned)(a) & ~2047) | |
1008 | ||
1009 | STATIC long equiv_end; | |
1010 | STATIC queue_head_t *Ovtop_table, *vtop_table, *Ofree_mapping, free_mapping; | |
1011 | STATIC struct phys_entry *Ophys_table, *phys_table; | |
1012 | STATIC long vm_last_phys, vm_first_phys; | |
1013 | STATIC struct mapping *firstmap, *lastmap, *Omap_table, *map_table; | |
1014 | STATIC unsigned Omlow, Omhigh, Omhead, Ovlow, Ovhigh, Oplow, Ophigh; | |
1015 | STATIC unsigned mlow, mhigh, mhead, vlow, vhigh, plow, phigh; | |
1016 | STATIC int vtopsize, physsize, mapsize; | |
1017 | STATIC int kmemfd; | |
1018 | ||
1019 | #define IS_OVTOPPTR(p) ((unsigned)(p) >= Ovlow && (unsigned)(p) < Ovhigh) | |
1020 | #define IS_OMAPPTR(p) ((unsigned)(p) >= Omlow && (unsigned)(p) < Omhigh) | |
1021 | #define IS_OPHYSPTR(p) ((unsigned)(p) >= Oplow && (unsigned)(p) < Ophigh) | |
1022 | #define IS_VTOPPTR(p) ((unsigned)(p) >= vlow && (unsigned)(p) < vhigh) | |
1023 | #define IS_MAPPTR(p) ((unsigned)(p) >= mlow && (unsigned)(p) < mhigh) | |
1024 | #define IS_PHYSPTR(p) ((unsigned)(p) >= plow && (unsigned)(p) < phigh) | |
1025 | ||
1026 | struct mapstate { | |
1027 | char unused; | |
1028 | char flags; | |
1029 | short hashix; | |
1030 | short physix; | |
1031 | } *mapstate; | |
1032 | ||
1033 | /* flags */ | |
1034 | #define M_ISFREE 1 | |
1035 | #define M_ISHASH 2 | |
1036 | #define M_ISPHYS 4 | |
1037 | ||
1038 | mach_vtophys_init() | |
1039 | { | |
1040 | int errors = 0; | |
1041 | ||
1042 | if (!readdata()) | |
1043 | errors++; | |
1044 | if (!verifydata()) | |
1045 | errors++; | |
1046 | if (!errors) | |
1047 | return(1); | |
1048 | fflush(stdout); | |
1049 | fprintf(stderr, | |
1050 | "translate: may not be able to translate all addresses\n"); | |
1051 | return(0); | |
1052 | } | |
1053 | ||
1054 | mach_vtophys(space, off, pa) | |
1055 | unsigned space, off, *pa; | |
1056 | { | |
1057 | register int i; | |
1058 | register queue_t qp; | |
1059 | register struct mapping *mp; | |
1060 | int poff; | |
1061 | ||
1062 | /* | |
1063 | * Kernel IO or equivilently mapped, one to one. | |
1064 | */ | |
1065 | if (space == 0 && (long)off < equiv_end) { | |
1066 | *pa = off; | |
1067 | return(1); | |
1068 | } | |
1069 | /* | |
1070 | * Else look it up in specified space | |
1071 | */ | |
1072 | poff = off - trunc_page(off); | |
1073 | off = trunc_page(off); | |
1074 | qp = &vtop_table[pmap_hash(space, off)]; | |
1075 | for (mp = (struct mapping *)qp->next; | |
1076 | qp != (queue_entry_t)mp; | |
1077 | mp = (struct mapping *)mp->hash_link.next) { | |
1078 | if (mp->space == space && mp->offset == off) { | |
1079 | *pa = (mp->tlbpage << 7) | poff; | |
1080 | return(1); | |
1081 | } | |
1082 | } | |
1083 | return(0); | |
1084 | } | |
1085 | ||
1086 | STATIC | |
1087 | readdata() | |
1088 | { | |
1089 | char *tmp, *mach_malloc(); | |
1090 | long size; | |
1091 | ||
1092 | /* easy scalars */ | |
1093 | mach_read("equiv_end", ~0, (char *)&equiv_end, sizeof equiv_end); | |
1094 | mach_read("vm_first_phys", ~0, | |
1095 | (char *)&vm_first_phys, sizeof vm_first_phys); | |
1096 | mach_read("vm_last_phys", ~0, | |
1097 | (char *)&vm_last_phys, sizeof vm_last_phys); | |
1098 | mach_read("firstmap", ~0, (char *)&firstmap, sizeof firstmap); | |
1099 | mach_read("lastmap", ~0, (char *)&lastmap, sizeof lastmap); | |
1100 | ||
1101 | /* virtual to physical hash table */ | |
1102 | vtopsize = HP800_HASHSIZE; | |
1103 | size = vtopsize * sizeof(queue_head_t); | |
1104 | tmp = mach_malloc("vtop table", size); | |
1105 | mach_read("vtop_table", ~0, (char *)&Ovtop_table, sizeof Ovtop_table); | |
1106 | mach_read("vtop table", (CORE_ADDR)Ovtop_table, tmp, size); | |
1107 | vtop_table = (queue_head_t *) tmp; | |
1108 | ||
1109 | /* inverted page table */ | |
1110 | physsize = atop(vm_last_phys - vm_first_phys); | |
1111 | size = physsize * sizeof(struct phys_entry); | |
1112 | tmp = mach_malloc("phys table", size); | |
1113 | mach_read("phys_table", ~0, (char *)&Ophys_table, sizeof Ophys_table); | |
1114 | mach_read("phys table", (CORE_ADDR)Ophys_table, tmp, size); | |
1115 | phys_table = (struct phys_entry *) tmp; | |
1116 | ||
1117 | /* mapping structures */ | |
1118 | Ofree_mapping = (queue_head_t *) ksym_lookup("free_mapping"); | |
1119 | mach_read("free mapping", (CORE_ADDR)Ofree_mapping, | |
1120 | (char *) &free_mapping, sizeof free_mapping); | |
1121 | Omap_table = firstmap; | |
1122 | mapsize = lastmap - firstmap; | |
1123 | size = mapsize * sizeof(struct mapping); | |
1124 | tmp = mach_malloc("mapping table", size); | |
1125 | mach_read("mapping table", (CORE_ADDR)Omap_table, tmp, size); | |
1126 | map_table = (struct mapping *) tmp; | |
1127 | ||
1128 | /* set limits */ | |
1129 | Ovlow = (unsigned) Ovtop_table; | |
1130 | Ovhigh = (unsigned) &Ovtop_table[vtopsize]; | |
1131 | Oplow = (unsigned) Ophys_table; | |
1132 | Ophigh = (unsigned) &Ophys_table[physsize]; | |
1133 | Omhead = (unsigned) Ofree_mapping; | |
1134 | Omlow = (unsigned) firstmap; | |
1135 | Omhigh = (unsigned) lastmap; | |
1136 | mlow = (unsigned) map_table; | |
1137 | mhigh = (unsigned) &map_table[mapsize]; | |
1138 | mhead = (unsigned) &free_mapping; | |
1139 | vlow = (unsigned) vtop_table; | |
1140 | vhigh = (unsigned) &vtop_table[vtopsize]; | |
1141 | plow = (unsigned) phys_table; | |
1142 | phigh = (unsigned) &phys_table[physsize]; | |
1143 | ||
1144 | #if 0 | |
1145 | fprintf(stderr, "Ovtop [%#x-%#x) Ophys [%#x-%#x) Omap %#x [%#x-%#x)\n", | |
1146 | Ovlow, Ovhigh, Oplow, Ophigh, Omhead, Omlow, Omhigh); | |
1147 | fprintf(stderr, "vtop [%#x-%#x) phys [%#x-%#x) map %#x [%#x-%#x)\n", | |
1148 | vlow, vhigh, plow, phigh, mhead, mlow, mhigh); | |
1149 | #endif | |
1150 | return(adjustdata()); | |
1151 | } | |
1152 | ||
1153 | STATIC unsigned | |
1154 | ptrcvt(ptr) | |
1155 | unsigned ptr; | |
1156 | { | |
1157 | unsigned ret; | |
1158 | char *str; | |
1159 | ||
1160 | if (ptr == 0) { | |
1161 | ret = ptr; | |
1162 | str = "null"; | |
1163 | } else if (IS_OVTOPPTR(ptr)) { | |
1164 | ret = vlow + (ptr - Ovlow); | |
1165 | str = "vtop"; | |
1166 | } else if (IS_OPHYSPTR(ptr)) { | |
1167 | ret = plow + (ptr - Oplow); | |
1168 | str = "phys"; | |
1169 | } else if (IS_OMAPPTR(ptr)) { | |
1170 | ret = mlow + (ptr - Omlow); | |
1171 | str = "map"; | |
1172 | } else if (ptr == Omhead) { | |
1173 | ret = mhead; | |
1174 | str = "maphead"; | |
1175 | } else { | |
1176 | error("bogus pointer %#x", ptr); | |
1177 | str = "wild"; | |
1178 | ret = ptr; | |
1179 | } | |
1180 | #if 0 | |
1181 | fprintf(stderr, "%x (%s) -> %x\n", ptr, str, ret); | |
1182 | #endif | |
1183 | return(ret); | |
1184 | } | |
1185 | ||
1186 | STATIC int | |
1187 | adjustdata() | |
1188 | { | |
1189 | register int i, lim; | |
1190 | queue_head_t *nq; | |
1191 | struct phys_entry *np; | |
1192 | struct mapping *nm; | |
1193 | ||
1194 | /* hash table */ | |
1195 | lim = vtopsize; | |
1196 | for (nq = vtop_table; nq < &vtop_table[lim]; nq++) { | |
1197 | nq->next = (queue_entry_t) ptrcvt((unsigned)nq->next); | |
1198 | nq->prev = (queue_entry_t) ptrcvt((unsigned)nq->prev); | |
1199 | } | |
1200 | ||
1201 | /* IPT */ | |
1202 | lim = physsize; | |
1203 | for (np = phys_table; np < &phys_table[lim]; np++) { | |
1204 | np->phys_link.next = (queue_entry_t) | |
1205 | ptrcvt((unsigned)np->phys_link.next); | |
1206 | np->phys_link.prev = (queue_entry_t) | |
1207 | ptrcvt((unsigned)np->phys_link.prev); | |
1208 | np->writer = (struct mapping *) ptrcvt((unsigned)np->writer); | |
1209 | } | |
1210 | ||
1211 | /* mapping table */ | |
1212 | free_mapping.next = (queue_entry_t)ptrcvt((unsigned)free_mapping.next); | |
1213 | free_mapping.prev = (queue_entry_t)ptrcvt((unsigned)free_mapping.prev); | |
1214 | lim = mapsize; | |
1215 | for (nm = map_table; nm < &map_table[lim]; nm++) { | |
1216 | nm->hash_link.next = (queue_entry_t) | |
1217 | ptrcvt((unsigned)nm->hash_link.next); | |
1218 | nm->hash_link.prev = (queue_entry_t) | |
1219 | ptrcvt((unsigned)nm->hash_link.prev); | |
1220 | nm->phys_link.next = (queue_entry_t) | |
1221 | ptrcvt((unsigned)nm->phys_link.next); | |
1222 | nm->phys_link.prev = (queue_entry_t) | |
1223 | ptrcvt((unsigned)nm->phys_link.prev); | |
1224 | } | |
1225 | return(1); | |
1226 | } | |
1227 | ||
1228 | /* | |
1229 | * Consistency checks, make sure: | |
1230 | * | |
1231 | * 1. all mappings are accounted for | |
1232 | * 2. no cycles | |
1233 | * 3. no wild pointers | |
1234 | * 4. consisent TLB state | |
1235 | */ | |
1236 | STATIC int | |
1237 | verifydata() | |
1238 | { | |
1239 | register struct mapstate *ms; | |
1240 | register int i; | |
1241 | int errors = 0; | |
1242 | ||
1243 | mapstate = (struct mapstate *) | |
1244 | mach_malloc("map state", mapsize * sizeof(struct mapstate)); | |
1245 | for (ms = mapstate; ms < &mapstate[mapsize]; ms++) { | |
1246 | ms->flags = 0; | |
1247 | ms->hashix = ms->physix = -2; | |
1248 | } | |
1249 | ||
1250 | /* | |
1251 | * Check the free list | |
1252 | */ | |
1253 | checkhashchain(&free_mapping, M_ISFREE, -1); | |
1254 | /* | |
1255 | * Check every hash chain | |
1256 | */ | |
1257 | for (i = 0; i < vtopsize; i++) | |
1258 | checkhashchain(&vtop_table[i], M_ISHASH, i); | |
1259 | /* | |
1260 | * Check every phys chain | |
1261 | */ | |
1262 | for (i = 0; i < physsize; i++) | |
1263 | checkphyschain(&phys_table[i].phys_link, M_ISPHYS, i); | |
1264 | /* | |
1265 | * Cycle through mapstate looking for anomolies | |
1266 | */ | |
1267 | ms = mapstate; | |
1268 | for (i = 0; i < mapsize; i++) { | |
1269 | switch (ms->flags) { | |
1270 | case M_ISFREE: | |
1271 | case M_ISHASH|M_ISPHYS: | |
1272 | break; | |
1273 | case 0: | |
1274 | merror(ms, "not found"); | |
1275 | errors++; | |
1276 | break; | |
1277 | case M_ISHASH: | |
1278 | merror(ms, "in vtop but not phys"); | |
1279 | errors++; | |
1280 | break; | |
1281 | case M_ISPHYS: | |
1282 | merror(ms, "in phys but not vtop"); | |
1283 | errors++; | |
1284 | break; | |
1285 | default: | |
1286 | merror(ms, "totally bogus"); | |
1287 | errors++; | |
1288 | break; | |
1289 | } | |
1290 | ms++; | |
1291 | } | |
1292 | return(errors ? 0 : 1); | |
1293 | } | |
1294 | ||
1295 | STATIC void | |
1296 | checkhashchain(qhp, flag, ix) | |
1297 | queue_entry_t qhp; | |
1298 | { | |
1299 | register queue_entry_t qp, pqp; | |
1300 | register struct mapping *mp; | |
1301 | struct mapstate *ms; | |
1302 | ||
1303 | qp = qhp->next; | |
1304 | /* | |
1305 | * First element is not a mapping structure, | |
1306 | * chain must be empty. | |
1307 | */ | |
1308 | if (!IS_MAPPTR(qp)) { | |
1309 | if (qp != qhp || qp != qhp->prev) | |
1310 | fatal("bad vtop_table header pointer"); | |
1311 | } else { | |
1312 | pqp = qhp; | |
1313 | do { | |
1314 | mp = (struct mapping *) qp; | |
1315 | qp = &mp->hash_link; | |
1316 | if (qp->prev != pqp) | |
1317 | fatal("bad hash_link prev pointer"); | |
1318 | ms = &mapstate[mp-map_table]; | |
1319 | ms->flags |= flag; | |
1320 | ms->hashix = ix; | |
1321 | pqp = (queue_entry_t) mp; | |
1322 | qp = qp->next; | |
1323 | } while (IS_MAPPTR(qp)); | |
1324 | if (qp != qhp) | |
1325 | fatal("bad hash_link next pointer"); | |
1326 | } | |
1327 | } | |
1328 | ||
1329 | STATIC void | |
1330 | checkphyschain(qhp, flag, ix) | |
1331 | queue_entry_t qhp; | |
1332 | { | |
1333 | register queue_entry_t qp, pqp; | |
1334 | register struct mapping *mp; | |
1335 | struct mapstate *ms; | |
1336 | ||
1337 | qp = qhp->next; | |
1338 | /* | |
1339 | * First element is not a mapping structure, | |
1340 | * chain must be empty. | |
1341 | */ | |
1342 | if (!IS_MAPPTR(qp)) { | |
1343 | if (qp != qhp || qp != qhp->prev) | |
1344 | fatal("bad phys_table header pointer"); | |
1345 | } else { | |
1346 | pqp = qhp; | |
1347 | do { | |
1348 | mp = (struct mapping *) qp; | |
1349 | qp = &mp->phys_link; | |
1350 | if (qp->prev != pqp) | |
1351 | fatal("bad phys_link prev pointer"); | |
1352 | ms = &mapstate[mp-map_table]; | |
1353 | ms->flags |= flag; | |
1354 | ms->physix = ix; | |
1355 | pqp = (queue_entry_t) mp; | |
1356 | qp = qp->next; | |
1357 | } while (IS_MAPPTR(qp)); | |
1358 | if (qp != qhp) | |
1359 | fatal("bad phys_link next pointer"); | |
1360 | } | |
1361 | } | |
1362 | ||
1363 | STATIC void | |
1364 | merror(ms, str) | |
1365 | struct mapstate *ms; | |
1366 | char *str; | |
1367 | { | |
1368 | terminal_ours(); | |
1369 | fflush(stdout); | |
1370 | fprintf(stderr, | |
1371 | "vtophys: %s: %c%c%c, hashix %d, physix %d, mapping %x\n", | |
1372 | str, | |
1373 | (ms->flags & M_ISFREE) ? 'F' : '-', | |
1374 | (ms->flags & M_ISHASH) ? 'H' : '-', | |
1375 | (ms->flags & M_ISPHYS) ? 'P' : '-', | |
1376 | ms->hashix, ms->physix, &map_table[ms-mapstate]); | |
1377 | return_to_top_level(); | |
1378 | } | |
1379 | ||
1380 | STATIC int | |
1381 | mach_read(str, from, top, size) | |
1382 | char *str; | |
1383 | CORE_ADDR from; | |
1384 | char *top; | |
1385 | int size; | |
1386 | { | |
1387 | CORE_ADDR paddr; | |
1388 | ||
1389 | if (from == ~0) | |
1390 | from = ksym_lookup(str); | |
1391 | paddr = vtophys(0, from); | |
1392 | if (paddr == ~0 || physrd(paddr, top, size) != 0) | |
1393 | fatal("cannot read %s", str); | |
1394 | } | |
1395 | ||
1396 | STATIC char * | |
1397 | mach_malloc(str, size) | |
1398 | char *str; | |
1399 | int size; | |
1400 | { | |
1401 | char *ptr = (char *) malloc(size); | |
1402 | ||
1403 | if (ptr == 0) | |
1404 | fatal("no memory for %s", str); | |
1405 | return(ptr); | |
1406 | } | |
1407 | #endif | |
1408 | ||
1409 | #ifdef KERNELDEBUG | |
1410 | void | |
1411 | _initialize_hp9k8_dep() | |
1412 | { | |
1413 | add_com ("process-address", class_obscure, set_paddr_command, | |
1414 | "The process identified by (ps-style) ADDR becomes the\n\ | |
1415 | \"current\" process context for kernel debugging."); | |
1416 | add_com_alias ("paddr", "process-address", class_obscure, 0); | |
1417 | add_com ("virtual-to-physical", class_obscure, vtop_command, | |
1418 | "Translates the kernel virtual address ADDR into a physical address."); | |
1419 | add_com_alias ("vtop", "virtual-to-physical", class_obscure, 0); | |
1420 | } | |
1421 | #endif |