vm_machdep.c revision 131837
1129198Scognet/*- 2129198Scognet * Copyright (c) 1982, 1986 The Regents of the University of California. 3129198Scognet * Copyright (c) 1989, 1990 William Jolitz 4129198Scognet * Copyright (c) 1994 John Dyson 5129198Scognet * All rights reserved. 6129198Scognet * 7129198Scognet * This code is derived from software contributed to Berkeley by 8129198Scognet * the Systems Programming Group of the University of Utah Computer 9129198Scognet * Science Department, and William Jolitz. 10129198Scognet * 11129198Scognet * Redistribution and use in source and binary forms, with or without 12129198Scognet * modification, are permitted provided that the following conditions 13129198Scognet * are met: 14129198Scognet * 1. Redistributions of source code must retain the above copyright 15129198Scognet * notice, this list of conditions and the following disclaimer. 16129198Scognet * 2. Redistributions in binary form must reproduce the above copyright 17129198Scognet * notice, this list of conditions and the following disclaimer in the 18129198Scognet * documentation and/or other materials provided with the distribution. 19129198Scognet * 3. All advertising materials mentioning features or use of this software 20129198Scognet * must display the following acknowledgement: 21129198Scognet * This product includes software developed by the University of 22129198Scognet * California, Berkeley and its contributors. 23129198Scognet * 4. Neither the name of the University nor the names of its contributors 24129198Scognet * may be used to endorse or promote products derived from this software 25129198Scognet * without specific prior written permission. 26129198Scognet * 27129198Scognet * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28129198Scognet * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29129198Scognet * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30129198Scognet * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31129198Scognet * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32129198Scognet * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33129198Scognet * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34129198Scognet * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35129198Scognet * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36129198Scognet * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37129198Scognet * SUCH DAMAGE. 38129198Scognet * 39129198Scognet * from: @(#)vm_machdep.c 7.3 (Berkeley) 5/13/91 40129198Scognet * Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$ 41129198Scognet *//*- 42129198Scognet * Copyright (c) 1982, 1986 The Regents of the University of California. 43129198Scognet * Copyright (c) 1989, 1990 William Jolitz 44129198Scognet * Copyright (c) 1994 John Dyson 45129198Scognet * All rights reserved. 46129198Scognet * 47129198Scognet * This code is derived from software contributed to Berkeley by 48129198Scognet * the Systems Programming Group of the University of Utah Computer 49129198Scognet * Science Department, and William Jolitz. 50129198Scognet * 51129198Scognet * Redistribution and use in source and binary forms, with or without 52129198Scognet * modification, are permitted provided that the following conditions 53129198Scognet * are met: 54129198Scognet * 1. Redistributions of source code must retain the above copyright 55129198Scognet * notice, this list of conditions and the following disclaimer. 56129198Scognet * 2. Redistributions in binary form must reproduce the above copyright 57129198Scognet * notice, this list of conditions and the following disclaimer in the 58129198Scognet * documentation and/or other materials provided with the distribution. 59129198Scognet * 3. All advertising materials mentioning features or use of this software 60129198Scognet * must display the following acknowledgement: 61129198Scognet * This product includes software developed by the University of 62129198Scognet * California, Berkeley and its contributors. 63129198Scognet * 4. Neither the name of the University nor the names of its contributors 64129198Scognet * may be used to endorse or promote products derived from this software 65129198Scognet * without specific prior written permission. 66129198Scognet * 67129198Scognet * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 68129198Scognet * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 69129198Scognet * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 70129198Scognet * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 71129198Scognet * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 72129198Scognet * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 73129198Scognet * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 74129198Scognet * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 75129198Scognet * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 76129198Scognet * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 77129198Scognet * SUCH DAMAGE. 78129198Scognet * 79129198Scognet * from: @(#)vm_machdep.c 7.3 (Berkeley) 5/13/91 80129198Scognet * Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$ 81129198Scognet */ 82129198Scognet 83129198Scognet#include <sys/cdefs.h> 84129198Scognet__FBSDID("$FreeBSD: head/sys/arm/arm/vm_machdep.c 131837 2004-07-08 21:03:35Z cognet $"); 85129198Scognet 86129198Scognet#include <sys/param.h> 87129198Scognet#include <sys/systm.h> 88129198Scognet#include <sys/kernel.h> 89129198Scognet#include <sys/malloc.h> 90129198Scognet#include <sys/mbuf.h> 91129198Scognet#include <sys/proc.h> 92129198Scognet#include <sys/socketvar.h> 93129198Scognet#include <sys/sf_buf.h> 94129198Scognet#include <sys/user.h> 95129198Scognet#include <machine/cpu.h> 96129198Scognet#include <machine/pcb.h> 97129198Scognet#include <vm/vm.h> 98129198Scognet#include <vm/pmap.h> 99129198Scognet#include <sys/lock.h> 100129198Scognet#include <sys/mutex.h> 101129198Scognet 102129198Scognet#include <vm/vm.h> 103129198Scognet#include <vm/vm_extern.h> 104129198Scognet#include <vm/vm_kern.h> 105129198Scognet#include <vm/vm_page.h> 106129198Scognet#include <vm/vm_map.h> 107129198Scognet#include <vm/vm_param.h> 108129198Scognet 109131837Scognet#ifndef NSFBUFS 110131837Scognet#define NSFBUFS (512 + maxusers * 16) 111131837Scognet#endif 112131837Scognet 113129198Scognetstatic void sf_buf_init(void *arg); 114129198ScognetSYSINIT(sock_sf, SI_SUB_MBUF, SI_ORDER_ANY, sf_buf_init, NULL) 115129198Scognet 116129198ScognetLIST_HEAD(sf_head, sf_buf); 117129198Scognet 118129198Scognet 119129198Scognet/* 120129198Scognet * A hash table of active sendfile(2) buffers 121129198Scognet */ 122129198Scognetstatic struct sf_head *sf_buf_active; 123129198Scognetstatic u_long sf_buf_hashmask; 124129198Scognet 125129198Scognet#define SF_BUF_HASH(m) (((m) - vm_page_array) & sf_buf_hashmask) 126129198Scognet 127129198Scognetstatic TAILQ_HEAD(, sf_buf) sf_buf_freelist; 128129198Scognetstatic u_int sf_buf_alloc_want; 129129198Scognet 130129198Scognet/* 131129198Scognet * A lock used to synchronize access to the hash table and free list 132129198Scognet */ 133129198Scognetstatic struct mtx sf_buf_lock; 134129198Scognet 135129198Scognet/* 136129198Scognet * Finish a fork operation, with process p2 nearly set up. 137129198Scognet * Copy and update the pcb, set up the stack so that the child 138129198Scognet * ready to run and return to user mode. 139129198Scognet */ 140129198Scognetvoid 141129198Scognetcpu_fork(register struct thread *td1, register struct proc *p2, 142129198Scognet struct thread *td2, int flags) 143129198Scognet{ 144129198Scognet struct pcb *pcb1, *pcb2; 145129198Scognet struct trapframe *tf; 146129198Scognet struct switchframe *sf; 147129198Scognet struct mdproc *mdp2; 148129198Scognet 149129198Scognet pcb1 = td1->td_pcb; 150129198Scognet pcb2 = (struct pcb *)(td2->td_kstack + td2->td_kstack_pages * PAGE_SIZE) - 1; 151129198Scognet td2->td_pcb = pcb2; 152129198Scognet bcopy(td1->td_pcb, pcb2, sizeof(*pcb2)); 153129198Scognet mdp2 = &p2->p_md; 154129198Scognet bcopy(&td1->td_proc->p_md, mdp2, sizeof(*mdp2)); 155129198Scognet pcb2->un_32.pcb32_und_sp = (u_int)td2->td_kstack + USPACE_UNDEF_STACK_TOP; 156129198Scognet pcb2->un_32.pcb32_sp = (u_int)td2->td_kstack + 157129198Scognet USPACE_SVC_STACK_TOP; 158129198Scognet pmap_activate(td2); 159129198Scognet td2->td_frame = tf = 160129198Scognet (struct trapframe *)pcb2->un_32.pcb32_sp - 1; 161129198Scognet *tf = *td1->td_frame; 162129198Scognet sf = (struct switchframe *)tf - 1; 163129198Scognet sf->sf_r4 = (u_int)fork_return; 164129198Scognet sf->sf_r5 = (u_int)td2; 165129198Scognet sf->sf_pc = (u_int)fork_trampoline; 166129198Scognet tf->tf_spsr &= ~PSR_C_bit; 167129198Scognet tf->tf_r0 = 0; 168129198Scognet pcb2->un_32.pcb32_sp = (u_int)sf; 169129198Scognet} 170129198Scognet 171129198Scognetvoid 172129198Scognetcpu_thread_swapin(struct thread *td) 173129198Scognet{ 174129198Scognet} 175129198Scognet 176129198Scognetvoid 177129198Scognetcpu_thread_swapout(struct thread *td) 178129198Scognet{ 179129198Scognet} 180129198Scognet 181129198Scognet/* 182129198Scognet * Detatch mapped page and release resources back to the system. 183129198Scognet */ 184129198Scognetvoid 185129198Scognetsf_buf_free(struct sf_buf *sf) 186129198Scognet{ 187129198Scognet mtx_lock(&sf_buf_lock); 188129198Scognet sf->ref_count--; 189129198Scognet if (sf->ref_count == 0) { 190129198Scognet TAILQ_INSERT_TAIL(&sf_buf_freelist, sf, free_entry); 191129198Scognet nsfbufsused--; 192129198Scognet if (sf_buf_alloc_want > 0) 193129198Scognet wakeup_one(&sf_buf_freelist); 194129198Scognet } 195129198Scognet mtx_unlock(&sf_buf_lock); 196129198Scognet} 197129198Scognet 198129198Scognet/* 199129198Scognet * * Allocate a pool of sf_bufs (sendfile(2) or "super-fast" if you prefer. :-)) 200129198Scognet * */ 201129198Scognetstatic void 202129198Scognetsf_buf_init(void *arg) 203129198Scognet{ 204129198Scognet struct sf_buf *sf_bufs; 205129198Scognet vm_offset_t sf_base; 206129198Scognet int i; 207129198Scognet 208131837Scognet nsfbufs = NSFBUFS; 209131837Scognet TUNABLE_INT_FETCH("kern.ipc.nsfbufs", &nsfbufs); 210131837Scognet 211129198Scognet sf_buf_active = hashinit(nsfbufs, M_TEMP, &sf_buf_hashmask); 212129198Scognet TAILQ_INIT(&sf_buf_freelist); 213129198Scognet sf_base = kmem_alloc_nofault(kernel_map, nsfbufs * PAGE_SIZE); 214129198Scognet sf_bufs = malloc(nsfbufs * sizeof(struct sf_buf), M_TEMP, 215129198Scognet M_NOWAIT | M_ZERO); 216129198Scognet for (i = 0; i < nsfbufs; i++) { 217129198Scognet sf_bufs[i].kva = sf_base + i * PAGE_SIZE; 218129198Scognet TAILQ_INSERT_TAIL(&sf_buf_freelist, &sf_bufs[i], free_entry); 219129198Scognet } 220129198Scognet sf_buf_alloc_want = 0; 221129198Scognet mtx_init(&sf_buf_lock, "sf_buf", NULL, MTX_DEF); 222129198Scognet} 223129198Scognet 224129198Scognet/* 225129198Scognet * Get an sf_buf from the freelist. Will block if none are available. 226129198Scognet */ 227129198Scognetstruct sf_buf * 228129198Scognetsf_buf_alloc(struct vm_page *m, int pri) 229129198Scognet{ 230129198Scognet struct sf_head *hash_list; 231129198Scognet struct sf_buf *sf; 232129198Scognet int error; 233129198Scognet 234129198Scognet hash_list = &sf_buf_active[SF_BUF_HASH(m)]; 235129198Scognet mtx_lock(&sf_buf_lock); 236129198Scognet LIST_FOREACH(sf, hash_list, list_entry) { 237129198Scognet if (sf->m == m) { 238129198Scognet sf->ref_count++; 239129198Scognet if (sf->ref_count == 1) { 240129198Scognet TAILQ_REMOVE(&sf_buf_freelist, sf, free_entry); 241129198Scognet nsfbufsused++; 242129198Scognet nsfbufspeak = imax(nsfbufspeak, nsfbufsused); 243129198Scognet } 244129198Scognet goto done; 245129198Scognet } 246129198Scognet } 247129198Scognet while ((sf = TAILQ_FIRST(&sf_buf_freelist)) == NULL) { 248129198Scognet sf_buf_alloc_want++; 249129198Scognet mbstat.sf_allocwait++; 250129198Scognet error = msleep(&sf_buf_freelist, &sf_buf_lock, PVM | pri, 251129198Scognet "sfbufa", 0); 252129198Scognet sf_buf_alloc_want--; 253129198Scognet 254129198Scognet 255129198Scognet /* 256129198Scognet * If we got a signal, don't risk going back to sleep. 257129198Scognet */ 258129198Scognet if (error) 259129198Scognet goto done; 260129198Scognet } 261129198Scognet TAILQ_REMOVE(&sf_buf_freelist, sf, free_entry); 262129198Scognet if (sf->m != NULL) 263129198Scognet LIST_REMOVE(sf, list_entry); 264129198Scognet LIST_INSERT_HEAD(hash_list, sf, list_entry); 265129198Scognet sf->ref_count = 1; 266129198Scognet sf->m = m; 267129198Scognet nsfbufsused++; 268129198Scognet nsfbufspeak = imax(nsfbufspeak, nsfbufsused); 269129198Scognet pmap_qenter(sf->kva, &sf->m, 1); 270129198Scognetdone: 271129198Scognet mtx_unlock(&sf_buf_lock); 272129198Scognet return (sf); 273129198Scognet 274129198Scognet} 275129198Scognet 276129198Scognet/* 277129198Scognet * Initialize machine state (pcb and trap frame) for a new thread about to 278129198Scognet * upcall. Put enough state in the new thread's PCB to get it to go back 279129198Scognet * userret(), where we can intercept it again to set the return (upcall) 280129198Scognet * Address and stack, along with those from upcals that are from other sources 281129198Scognet * such as those generated in thread_userret() itself. 282129198Scognet */ 283129198Scognetvoid 284129198Scognetcpu_set_upcall(struct thread *td, struct thread *td0) 285129198Scognet{ 286129198Scognet panic("set upcall\n"); 287129198Scognet} 288129198Scognet 289129198Scognet/* 290129198Scognet * Set that machine state for performing an upcall that has to 291129198Scognet * be done in thread_userret() so that those upcalls generated 292129198Scognet * in thread_userret() itself can be done as well. 293129198Scognet */ 294129198Scognetvoid 295129198Scognetcpu_set_upcall_kse(struct thread *td, struct kse_upcall *ku) 296129198Scognet{ 297129198Scognet panic("setupcallkse\n"); 298129198Scognet} 299129198Scognet 300129198Scognetvoid 301129198Scognetcpu_thread_exit(struct thread *td) 302129198Scognet{ 303129198Scognet} 304129198Scognet 305129198Scognetvoid 306129198Scognetcpu_thread_setup(struct thread *td) 307129198Scognet{ 308129198Scognet td->td_pcb = (struct pcb *)(td->td_kstack + KSTACK_PAGES * 309129198Scognet PAGE_SIZE) - 1; 310129198Scognet td->td_frame = (struct trapframe *) 311129198Scognet ((u_int)td->td_kstack + USPACE_SVC_STACK_TOP) - 1; 312129198Scognet} 313129198Scognetvoid 314129198Scognetcpu_thread_clean(struct thread *td) 315129198Scognet{ 316129198Scognet} 317129198Scognet 318129198Scognet/* 319129198Scognet * Intercept the return address from a freshly forked process that has NOT 320129198Scognet * been scheduled yet. 321129198Scognet * 322129198Scognet * This is needed to make kernel threads stay in kernel mode. 323129198Scognet */ 324129198Scognetvoid 325129198Scognetcpu_set_fork_handler(struct thread *td, void (*func)(void *), void *arg) 326129198Scognet{ 327129198Scognet struct switchframe *sf; 328129198Scognet struct trapframe *tf; 329129198Scognet 330129198Scognet 331129198Scognet tf = td->td_frame; 332129198Scognet sf = (struct switchframe *)tf - 1; 333129198Scognet sf->sf_r4 = (u_int)func; 334129198Scognet sf->sf_r5 = (u_int)arg; 335129198Scognet td->td_pcb->un_32.pcb32_sp = (u_int)sf; 336129198Scognet} 337129198Scognet 338129198Scognet/* 339129198Scognet * Software interrupt handler for queued VM system processing. 340129198Scognet */ 341129198Scognetvoid 342129198Scognetswi_vm(void *dummy) 343129198Scognet{ 344129198Scognet} 345129198Scognet 346129198Scognetvoid 347129198Scognetcpu_exit(struct thread *td) 348129198Scognet{ 349129198Scognet} 350