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