vm_machdep.c revision 254025
1178172Simp/*- 2178172Simp * Copyright (c) 1982, 1986 The Regents of the University of California. 3178172Simp * Copyright (c) 1989, 1990 William Jolitz 4178172Simp * Copyright (c) 1994 John Dyson 5178172Simp * All rights reserved. 6178172Simp * 7178172Simp * This code is derived from software contributed to Berkeley by 8178172Simp * the Systems Programming Group of the University of Utah Computer 9178172Simp * Science Department, and William Jolitz. 10178172Simp * 11178172Simp * Redistribution and use in source and binary forms, with or without 12178172Simp * modification, are permitted provided that the following conditions 13178172Simp * are met: 14178172Simp * 1. Redistributions of source code must retain the above copyright 15178172Simp * notice, this list of conditions and the following disclaimer. 16178172Simp * 2. Redistributions in binary form must reproduce the above copyright 17178172Simp * notice, this list of conditions and the following disclaimer in the 18178172Simp * documentation and/or other materials provided with the distribution. 19178172Simp * 4. Neither the name of the University nor the names of its contributors 20178172Simp * may be used to endorse or promote products derived from this software 21178172Simp * without specific prior written permission. 22178172Simp * 23178172Simp * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24178172Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25178172Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26178172Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27178172Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28178172Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29178172Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30178172Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31178172Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32178172Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33178172Simp * SUCH DAMAGE. 34178172Simp * 35178172Simp * from: @(#)vm_machdep.c 7.3 (Berkeley) 5/13/91 36178172Simp * Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$ 37178172Simp * from: src/sys/i386/i386/vm_machdep.c,v 1.132.2.2 2000/08/26 04:19:26 yokota 38178172Simp * JNPR: vm_machdep.c,v 1.8.2.2 2007/08/16 15:59:17 girish 39178172Simp */ 40178172Simp 41178172Simp#include <sys/cdefs.h> 42178172Simp__FBSDID("$FreeBSD: head/sys/mips/mips/vm_machdep.c 254025 2013-08-07 06:21:20Z jeff $"); 43178172Simp 44232449Sjmallett#include "opt_compat.h" 45202046Simp#include "opt_ddb.h" 46202046Simp 47178172Simp#include <sys/param.h> 48178172Simp#include <sys/systm.h> 49178172Simp#include <sys/malloc.h> 50178172Simp#include <sys/proc.h> 51199135Skib#include <sys/syscall.h> 52232449Sjmallett#include <sys/sysent.h> 53178172Simp#include <sys/buf.h> 54178172Simp#include <sys/vnode.h> 55178172Simp#include <sys/vmmeter.h> 56178172Simp#include <sys/kernel.h> 57178172Simp#include <sys/sysctl.h> 58178172Simp#include <sys/unistd.h> 59178172Simp 60202046Simp#include <machine/cache.h> 61178172Simp#include <machine/clock.h> 62178172Simp#include <machine/cpu.h> 63178172Simp#include <machine/md_var.h> 64178172Simp#include <machine/pcb.h> 65178172Simp 66178172Simp#include <vm/vm.h> 67206714Sjmallett#include <vm/vm_extern.h> 68206714Sjmallett#include <vm/pmap.h> 69178172Simp#include <vm/vm_kern.h> 70206714Sjmallett#include <vm/vm_map.h> 71178172Simp#include <vm/vm_page.h> 72206714Sjmallett#include <vm/vm_pageout.h> 73206714Sjmallett#include <vm/vm_param.h> 74206714Sjmallett#include <vm/uma.h> 75206714Sjmallett#include <vm/uma_int.h> 76178172Simp 77178172Simp#include <sys/user.h> 78178172Simp#include <sys/mbuf.h> 79178172Simp#include <sys/sf_buf.h> 80178172Simp 81178172Simp#ifndef NSFBUFS 82178172Simp#define NSFBUFS (512 + maxusers * 16) 83178172Simp#endif 84178172Simp 85250137Simp/* Duplicated from asm.h */ 86250137Simp#if defined(__mips_o32) 87250137Simp#define SZREG 4 88250137Simp#else 89250137Simp#define SZREG 8 90250137Simp#endif 91250137Simp#if defined(__mips_o32) || defined(__mips_o64) 92250137Simp#define CALLFRAME_SIZ (SZREG * (4 + 2)) 93250137Simp#elif defined(__mips_n32) || defined(__mips_n64) 94250137Simp#define CALLFRAME_SIZ (SZREG * 4) 95250137Simp#endif 96250137Simp 97217944Sjchandra#ifndef __mips_n64 98178172Simpstatic void sf_buf_init(void *arg); 99178172SimpSYSINIT(sock_sf, SI_SUB_MBUF, SI_ORDER_ANY, sf_buf_init, NULL); 100178172Simp 101178172Simp/* 102206714Sjmallett * Expanded sf_freelist head. Really an SLIST_HEAD() in disguise, with the 103206714Sjmallett * sf_freelist head with the sf_lock mutex. 104178172Simp */ 105206714Sjmallettstatic struct { 106206714Sjmallett SLIST_HEAD(, sf_buf) sf_head; 107206714Sjmallett struct mtx sf_lock; 108206714Sjmallett} sf_freelist; 109178172Simp 110178172Simpstatic u_int sf_buf_alloc_want; 111217944Sjchandra#endif 112178172Simp 113178172Simp/* 114178172Simp * Finish a fork operation, with process p2 nearly set up. 115178172Simp * Copy and update the pcb, set up the stack so that the child 116178172Simp * ready to run and return to user mode. 117178172Simp */ 118178172Simpvoid 119178172Simpcpu_fork(register struct thread *td1,register struct proc *p2, 120178172Simp struct thread *td2,int flags) 121178172Simp{ 122178172Simp register struct proc *p1; 123178172Simp struct pcb *pcb2; 124178172Simp 125178172Simp p1 = td1->td_proc; 126178172Simp if ((flags & RFPROC) == 0) 127178172Simp return; 128178172Simp /* It is assumed that the vm_thread_alloc called 129178172Simp * cpu_thread_alloc() before cpu_fork is called. 130178172Simp */ 131178172Simp 132178172Simp /* Point the pcb to the top of the stack */ 133178172Simp pcb2 = td2->td_pcb; 134178172Simp 135178172Simp /* Copy p1's pcb, note that in this case 136178172Simp * our pcb also includes the td_frame being copied 137178172Simp * too. The older mips2 code did an additional copy 138215034Sbrucec * of the td_frame, for us that's not needed any 139215034Sbrucec * longer (this copy does them both) 140178172Simp */ 141178172Simp bcopy(td1->td_pcb, pcb2, sizeof(*pcb2)); 142178172Simp 143178172Simp /* Point mdproc and then copy over td1's contents 144178172Simp * md_proc is empty for MIPS 145178172Simp */ 146178172Simp td2->td_md.md_flags = td1->td_md.md_flags & MDTD_FPUSED; 147178172Simp 148178172Simp /* 149178172Simp * Set up return-value registers as fork() libc stub expects. 150178172Simp */ 151178172Simp td2->td_frame->v0 = 0; 152178172Simp td2->td_frame->v1 = 1; 153178172Simp td2->td_frame->a3 = 0; 154178172Simp 155178172Simp if (td1 == PCPU_GET(fpcurthread)) 156178172Simp MipsSaveCurFPState(td1); 157178172Simp 158209500Sjchandra pcb2->pcb_context[PCB_REG_RA] = (register_t)(intptr_t)fork_trampoline; 159178172Simp /* Make sp 64-bit aligned */ 160202046Simp pcb2->pcb_context[PCB_REG_SP] = (register_t)(((vm_offset_t)td2->td_pcb & 161206834Sjmallett ~(sizeof(__int64_t) - 1)) - CALLFRAME_SIZ); 162209500Sjchandra pcb2->pcb_context[PCB_REG_S0] = (register_t)(intptr_t)fork_return; 163209500Sjchandra pcb2->pcb_context[PCB_REG_S1] = (register_t)(intptr_t)td2; 164209500Sjchandra pcb2->pcb_context[PCB_REG_S2] = (register_t)(intptr_t)td2->td_frame; 165210644Sjchandra pcb2->pcb_context[PCB_REG_SR] = mips_rd_status() & 166210644Sjchandra (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_INT_MASK); 167178172Simp /* 168178172Simp * FREEBSD_DEVELOPERS_FIXME: 169178172Simp * Setup any other CPU-Specific registers (Not MIPS Standard) 170178172Simp * and/or bits in other standard MIPS registers (if CPU-Specific) 171178172Simp * that are needed. 172178172Simp */ 173178172Simp 174202046Simp td2->td_md.md_tls = td1->td_md.md_tls; 175178172Simp td2->td_md.md_saved_intr = MIPS_SR_INT_IE; 176178172Simp td2->td_md.md_spinlock_count = 1; 177210311Sjmallett#ifdef CPU_CNMIPS 178229677Sgonzo if (td1->td_md.md_flags & MDTD_COP2USED) { 179229677Sgonzo if (td1->td_md.md_cop2owner == COP2_OWNER_USERLAND) { 180229677Sgonzo if (td1->td_md.md_ucop2) 181229677Sgonzo octeon_cop2_save(td1->td_md.md_ucop2); 182229677Sgonzo else 183229677Sgonzo panic("cpu_fork: ucop2 is NULL but COP2 is enabled"); 184229677Sgonzo } 185229677Sgonzo else { 186229677Sgonzo if (td1->td_md.md_cop2) 187229677Sgonzo octeon_cop2_save(td1->td_md.md_cop2); 188229677Sgonzo else 189229677Sgonzo panic("cpu_fork: cop2 is NULL but COP2 is enabled"); 190229677Sgonzo } 191229677Sgonzo } 192229677Sgonzo 193229677Sgonzo if (td1->td_md.md_cop2) { 194229677Sgonzo td2->td_md.md_cop2 = octeon_cop2_alloc_ctx(); 195229677Sgonzo memcpy(td2->td_md.md_cop2, td1->td_md.md_cop2, 196229677Sgonzo sizeof(*td1->td_md.md_cop2)); 197229677Sgonzo } 198229677Sgonzo if (td1->td_md.md_ucop2) { 199229677Sgonzo td2->td_md.md_ucop2 = octeon_cop2_alloc_ctx(); 200229677Sgonzo memcpy(td2->td_md.md_ucop2, td1->td_md.md_ucop2, 201229677Sgonzo sizeof(*td1->td_md.md_ucop2)); 202229677Sgonzo } 203229677Sgonzo td2->td_md.md_cop2owner = td1->td_md.md_cop2owner; 204229677Sgonzo pcb2->pcb_context[PCB_REG_SR] |= MIPS_SR_PX | MIPS_SR_UX | MIPS_SR_KX | MIPS_SR_SX; 205229677Sgonzo /* Clear COP2 bits for userland & kernel */ 206229677Sgonzo td2->td_frame->sr &= ~MIPS_SR_COP_2_BIT; 207229677Sgonzo pcb2->pcb_context[PCB_REG_SR] &= ~MIPS_SR_COP_2_BIT; 208178172Simp#endif 209178172Simp} 210178172Simp 211178172Simp/* 212178172Simp * Intercept the return address from a freshly forked process that has NOT 213178172Simp * been scheduled yet. 214178172Simp * 215178172Simp * This is needed to make kernel threads stay in kernel mode. 216178172Simp */ 217178172Simpvoid 218178172Simpcpu_set_fork_handler(struct thread *td, void (*func) __P((void *)), void *arg) 219178172Simp{ 220178172Simp /* 221178172Simp * Note that the trap frame follows the args, so the function 222178172Simp * is really called like this: func(arg, frame); 223178172Simp */ 224209500Sjchandra td->td_pcb->pcb_context[PCB_REG_S0] = (register_t)(intptr_t)func; 225209500Sjchandra td->td_pcb->pcb_context[PCB_REG_S1] = (register_t)(intptr_t)arg; 226178172Simp} 227178172Simp 228178172Simpvoid 229178172Simpcpu_exit(struct thread *td) 230178172Simp{ 231178172Simp} 232178172Simp 233178172Simpvoid 234178172Simpcpu_thread_exit(struct thread *td) 235178172Simp{ 236178172Simp 237178172Simp if (PCPU_GET(fpcurthread) == td) 238178172Simp PCPU_GET(fpcurthread) = (struct thread *)0; 239229677Sgonzo#ifdef CPU_CNMIPS 240229677Sgonzo if (td->td_md.md_cop2) 241229677Sgonzo memset(td->td_md.md_cop2, 0, 242229677Sgonzo sizeof(*td->td_md.md_cop2)); 243229677Sgonzo if (td->td_md.md_ucop2) 244229677Sgonzo memset(td->td_md.md_ucop2, 0, 245229677Sgonzo sizeof(*td->td_md.md_ucop2)); 246229677Sgonzo#endif 247178172Simp} 248178172Simp 249178172Simpvoid 250178172Simpcpu_thread_free(struct thread *td) 251178172Simp{ 252229677Sgonzo#ifdef CPU_CNMIPS 253229677Sgonzo if (td->td_md.md_cop2) 254229677Sgonzo octeon_cop2_free_ctx(td->td_md.md_cop2); 255229677Sgonzo if (td->td_md.md_ucop2) 256229677Sgonzo octeon_cop2_free_ctx(td->td_md.md_ucop2); 257229677Sgonzo td->td_md.md_cop2 = NULL; 258229677Sgonzo td->td_md.md_ucop2 = NULL; 259229677Sgonzo#endif 260178172Simp} 261178172Simp 262178172Simpvoid 263178172Simpcpu_thread_clean(struct thread *td) 264178172Simp{ 265178172Simp} 266178172Simp 267178172Simpvoid 268178172Simpcpu_thread_swapin(struct thread *td) 269178172Simp{ 270178172Simp pt_entry_t *pte; 271178172Simp int i; 272178172Simp 273178172Simp /* 274178172Simp * The kstack may be at a different physical address now. 275178172Simp * Cache the PTEs for the Kernel stack in the machine dependent 276178172Simp * part of the thread struct so cpu_switch() can quickly map in 277178172Simp * the pcb struct and kernel stack. 278178172Simp */ 279206819Sjmallett for (i = 0; i < KSTACK_PAGES; i++) { 280206819Sjmallett pte = pmap_pte(kernel_pmap, td->td_kstack + i * PAGE_SIZE); 281209482Sjchandra td->td_md.md_upte[i] = *pte & ~TLBLO_SWBITS_MASK; 282178172Simp } 283178172Simp} 284178172Simp 285178172Simpvoid 286178172Simpcpu_thread_swapout(struct thread *td) 287178172Simp{ 288178172Simp} 289178172Simp 290178172Simpvoid 291178172Simpcpu_thread_alloc(struct thread *td) 292178172Simp{ 293178172Simp pt_entry_t *pte; 294178172Simp int i; 295178172Simp 296206819Sjmallett KASSERT((td->td_kstack & (1 << PAGE_SHIFT)) == 0, ("kernel stack must be aligned.")); 297206819Sjmallett td->td_pcb = (struct pcb *)(td->td_kstack + 298206819Sjmallett td->td_kstack_pages * PAGE_SIZE) - 1; 299178172Simp td->td_frame = &td->td_pcb->pcb_regs; 300178172Simp 301206819Sjmallett for (i = 0; i < KSTACK_PAGES; i++) { 302206819Sjmallett pte = pmap_pte(kernel_pmap, td->td_kstack + i * PAGE_SIZE); 303209482Sjchandra td->td_md.md_upte[i] = *pte & ~TLBLO_SWBITS_MASK; 304178172Simp } 305178172Simp} 306178172Simp 307199135Skibvoid 308199135Skibcpu_set_syscall_retval(struct thread *td, int error) 309199135Skib{ 310199135Skib struct trapframe *locr0 = td->td_frame; 311199135Skib unsigned int code; 312199135Skib int quad_syscall; 313199135Skib 314199135Skib code = locr0->v0; 315199135Skib quad_syscall = 0; 316232449Sjmallett#if defined(__mips_n32) || defined(__mips_n64) 317232449Sjmallett#ifdef COMPAT_FREEBSD32 318232449Sjmallett if (code == SYS___syscall && SV_PROC_FLAG(td->td_proc, SV_ILP32)) 319232449Sjmallett quad_syscall = 1; 320232449Sjmallett#endif 321232449Sjmallett#else 322209500Sjchandra if (code == SYS___syscall) 323209500Sjchandra quad_syscall = 1; 324209500Sjchandra#endif 325209500Sjchandra 326199135Skib if (code == SYS_syscall) 327199135Skib code = locr0->a0; 328199135Skib else if (code == SYS___syscall) { 329209500Sjchandra if (quad_syscall) 330209500Sjchandra code = _QUAD_LOWWORD ? locr0->a1 : locr0->a0; 331209500Sjchandra else 332209500Sjchandra code = locr0->a0; 333199135Skib } 334199135Skib 335199135Skib switch (error) { 336199135Skib case 0: 337199135Skib if (quad_syscall && code != SYS_lseek) { 338199135Skib /* 339199135Skib * System call invoked through the 340199135Skib * SYS___syscall interface but the 341199135Skib * return value is really just 32 342199135Skib * bits. 343199135Skib */ 344199135Skib locr0->v0 = td->td_retval[0]; 345199135Skib if (_QUAD_LOWWORD) 346199135Skib locr0->v1 = td->td_retval[0]; 347199135Skib locr0->a3 = 0; 348199135Skib } else { 349199135Skib locr0->v0 = td->td_retval[0]; 350199135Skib locr0->v1 = td->td_retval[1]; 351199135Skib locr0->a3 = 0; 352199135Skib } 353199135Skib break; 354199135Skib 355199135Skib case ERESTART: 356199135Skib locr0->pc = td->td_pcb->pcb_tpc; 357199135Skib break; 358199135Skib 359199135Skib case EJUSTRETURN: 360199135Skib break; /* nothing to do */ 361199135Skib 362199135Skib default: 363199135Skib if (quad_syscall && code != SYS_lseek) { 364199135Skib locr0->v0 = error; 365199135Skib if (_QUAD_LOWWORD) 366199135Skib locr0->v1 = error; 367199135Skib locr0->a3 = 1; 368199135Skib } else { 369199135Skib locr0->v0 = error; 370199135Skib locr0->a3 = 1; 371199135Skib } 372199135Skib } 373199135Skib} 374199135Skib 375178172Simp/* 376178172Simp * Initialize machine state (pcb and trap frame) for a new thread about to 377178172Simp * upcall. Put enough state in the new thread's PCB to get it to go back 378178172Simp * userret(), where we can intercept it again to set the return (upcall) 379215034Sbrucec * Address and stack, along with those from upcalls that are from other sources 380178172Simp * such as those generated in thread_userret() itself. 381178172Simp */ 382178172Simpvoid 383178172Simpcpu_set_upcall(struct thread *td, struct thread *td0) 384178172Simp{ 385178172Simp struct pcb *pcb2; 386178172Simp 387178172Simp /* Point the pcb to the top of the stack. */ 388178172Simp pcb2 = td->td_pcb; 389178172Simp 390178172Simp /* 391178172Simp * Copy the upcall pcb. This loads kernel regs. 392178172Simp * Those not loaded individually below get their default 393178172Simp * values here. 394178172Simp * 395178172Simp * XXXKSE It might be a good idea to simply skip this as 396178172Simp * the values of the other registers may be unimportant. 397178172Simp * This would remove any requirement for knowing the KSE 398178172Simp * at this time (see the matching comment below for 399178172Simp * more analysis) (need a good safe default). 400178172Simp * In MIPS, the trapframe is the first element of the PCB 401215034Sbrucec * and gets copied when we copy the PCB. No separate copy 402178172Simp * is needed. 403178172Simp */ 404178172Simp bcopy(td0->td_pcb, pcb2, sizeof(*pcb2)); 405178172Simp 406178172Simp /* 407178172Simp * Set registers for trampoline to user mode. 408178172Simp */ 409178172Simp 410209500Sjchandra pcb2->pcb_context[PCB_REG_RA] = (register_t)(intptr_t)fork_trampoline; 411178172Simp /* Make sp 64-bit aligned */ 412202046Simp pcb2->pcb_context[PCB_REG_SP] = (register_t)(((vm_offset_t)td->td_pcb & 413206834Sjmallett ~(sizeof(__int64_t) - 1)) - CALLFRAME_SIZ); 414209500Sjchandra pcb2->pcb_context[PCB_REG_S0] = (register_t)(intptr_t)fork_return; 415209500Sjchandra pcb2->pcb_context[PCB_REG_S1] = (register_t)(intptr_t)td; 416209500Sjchandra pcb2->pcb_context[PCB_REG_S2] = (register_t)(intptr_t)td->td_frame; 417202046Simp /* Dont set IE bit in SR. sched lock release will take care of it */ 418210644Sjchandra pcb2->pcb_context[PCB_REG_SR] = mips_rd_status() & 419232770Sjmallett (MIPS_SR_PX | MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_INT_MASK); 420178172Simp 421178172Simp /* 422178172Simp * FREEBSD_DEVELOPERS_FIXME: 423178172Simp * Setup any other CPU-Specific registers (Not MIPS Standard) 424178172Simp * that are needed. 425178172Simp */ 426178172Simp 427178172Simp /* SMP Setup to release sched_lock in fork_exit(). */ 428178172Simp td->td_md.md_spinlock_count = 1; 429178172Simp td->td_md.md_saved_intr = MIPS_SR_INT_IE; 430178172Simp#if 0 431178172Simp /* Maybe we need to fix this? */ 432178172Simp td->td_md.md_saved_sr = ( (MIPS_SR_COP_2_BIT | MIPS_SR_COP_0_BIT) | 433210038Simp (MIPS_SR_PX | MIPS_SR_UX | MIPS_SR_KX | MIPS_SR_SX) | 434178172Simp (MIPS_SR_INT_IE | MIPS_HARD_INT_MASK)); 435178172Simp#endif 436178172Simp} 437178172Simp 438178172Simp/* 439178172Simp * Set that machine state for performing an upcall that has to 440178172Simp * be done in thread_userret() so that those upcalls generated 441178172Simp * in thread_userret() itself can be done as well. 442178172Simp */ 443178172Simpvoid 444178172Simpcpu_set_upcall_kse(struct thread *td, void (*entry)(void *), void *arg, 445178172Simp stack_t *stack) 446178172Simp{ 447178172Simp struct trapframe *tf; 448202046Simp register_t sp; 449178172Simp 450178172Simp /* 451250137Simp * At the point where a function is called, sp must be 8 452250137Simp * byte aligned[for compatibility with 64-bit CPUs] 453250137Simp * in ``See MIPS Run'' by D. Sweetman, p. 269 454250137Simp * align stack 455250137Simp */ 456209500Sjchandra sp = ((register_t)(intptr_t)(stack->ss_sp + stack->ss_size) & ~0x7) - 457206834Sjmallett CALLFRAME_SIZ; 458178172Simp 459178172Simp /* 460178172Simp * Set the trap frame to point at the beginning of the uts 461178172Simp * function. 462178172Simp */ 463178172Simp tf = td->td_frame; 464178172Simp bzero(tf, sizeof(struct trapframe)); 465209500Sjchandra tf->sp = sp; 466209500Sjchandra tf->pc = (register_t)(intptr_t)entry; 467202046Simp /* 468202046Simp * MIPS ABI requires T9 to be the same as PC 469202046Simp * in subroutine entry point 470202046Simp */ 471209500Sjchandra tf->t9 = (register_t)(intptr_t)entry; 472209500Sjchandra tf->a0 = (register_t)(intptr_t)arg; 473178172Simp 474202046Simp /* 475202046Simp * Keep interrupt mask 476202046Simp */ 477210644Sjchandra td->td_frame->sr = MIPS_SR_KSU_USER | MIPS_SR_EXL | MIPS_SR_INT_IE | 478210644Sjchandra (mips_rd_status() & MIPS_SR_INT_MASK); 479210644Sjchandra#if defined(__mips_n32) 480210644Sjchandra td->td_frame->sr |= MIPS_SR_PX; 481210644Sjchandra#elif defined(__mips_n64) 482211218Sjchandra td->td_frame->sr |= MIPS_SR_PX | MIPS_SR_UX | MIPS_SR_KX; 483210644Sjchandra#endif 484178172Simp/* tf->sr |= (ALL_INT_MASK & idle_mask) | SR_INT_ENAB; */ 485178172Simp /**XXX the above may now be wrong -- mips2 implements this as panic */ 486178172Simp /* 487178172Simp * FREEBSD_DEVELOPERS_FIXME: 488178172Simp * Setup any other CPU-Specific registers (Not MIPS Standard) 489178172Simp * that are needed. 490178172Simp */ 491178172Simp} 492178172Simp 493178172Simp/* 494178172Simp * Implement the pre-zeroed page mechanism. 495178172Simp * This routine is called from the idle loop. 496178172Simp */ 497178172Simp 498178172Simp#define ZIDLE_LO(v) ((v) * 2 / 3) 499178172Simp#define ZIDLE_HI(v) ((v) * 4 / 5) 500178172Simp 501178172Simp/* 502178172Simp * Allocate a pool of sf_bufs (sendfile(2) or "super-fast" if you prefer. :-)) 503178172Simp */ 504217944Sjchandra#ifndef __mips_n64 505178172Simpstatic void 506178172Simpsf_buf_init(void *arg) 507178172Simp{ 508178172Simp struct sf_buf *sf_bufs; 509178172Simp vm_offset_t sf_base; 510178172Simp int i; 511178172Simp 512178172Simp nsfbufs = NSFBUFS; 513178172Simp TUNABLE_INT_FETCH("kern.ipc.nsfbufs", &nsfbufs); 514178172Simp 515206714Sjmallett mtx_init(&sf_freelist.sf_lock, "sf_bufs list lock", NULL, MTX_DEF); 516206714Sjmallett SLIST_INIT(&sf_freelist.sf_head); 517254025Sjeff sf_base = kva_alloc(nsfbufs * PAGE_SIZE); 518178172Simp sf_bufs = malloc(nsfbufs * sizeof(struct sf_buf), M_TEMP, 519178172Simp M_NOWAIT | M_ZERO); 520178172Simp for (i = 0; i < nsfbufs; i++) { 521178172Simp sf_bufs[i].kva = sf_base + i * PAGE_SIZE; 522206714Sjmallett SLIST_INSERT_HEAD(&sf_freelist.sf_head, &sf_bufs[i], free_list); 523178172Simp } 524178172Simp sf_buf_alloc_want = 0; 525178172Simp} 526217944Sjchandra#endif 527178172Simp 528178172Simp/* 529206714Sjmallett * Get an sf_buf from the freelist. Will block if none are available. 530178172Simp */ 531178172Simpstruct sf_buf * 532178172Simpsf_buf_alloc(struct vm_page *m, int flags) 533178172Simp{ 534217944Sjchandra#ifndef __mips_n64 535178172Simp struct sf_buf *sf; 536178172Simp int error; 537178172Simp 538206714Sjmallett mtx_lock(&sf_freelist.sf_lock); 539206714Sjmallett while ((sf = SLIST_FIRST(&sf_freelist.sf_head)) == NULL) { 540178172Simp if (flags & SFB_NOWAIT) 541206714Sjmallett break; 542178172Simp sf_buf_alloc_want++; 543253351Sae SFSTAT_INC(sf_allocwait); 544206714Sjmallett error = msleep(&sf_freelist, &sf_freelist.sf_lock, 545178172Simp (flags & SFB_CATCH) ? PCATCH | PVM : PVM, "sfbufa", 0); 546178172Simp sf_buf_alloc_want--; 547178172Simp 548178172Simp /* 549178172Simp * If we got a signal, don't risk going back to sleep. 550178172Simp */ 551178172Simp if (error) 552206714Sjmallett break; 553178172Simp } 554206714Sjmallett if (sf != NULL) { 555206714Sjmallett SLIST_REMOVE_HEAD(&sf_freelist.sf_head, free_list); 556206714Sjmallett sf->m = m; 557206714Sjmallett nsfbufsused++; 558206714Sjmallett nsfbufspeak = imax(nsfbufspeak, nsfbufsused); 559206714Sjmallett pmap_qenter(sf->kva, &sf->m, 1); 560206714Sjmallett } 561206714Sjmallett mtx_unlock(&sf_freelist.sf_lock); 562178172Simp return (sf); 563217944Sjchandra#else 564217944Sjchandra return ((struct sf_buf *)m); 565217944Sjchandra#endif 566178172Simp} 567178172Simp 568178172Simp/* 569206714Sjmallett * Release resources back to the system. 570178172Simp */ 571178172Simpvoid 572178172Simpsf_buf_free(struct sf_buf *sf) 573178172Simp{ 574217944Sjchandra#ifndef __mips_n64 575206714Sjmallett pmap_qremove(sf->kva, 1); 576206714Sjmallett mtx_lock(&sf_freelist.sf_lock); 577206714Sjmallett SLIST_INSERT_HEAD(&sf_freelist.sf_head, sf, free_list); 578206714Sjmallett nsfbufsused--; 579206714Sjmallett if (sf_buf_alloc_want > 0) 580217561Skib wakeup(&sf_freelist); 581206714Sjmallett mtx_unlock(&sf_freelist.sf_lock); 582217944Sjchandra#endif 583178172Simp} 584178172Simp 585178172Simp/* 586178172Simp * Software interrupt handler for queued VM system processing. 587178172Simp */ 588178172Simpvoid 589178172Simpswi_vm(void *dummy) 590178172Simp{ 591216317Sjchandra 592216317Sjchandra if (busdma_swi_pending) 593216317Sjchandra busdma_swi(); 594178172Simp} 595178172Simp 596178172Simpint 597178172Simpcpu_set_user_tls(struct thread *td, void *tls_base) 598178172Simp{ 599178172Simp 600232577Sgonzo td->td_md.md_tls = (char*)tls_base; 601232449Sjmallett 602232478Sjmallett return (0); 603178172Simp} 604178172Simp 605202046Simp#ifdef DDB 606202046Simp#include <ddb/ddb.h> 607202046Simp 608202046Simp#define DB_PRINT_REG(ptr, regname) \ 609209500Sjchandra db_printf(" %-12s %p\n", #regname, (void *)(intptr_t)((ptr)->regname)) 610202046Simp 611202046Simp#define DB_PRINT_REG_ARRAY(ptr, arrname, regname) \ 612209500Sjchandra db_printf(" %-12s %p\n", #regname, (void *)(intptr_t)((ptr)->arrname[regname])) 613202046Simp 614202999Sneelstatic void 615202999Sneeldump_trapframe(struct trapframe *trapframe) 616202046Simp{ 617202046Simp 618202999Sneel db_printf("Trapframe at %p\n", trapframe); 619202046Simp 620202046Simp DB_PRINT_REG(trapframe, zero); 621202046Simp DB_PRINT_REG(trapframe, ast); 622202046Simp DB_PRINT_REG(trapframe, v0); 623202046Simp DB_PRINT_REG(trapframe, v1); 624202046Simp DB_PRINT_REG(trapframe, a0); 625202046Simp DB_PRINT_REG(trapframe, a1); 626202046Simp DB_PRINT_REG(trapframe, a2); 627202046Simp DB_PRINT_REG(trapframe, a3); 628249790Simp#if defined(__mips_n32) || defined(__mips_n64) 629249790Simp DB_PRINT_REG(trapframe, a4); 630249790Simp DB_PRINT_REG(trapframe, a5); 631249790Simp DB_PRINT_REG(trapframe, a6); 632249790Simp DB_PRINT_REG(trapframe, a7); 633202046Simp DB_PRINT_REG(trapframe, t0); 634202046Simp DB_PRINT_REG(trapframe, t1); 635202046Simp DB_PRINT_REG(trapframe, t2); 636202046Simp DB_PRINT_REG(trapframe, t3); 637249790Simp#else 638249790Simp DB_PRINT_REG(trapframe, t0); 639249790Simp DB_PRINT_REG(trapframe, t1); 640249790Simp DB_PRINT_REG(trapframe, t2); 641249790Simp DB_PRINT_REG(trapframe, t3); 642202046Simp DB_PRINT_REG(trapframe, t4); 643202046Simp DB_PRINT_REG(trapframe, t5); 644202046Simp DB_PRINT_REG(trapframe, t6); 645202046Simp DB_PRINT_REG(trapframe, t7); 646249790Simp#endif 647202046Simp DB_PRINT_REG(trapframe, s0); 648202046Simp DB_PRINT_REG(trapframe, s1); 649202046Simp DB_PRINT_REG(trapframe, s2); 650202046Simp DB_PRINT_REG(trapframe, s3); 651202046Simp DB_PRINT_REG(trapframe, s4); 652202046Simp DB_PRINT_REG(trapframe, s5); 653202046Simp DB_PRINT_REG(trapframe, s6); 654202046Simp DB_PRINT_REG(trapframe, s7); 655202046Simp DB_PRINT_REG(trapframe, t8); 656202046Simp DB_PRINT_REG(trapframe, t9); 657202046Simp DB_PRINT_REG(trapframe, k0); 658202046Simp DB_PRINT_REG(trapframe, k1); 659202046Simp DB_PRINT_REG(trapframe, gp); 660202046Simp DB_PRINT_REG(trapframe, sp); 661202046Simp DB_PRINT_REG(trapframe, s8); 662202046Simp DB_PRINT_REG(trapframe, ra); 663202046Simp DB_PRINT_REG(trapframe, sr); 664202046Simp DB_PRINT_REG(trapframe, mullo); 665202046Simp DB_PRINT_REG(trapframe, mulhi); 666202046Simp DB_PRINT_REG(trapframe, badvaddr); 667202046Simp DB_PRINT_REG(trapframe, cause); 668202046Simp DB_PRINT_REG(trapframe, pc); 669202999Sneel} 670202046Simp 671202999SneelDB_SHOW_COMMAND(pcb, ddb_dump_pcb) 672202999Sneel{ 673202999Sneel struct thread *td; 674202999Sneel struct pcb *pcb; 675202999Sneel struct trapframe *trapframe; 676202999Sneel 677202999Sneel /* Determine which thread to examine. */ 678202999Sneel if (have_addr) 679202999Sneel td = db_lookup_thread(addr, TRUE); 680202999Sneel else 681202999Sneel td = curthread; 682202999Sneel 683202999Sneel pcb = td->td_pcb; 684202999Sneel 685202999Sneel db_printf("Thread %d at %p\n", td->td_tid, td); 686202999Sneel 687202999Sneel db_printf("PCB at %p\n", pcb); 688202999Sneel 689202999Sneel trapframe = &pcb->pcb_regs; 690202999Sneel dump_trapframe(trapframe); 691202999Sneel 692202046Simp db_printf("PCB Context:\n"); 693202046Simp DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_S0); 694202046Simp DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_S1); 695202046Simp DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_S2); 696202046Simp DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_S3); 697202046Simp DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_S4); 698202046Simp DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_S5); 699202046Simp DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_S6); 700202046Simp DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_S7); 701202046Simp DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_SP); 702202046Simp DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_S8); 703202046Simp DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_RA); 704202046Simp DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_SR); 705202046Simp DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_GP); 706202046Simp DB_PRINT_REG_ARRAY(pcb, pcb_context, PCB_REG_PC); 707202046Simp 708206749Sjmallett db_printf("PCB onfault = %p\n", pcb->pcb_onfault); 709202046Simp db_printf("md_saved_intr = 0x%0lx\n", (long)td->td_md.md_saved_intr); 710202046Simp db_printf("md_spinlock_count = %d\n", td->td_md.md_spinlock_count); 711202046Simp 712202046Simp if (td->td_frame != trapframe) { 713202046Simp db_printf("td->td_frame %p is not the same as pcb_regs %p\n", 714202046Simp td->td_frame, trapframe); 715202046Simp } 716202046Simp} 717202046Simp 718202999Sneel/* 719202999Sneel * Dump the trapframe beginning at address specified by first argument. 720202999Sneel */ 721202999SneelDB_SHOW_COMMAND(trapframe, ddb_dump_trapframe) 722202999Sneel{ 723202999Sneel 724202999Sneel if (!have_addr) 725202999Sneel return; 726202999Sneel 727202999Sneel dump_trapframe((struct trapframe *)addr); 728202999Sneel} 729202999Sneel 730202046Simp#endif /* DDB */ 731