]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/mips/mips/vm_machdep.c
DTrace: print() should try to resolve function pointers
[FreeBSD/FreeBSD.git] / sys / mips / mips / vm_machdep.c
1 /*-
2  * Copyright (c) 1982, 1986 The Regents of the University of California.
3  * Copyright (c) 1989, 1990 William Jolitz
4  * Copyright (c) 1994 John Dyson
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * the Systems Programming Group of the University of Utah Computer
9  * Science Department, and William Jolitz.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  *      from: @(#)vm_machdep.c  7.3 (Berkeley) 5/13/91
36  *      Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$
37  *      from: src/sys/i386/i386/vm_machdep.c,v 1.132.2.2 2000/08/26 04:19:26 yokota
38  *      JNPR: vm_machdep.c,v 1.8.2.2 2007/08/16 15:59:17 girish
39  */
40
41 #include <sys/cdefs.h>
42 __FBSDID("$FreeBSD$");
43
44 #include "opt_compat.h"
45 #include "opt_ddb.h"
46
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/malloc.h>
50 #include <sys/proc.h>
51 #include <sys/syscall.h>
52 #include <sys/sysent.h>
53 #include <sys/buf.h>
54 #include <sys/vnode.h>
55 #include <sys/vmmeter.h>
56 #include <sys/kernel.h>
57 #include <sys/sysctl.h>
58 #include <sys/unistd.h>
59
60 #include <machine/asm.h>
61 #include <machine/cache.h>
62 #include <machine/clock.h>
63 #include <machine/cpu.h>
64 #include <machine/md_var.h>
65 #include <machine/pcb.h>
66
67 #include <vm/vm.h>
68 #include <vm/vm_extern.h>
69 #include <vm/pmap.h>
70 #include <vm/vm_kern.h>
71 #include <vm/vm_map.h>
72 #include <vm/vm_page.h>
73 #include <vm/vm_pageout.h>
74 #include <vm/vm_param.h>
75 #include <vm/uma.h>
76 #include <vm/uma_int.h>
77
78 #include <sys/user.h>
79 #include <sys/mbuf.h>
80 #include <sys/sf_buf.h>
81
82 #ifndef NSFBUFS
83 #define NSFBUFS         (512 + maxusers * 16)
84 #endif
85
86 #ifndef __mips_n64
87 static void     sf_buf_init(void *arg);
88 SYSINIT(sock_sf, SI_SUB_MBUF, SI_ORDER_ANY, sf_buf_init, NULL);
89
90 /*
91  * Expanded sf_freelist head.  Really an SLIST_HEAD() in disguise, with the
92  * sf_freelist head with the sf_lock mutex.
93  */
94 static struct {
95         SLIST_HEAD(, sf_buf) sf_head;
96         struct mtx sf_lock;
97 } sf_freelist;
98
99 static u_int    sf_buf_alloc_want;
100 #endif
101
102 /*
103  * Finish a fork operation, with process p2 nearly set up.
104  * Copy and update the pcb, set up the stack so that the child
105  * ready to run and return to user mode.
106  */
107 void
108 cpu_fork(register struct thread *td1,register struct proc *p2,
109     struct thread *td2,int flags)
110 {
111         register struct proc *p1;
112         struct pcb *pcb2;
113
114         p1 = td1->td_proc;
115         if ((flags & RFPROC) == 0)
116                 return;
117         /* It is assumed that the vm_thread_alloc called
118          * cpu_thread_alloc() before cpu_fork is called.
119          */
120
121         /* Point the pcb to the top of the stack */
122         pcb2 = td2->td_pcb;
123
124         /* Copy p1's pcb, note that in this case
125          * our pcb also includes the td_frame being copied
126          * too. The older mips2 code did an additional copy
127          * of the td_frame, for us that's not needed any
128          * longer (this copy does them both) 
129          */
130         bcopy(td1->td_pcb, pcb2, sizeof(*pcb2));
131
132         /* Point mdproc and then copy over td1's contents
133          * md_proc is empty for MIPS
134          */
135         td2->td_md.md_flags = td1->td_md.md_flags & MDTD_FPUSED;
136
137         /*
138          * Set up return-value registers as fork() libc stub expects.
139          */
140         td2->td_frame->v0 = 0;
141         td2->td_frame->v1 = 1;
142         td2->td_frame->a3 = 0;
143
144         if (td1 == PCPU_GET(fpcurthread))
145                 MipsSaveCurFPState(td1);
146
147         pcb2->pcb_context[PCB_REG_RA] = (register_t)(intptr_t)fork_trampoline;
148         /* Make sp 64-bit aligned */
149         pcb2->pcb_context[PCB_REG_SP] = (register_t)(((vm_offset_t)td2->td_pcb &
150             ~(sizeof(__int64_t) - 1)) - CALLFRAME_SIZ);
151         pcb2->pcb_context[PCB_REG_S0] = (register_t)(intptr_t)fork_return;
152         pcb2->pcb_context[PCB_REG_S1] = (register_t)(intptr_t)td2;
153         pcb2->pcb_context[PCB_REG_S2] = (register_t)(intptr_t)td2->td_frame;
154         pcb2->pcb_context[PCB_REG_SR] = mips_rd_status() &
155             (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_INT_MASK);
156         /*
157          * FREEBSD_DEVELOPERS_FIXME:
158          * Setup any other CPU-Specific registers (Not MIPS Standard)
159          * and/or bits in other standard MIPS registers (if CPU-Specific)
160          *  that are needed.
161          */
162
163         td2->td_md.md_tls = td1->td_md.md_tls;
164         td2->td_md.md_saved_intr = MIPS_SR_INT_IE;
165         td2->td_md.md_spinlock_count = 1;
166 #ifdef CPU_CNMIPS
167         if (td1->td_md.md_flags & MDTD_COP2USED) {
168                 if (td1->td_md.md_cop2owner == COP2_OWNER_USERLAND) {
169                         if (td1->td_md.md_ucop2)
170                                 octeon_cop2_save(td1->td_md.md_ucop2);
171                         else
172                                 panic("cpu_fork: ucop2 is NULL but COP2 is enabled");
173                 }
174                 else {
175                         if (td1->td_md.md_cop2)
176                                 octeon_cop2_save(td1->td_md.md_cop2);
177                         else
178                                 panic("cpu_fork: cop2 is NULL but COP2 is enabled");
179                 }
180         }
181
182         if (td1->td_md.md_cop2) {
183                 td2->td_md.md_cop2 = octeon_cop2_alloc_ctx();
184                 memcpy(td2->td_md.md_cop2, td1->td_md.md_cop2, 
185                         sizeof(*td1->td_md.md_cop2));
186         }
187         if (td1->td_md.md_ucop2) {
188                 td2->td_md.md_ucop2 = octeon_cop2_alloc_ctx();
189                 memcpy(td2->td_md.md_ucop2, td1->td_md.md_ucop2, 
190                         sizeof(*td1->td_md.md_ucop2));
191         }
192         td2->td_md.md_cop2owner = td1->td_md.md_cop2owner;
193         pcb2->pcb_context[PCB_REG_SR] |= MIPS_SR_PX | MIPS_SR_UX | MIPS_SR_KX | MIPS_SR_SX;
194         /* Clear COP2 bits for userland & kernel */
195         td2->td_frame->sr &= ~MIPS_SR_COP_2_BIT;
196         pcb2->pcb_context[PCB_REG_SR] &= ~MIPS_SR_COP_2_BIT;
197 #endif
198 }
199
200 /*
201  * Intercept the return address from a freshly forked process that has NOT
202  * been scheduled yet.
203  *
204  * This is needed to make kernel threads stay in kernel mode.
205  */
206 void
207 cpu_set_fork_handler(struct thread *td, void (*func) __P((void *)), void *arg)
208 {
209         /*
210          * Note that the trap frame follows the args, so the function
211          * is really called like this:  func(arg, frame);
212          */
213         td->td_pcb->pcb_context[PCB_REG_S0] = (register_t)(intptr_t)func;
214         td->td_pcb->pcb_context[PCB_REG_S1] = (register_t)(intptr_t)arg;
215 }
216
217 void
218 cpu_exit(struct thread *td)
219 {
220 }
221
222 void
223 cpu_thread_exit(struct thread *td)
224 {
225
226         if (PCPU_GET(fpcurthread) == td)
227                 PCPU_GET(fpcurthread) = (struct thread *)0;
228 #ifdef  CPU_CNMIPS
229         if (td->td_md.md_cop2)
230                 memset(td->td_md.md_cop2, 0,
231                         sizeof(*td->td_md.md_cop2));
232         if (td->td_md.md_ucop2)
233                 memset(td->td_md.md_ucop2, 0,
234                         sizeof(*td->td_md.md_ucop2));
235 #endif
236 }
237
238 void
239 cpu_thread_free(struct thread *td)
240 {
241 #ifdef  CPU_CNMIPS
242         if (td->td_md.md_cop2)
243                 octeon_cop2_free_ctx(td->td_md.md_cop2);
244         if (td->td_md.md_ucop2)
245                 octeon_cop2_free_ctx(td->td_md.md_ucop2);
246         td->td_md.md_cop2 = NULL;
247         td->td_md.md_ucop2 = NULL;
248 #endif
249 }
250
251 void
252 cpu_thread_clean(struct thread *td)
253 {
254 }
255
256 void
257 cpu_thread_swapin(struct thread *td)
258 {
259         pt_entry_t *pte;
260         int i;
261
262         /*
263          * The kstack may be at a different physical address now.
264          * Cache the PTEs for the Kernel stack in the machine dependent
265          * part of the thread struct so cpu_switch() can quickly map in
266          * the pcb struct and kernel stack.
267          */
268         for (i = 0; i < KSTACK_PAGES; i++) {
269                 pte = pmap_pte(kernel_pmap, td->td_kstack + i * PAGE_SIZE);
270                 td->td_md.md_upte[i] = *pte & ~TLBLO_SWBITS_MASK;
271         }
272 }
273
274 void
275 cpu_thread_swapout(struct thread *td)
276 {
277 }
278
279 void
280 cpu_thread_alloc(struct thread *td)
281 {
282         pt_entry_t *pte;
283         int i;
284
285         KASSERT((td->td_kstack & (1 << PAGE_SHIFT)) == 0, ("kernel stack must be aligned."));
286         td->td_pcb = (struct pcb *)(td->td_kstack +
287             td->td_kstack_pages * PAGE_SIZE) - 1;
288         td->td_frame = &td->td_pcb->pcb_regs;
289
290         for (i = 0; i < KSTACK_PAGES; i++) {
291                 pte = pmap_pte(kernel_pmap, td->td_kstack + i * PAGE_SIZE);
292                 td->td_md.md_upte[i] = *pte & ~TLBLO_SWBITS_MASK;
293         }
294 }
295
296 void
297 cpu_set_syscall_retval(struct thread *td, int error)
298 {
299         struct trapframe *locr0 = td->td_frame;
300         unsigned int code;
301         int quad_syscall;
302
303         code = locr0->v0;
304         quad_syscall = 0;
305 #if defined(__mips_n32) || defined(__mips_n64)
306 #ifdef COMPAT_FREEBSD32
307         if (code == SYS___syscall && SV_PROC_FLAG(td->td_proc, SV_ILP32))
308                 quad_syscall = 1;
309 #endif
310 #else
311         if (code == SYS___syscall)
312                 quad_syscall = 1;
313 #endif
314
315         if (code == SYS_syscall)
316                 code = locr0->a0;
317         else if (code == SYS___syscall) {
318                 if (quad_syscall)
319                         code = _QUAD_LOWWORD ? locr0->a1 : locr0->a0;
320                 else
321                         code = locr0->a0;
322         }
323
324         switch (error) {
325         case 0:
326                 if (quad_syscall && code != SYS_lseek) {
327                         /*
328                          * System call invoked through the
329                          * SYS___syscall interface but the
330                          * return value is really just 32
331                          * bits.
332                          */
333                         locr0->v0 = td->td_retval[0];
334                         if (_QUAD_LOWWORD)
335                                 locr0->v1 = td->td_retval[0];
336                         locr0->a3 = 0;
337                 } else {
338                         locr0->v0 = td->td_retval[0];
339                         locr0->v1 = td->td_retval[1];
340                         locr0->a3 = 0;
341                 }
342                 break;
343
344         case ERESTART:
345                 locr0->pc = td->td_pcb->pcb_tpc;
346                 break;
347
348         case EJUSTRETURN:
349                 break;  /* nothing to do */
350
351         default:
352                 if (quad_syscall && code != SYS_lseek) {
353                         locr0->v0 = error;
354                         if (_QUAD_LOWWORD)
355                                 locr0->v1 = error;
356                         locr0->a3 = 1;
357                 } else {
358                         locr0->v0 = error;
359                         locr0->a3 = 1;
360                 }
361         }
362 }
363
364 /*
365  * Initialize machine state (pcb and trap frame) for a new thread about to
366  * upcall. Put enough state in the new thread's PCB to get it to go back
367  * userret(), where we can intercept it again to set the return (upcall)
368  * Address and stack, along with those from upcalls that are from other sources
369  * such as those generated in thread_userret() itself.
370  */
371 void
372 cpu_set_upcall(struct thread *td, struct thread *td0)
373 {
374         struct pcb *pcb2;
375
376         /* Point the pcb to the top of the stack. */
377         pcb2 = td->td_pcb;
378
379         /*
380          * Copy the upcall pcb.  This loads kernel regs.
381          * Those not loaded individually below get their default
382          * values here.
383          *
384          * XXXKSE It might be a good idea to simply skip this as
385          * the values of the other registers may be unimportant.
386          * This would remove any requirement for knowing the KSE
387          * at this time (see the matching comment below for
388          * more analysis) (need a good safe default).
389          * In MIPS, the trapframe is the first element of the PCB
390          * and gets copied when we copy the PCB. No separate copy
391          * is needed.
392          */
393         bcopy(td0->td_pcb, pcb2, sizeof(*pcb2));
394
395         /*
396          * Set registers for trampoline to user mode.
397          */
398
399         pcb2->pcb_context[PCB_REG_RA] = (register_t)(intptr_t)fork_trampoline;
400         /* Make sp 64-bit aligned */
401         pcb2->pcb_context[PCB_REG_SP] = (register_t)(((vm_offset_t)td->td_pcb &
402             ~(sizeof(__int64_t) - 1)) - CALLFRAME_SIZ);
403         pcb2->pcb_context[PCB_REG_S0] = (register_t)(intptr_t)fork_return;
404         pcb2->pcb_context[PCB_REG_S1] = (register_t)(intptr_t)td;
405         pcb2->pcb_context[PCB_REG_S2] = (register_t)(intptr_t)td->td_frame;
406         /* Dont set IE bit in SR. sched lock release will take care of it */
407         pcb2->pcb_context[PCB_REG_SR] = mips_rd_status() &
408             (MIPS_SR_PX | MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_INT_MASK);
409
410         /*
411          * FREEBSD_DEVELOPERS_FIXME:
412          * Setup any other CPU-Specific registers (Not MIPS Standard)
413          * that are needed.
414          */
415
416         /* SMP Setup to release sched_lock in fork_exit(). */
417         td->td_md.md_spinlock_count = 1;
418         td->td_md.md_saved_intr = MIPS_SR_INT_IE;
419 #if 0
420             /* Maybe we need to fix this? */
421         td->td_md.md_saved_sr = ( (MIPS_SR_COP_2_BIT | MIPS_SR_COP_0_BIT) |
422                                   (MIPS_SR_PX | MIPS_SR_UX | MIPS_SR_KX | MIPS_SR_SX) |
423                                   (MIPS_SR_INT_IE | MIPS_HARD_INT_MASK));
424 #endif
425 }
426
427 /*
428  * Set that machine state for performing an upcall that has to
429  * be done in thread_userret() so that those upcalls generated
430  * in thread_userret() itself can be done as well.
431  */
432 void
433 cpu_set_upcall_kse(struct thread *td, void (*entry)(void *), void *arg,
434     stack_t *stack)
435 {
436         struct trapframe *tf;
437         register_t sp;
438
439         /*
440         * At the point where a function is called, sp must be 8
441         * byte aligned[for compatibility with 64-bit CPUs]
442         * in ``See MIPS Run'' by D. Sweetman, p. 269
443         * align stack */
444         sp = ((register_t)(intptr_t)(stack->ss_sp + stack->ss_size) & ~0x7) -
445             CALLFRAME_SIZ;
446
447         /*
448          * Set the trap frame to point at the beginning of the uts
449          * function.
450          */
451         tf = td->td_frame;
452         bzero(tf, sizeof(struct trapframe));
453         tf->sp = sp;
454         tf->pc = (register_t)(intptr_t)entry;
455         /* 
456          * MIPS ABI requires T9 to be the same as PC 
457          * in subroutine entry point
458          */
459         tf->t9 = (register_t)(intptr_t)entry; 
460         tf->a0 = (register_t)(intptr_t)arg;
461
462         /*
463          * Keep interrupt mask
464          */
465         td->td_frame->sr = MIPS_SR_KSU_USER | MIPS_SR_EXL | MIPS_SR_INT_IE |
466             (mips_rd_status() & MIPS_SR_INT_MASK);
467 #if defined(__mips_n32) 
468         td->td_frame->sr |= MIPS_SR_PX;
469 #elif  defined(__mips_n64)
470         td->td_frame->sr |= MIPS_SR_PX | MIPS_SR_UX | MIPS_SR_KX;
471 #endif
472 /*      tf->sr |= (ALL_INT_MASK & idle_mask) | SR_INT_ENAB; */
473         /**XXX the above may now be wrong -- mips2 implements this as panic */
474         /*
475          * FREEBSD_DEVELOPERS_FIXME:
476          * Setup any other CPU-Specific registers (Not MIPS Standard)
477          * that are needed.
478          */
479 }
480
481 /*
482  * Implement the pre-zeroed page mechanism.
483  * This routine is called from the idle loop.
484  */
485
486 #define ZIDLE_LO(v)     ((v) * 2 / 3)
487 #define ZIDLE_HI(v)     ((v) * 4 / 5)
488
489 /*
490  * Allocate a pool of sf_bufs (sendfile(2) or "super-fast" if you prefer. :-))
491  */
492 #ifndef __mips_n64
493 static void
494 sf_buf_init(void *arg)
495 {
496         struct sf_buf *sf_bufs;
497         vm_offset_t sf_base;
498         int i;
499
500         nsfbufs = NSFBUFS;
501         TUNABLE_INT_FETCH("kern.ipc.nsfbufs", &nsfbufs);
502
503         mtx_init(&sf_freelist.sf_lock, "sf_bufs list lock", NULL, MTX_DEF);
504         SLIST_INIT(&sf_freelist.sf_head);
505         sf_base = kmem_alloc_nofault(kernel_map, nsfbufs * PAGE_SIZE);
506         sf_bufs = malloc(nsfbufs * sizeof(struct sf_buf), M_TEMP,
507             M_NOWAIT | M_ZERO);
508         for (i = 0; i < nsfbufs; i++) {
509                 sf_bufs[i].kva = sf_base + i * PAGE_SIZE;
510                 SLIST_INSERT_HEAD(&sf_freelist.sf_head, &sf_bufs[i], free_list);
511         }
512         sf_buf_alloc_want = 0;
513 }
514 #endif
515
516 /*
517  * Get an sf_buf from the freelist.  Will block if none are available.
518  */
519 struct sf_buf *
520 sf_buf_alloc(struct vm_page *m, int flags)
521 {
522 #ifndef __mips_n64
523         struct sf_buf *sf;
524         int error;
525
526         mtx_lock(&sf_freelist.sf_lock);
527         while ((sf = SLIST_FIRST(&sf_freelist.sf_head)) == NULL) {
528                 if (flags & SFB_NOWAIT)
529                         break;
530                 sf_buf_alloc_want++;
531                 mbstat.sf_allocwait++;
532                 error = msleep(&sf_freelist, &sf_freelist.sf_lock,
533                     (flags & SFB_CATCH) ? PCATCH | PVM : PVM, "sfbufa", 0);
534                 sf_buf_alloc_want--;
535
536                 /*
537                  * If we got a signal, don't risk going back to sleep.
538                  */
539                 if (error)
540                         break;
541         }
542         if (sf != NULL) {
543                 SLIST_REMOVE_HEAD(&sf_freelist.sf_head, free_list);
544                 sf->m = m;
545                 nsfbufsused++;
546                 nsfbufspeak = imax(nsfbufspeak, nsfbufsused);
547                 pmap_qenter(sf->kva, &sf->m, 1);
548         }
549         mtx_unlock(&sf_freelist.sf_lock);
550         return (sf);
551 #else
552         return ((struct sf_buf *)m);
553 #endif
554 }
555
556 /*
557  * Release resources back to the system.
558  */
559 void
560 sf_buf_free(struct sf_buf *sf)
561 {
562 #ifndef __mips_n64
563         pmap_qremove(sf->kva, 1);
564         mtx_lock(&sf_freelist.sf_lock);
565         SLIST_INSERT_HEAD(&sf_freelist.sf_head, sf, free_list);
566         nsfbufsused--;
567         if (sf_buf_alloc_want > 0)
568                 wakeup(&sf_freelist);
569         mtx_unlock(&sf_freelist.sf_lock);
570 #endif
571 }
572
573 /*
574  * Software interrupt handler for queued VM system processing.
575  */
576 void
577 swi_vm(void *dummy)
578 {
579
580         if (busdma_swi_pending)
581                 busdma_swi();
582 }
583
584 int
585 cpu_set_user_tls(struct thread *td, void *tls_base)
586 {
587
588         td->td_md.md_tls = (char*)tls_base;
589
590         return (0);
591 }
592
593 #ifdef DDB
594 #include <ddb/ddb.h>
595
596 #define DB_PRINT_REG(ptr, regname)                      \
597         db_printf("  %-12s %p\n", #regname, (void *)(intptr_t)((ptr)->regname))
598
599 #define DB_PRINT_REG_ARRAY(ptr, arrname, regname)       \
600         db_printf("  %-12s %p\n", #regname, (void *)(intptr_t)((ptr)->arrname[regname]))
601
602 static void
603 dump_trapframe(struct trapframe *trapframe)
604 {
605
606         db_printf("Trapframe at %p\n", trapframe);
607
608         DB_PRINT_REG(trapframe, zero);
609         DB_PRINT_REG(trapframe, ast);
610         DB_PRINT_REG(trapframe, v0);
611         DB_PRINT_REG(trapframe, v1);
612         DB_PRINT_REG(trapframe, a0);
613         DB_PRINT_REG(trapframe, a1);
614         DB_PRINT_REG(trapframe, a2);
615         DB_PRINT_REG(trapframe, a3);
616         DB_PRINT_REG(trapframe, t0);
617         DB_PRINT_REG(trapframe, t1);
618         DB_PRINT_REG(trapframe, t2);
619         DB_PRINT_REG(trapframe, t3);
620         DB_PRINT_REG(trapframe, t4);
621         DB_PRINT_REG(trapframe, t5);
622         DB_PRINT_REG(trapframe, t6);
623         DB_PRINT_REG(trapframe, t7);
624         DB_PRINT_REG(trapframe, s0);
625         DB_PRINT_REG(trapframe, s1);
626         DB_PRINT_REG(trapframe, s2);
627         DB_PRINT_REG(trapframe, s3);
628         DB_PRINT_REG(trapframe, s4);
629         DB_PRINT_REG(trapframe, s5);
630         DB_PRINT_REG(trapframe, s6);
631         DB_PRINT_REG(trapframe, s7);
632         DB_PRINT_REG(trapframe, t8);
633         DB_PRINT_REG(trapframe, t9);
634         DB_PRINT_REG(trapframe, k0);
635         DB_PRINT_REG(trapframe, k1);
636         DB_PRINT_REG(trapframe, gp);
637         DB_PRINT_REG(trapframe, sp);
638         DB_PRINT_REG(trapframe, s8);
639         DB_PRINT_REG(trapframe, ra);
640         DB_PRINT_REG(trapframe, sr);
641         DB_PRINT_REG(trapframe, mullo);
642         DB_PRINT_REG(trapframe, mulhi);
643         DB_PRINT_REG(trapframe, badvaddr);
644         DB_PRINT_REG(trapframe, cause);
645         DB_PRINT_REG(trapframe, pc);
646 }
647
648 DB_SHOW_COMMAND(pcb, ddb_dump_pcb)
649 {
650         struct thread *td;
651         struct pcb *pcb;
652         struct trapframe *trapframe;
653
654         /* Determine which thread to examine. */
655         if (have_addr)
656                 td = db_lookup_thread(addr, TRUE);
657         else
658                 td = curthread;
659         
660         pcb = td->td_pcb;
661
662         db_printf("Thread %d at %p\n", td->td_tid, td);
663
664         db_printf("PCB at %p\n", pcb);
665
666         trapframe = &pcb->pcb_regs;
667         dump_trapframe(trapframe);
668
669         db_printf("PCB Context:\n");
670         DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_S0);
671         DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_S1);
672         DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_S2);
673         DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_S3);
674         DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_S4);
675         DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_S5);
676         DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_S6);
677         DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_S7);
678         DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_SP);
679         DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_S8);
680         DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_RA);
681         DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_SR);
682         DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_GP);
683         DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_PC);
684
685         db_printf("PCB onfault = %p\n", pcb->pcb_onfault);
686         db_printf("md_saved_intr = 0x%0lx\n", (long)td->td_md.md_saved_intr);
687         db_printf("md_spinlock_count = %d\n", td->td_md.md_spinlock_count);
688
689         if (td->td_frame != trapframe) {
690                 db_printf("td->td_frame %p is not the same as pcb_regs %p\n",
691                           td->td_frame, trapframe);
692         }
693 }
694
695 /*
696  * Dump the trapframe beginning at address specified by first argument.
697  */
698 DB_SHOW_COMMAND(trapframe, ddb_dump_trapframe)
699 {
700         
701         if (!have_addr)
702                 return;
703
704         dump_trapframe((struct trapframe *)addr);
705 }
706
707 #endif  /* DDB */