vm_machdep.c revision 135657
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 135657 2004-09-23 22:24:12Z 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; 148135657Scognet vm_offset_t uarea = td2->td_kstack + td2->td_kstack_pages * PAGE_SIZE 149135657Scognet - USPACE; 150129198Scognet 151129198Scognet pcb1 = td1->td_pcb; 152129198Scognet pcb2 = (struct pcb *)(td2->td_kstack + td2->td_kstack_pages * PAGE_SIZE) - 1; 153135657Scognet#ifdef __XSCALE__ 154135657Scognet pmap_use_minicache(td2->td_kstack, td2->td_kstack_pages * PAGE_SIZE); 155135657Scognet#endif 156129198Scognet td2->td_pcb = pcb2; 157129198Scognet bcopy(td1->td_pcb, pcb2, sizeof(*pcb2)); 158129198Scognet mdp2 = &p2->p_md; 159129198Scognet bcopy(&td1->td_proc->p_md, mdp2, sizeof(*mdp2)); 160135657Scognet pcb2->un_32.pcb32_und_sp = uarea + USPACE_UNDEF_STACK_TOP; 161135657Scognet pcb2->un_32.pcb32_sp = uarea + 162135657Scognet USPACE_SVC_STACK_TOP - sizeof(*pcb2); 163129198Scognet pmap_activate(td2); 164129198Scognet td2->td_frame = tf = 165129198Scognet (struct trapframe *)pcb2->un_32.pcb32_sp - 1; 166129198Scognet *tf = *td1->td_frame; 167129198Scognet sf = (struct switchframe *)tf - 1; 168129198Scognet sf->sf_r4 = (u_int)fork_return; 169129198Scognet sf->sf_r5 = (u_int)td2; 170129198Scognet sf->sf_pc = (u_int)fork_trampoline; 171129198Scognet tf->tf_spsr &= ~PSR_C_bit; 172129198Scognet tf->tf_r0 = 0; 173135657Scognet tf->tf_r1 = 0; 174129198Scognet pcb2->un_32.pcb32_sp = (u_int)sf; 175129198Scognet} 176129198Scognet 177129198Scognetvoid 178129198Scognetcpu_thread_swapin(struct thread *td) 179129198Scognet{ 180129198Scognet} 181129198Scognet 182129198Scognetvoid 183129198Scognetcpu_thread_swapout(struct thread *td) 184129198Scognet{ 185129198Scognet} 186129198Scognet 187129198Scognet/* 188129198Scognet * Detatch mapped page and release resources back to the system. 189129198Scognet */ 190129198Scognetvoid 191129198Scognetsf_buf_free(struct sf_buf *sf) 192129198Scognet{ 193129198Scognet mtx_lock(&sf_buf_lock); 194129198Scognet sf->ref_count--; 195129198Scognet if (sf->ref_count == 0) { 196129198Scognet TAILQ_INSERT_TAIL(&sf_buf_freelist, sf, free_entry); 197129198Scognet nsfbufsused--; 198129198Scognet if (sf_buf_alloc_want > 0) 199129198Scognet wakeup_one(&sf_buf_freelist); 200129198Scognet } 201129198Scognet mtx_unlock(&sf_buf_lock); 202129198Scognet} 203129198Scognet 204129198Scognet/* 205129198Scognet * * Allocate a pool of sf_bufs (sendfile(2) or "super-fast" if you prefer. :-)) 206129198Scognet * */ 207129198Scognetstatic void 208129198Scognetsf_buf_init(void *arg) 209129198Scognet{ 210129198Scognet struct sf_buf *sf_bufs; 211129198Scognet vm_offset_t sf_base; 212129198Scognet int i; 213129198Scognet 214131837Scognet nsfbufs = NSFBUFS; 215131837Scognet TUNABLE_INT_FETCH("kern.ipc.nsfbufs", &nsfbufs); 216131837Scognet 217129198Scognet sf_buf_active = hashinit(nsfbufs, M_TEMP, &sf_buf_hashmask); 218129198Scognet TAILQ_INIT(&sf_buf_freelist); 219129198Scognet sf_base = kmem_alloc_nofault(kernel_map, nsfbufs * PAGE_SIZE); 220129198Scognet sf_bufs = malloc(nsfbufs * sizeof(struct sf_buf), M_TEMP, 221129198Scognet M_NOWAIT | M_ZERO); 222129198Scognet for (i = 0; i < nsfbufs; i++) { 223129198Scognet sf_bufs[i].kva = sf_base + i * PAGE_SIZE; 224129198Scognet TAILQ_INSERT_TAIL(&sf_buf_freelist, &sf_bufs[i], free_entry); 225129198Scognet } 226129198Scognet sf_buf_alloc_want = 0; 227129198Scognet mtx_init(&sf_buf_lock, "sf_buf", NULL, MTX_DEF); 228129198Scognet} 229129198Scognet 230129198Scognet/* 231129198Scognet * Get an sf_buf from the freelist. Will block if none are available. 232129198Scognet */ 233129198Scognetstruct sf_buf * 234129198Scognetsf_buf_alloc(struct vm_page *m, int pri) 235129198Scognet{ 236129198Scognet struct sf_head *hash_list; 237129198Scognet struct sf_buf *sf; 238129198Scognet int error; 239129198Scognet 240129198Scognet hash_list = &sf_buf_active[SF_BUF_HASH(m)]; 241129198Scognet mtx_lock(&sf_buf_lock); 242129198Scognet LIST_FOREACH(sf, hash_list, list_entry) { 243129198Scognet if (sf->m == m) { 244129198Scognet sf->ref_count++; 245129198Scognet if (sf->ref_count == 1) { 246129198Scognet TAILQ_REMOVE(&sf_buf_freelist, sf, free_entry); 247129198Scognet nsfbufsused++; 248129198Scognet nsfbufspeak = imax(nsfbufspeak, nsfbufsused); 249129198Scognet } 250129198Scognet goto done; 251129198Scognet } 252129198Scognet } 253129198Scognet while ((sf = TAILQ_FIRST(&sf_buf_freelist)) == NULL) { 254129198Scognet sf_buf_alloc_want++; 255129198Scognet mbstat.sf_allocwait++; 256129198Scognet error = msleep(&sf_buf_freelist, &sf_buf_lock, PVM | pri, 257129198Scognet "sfbufa", 0); 258129198Scognet sf_buf_alloc_want--; 259129198Scognet 260129198Scognet 261129198Scognet /* 262129198Scognet * If we got a signal, don't risk going back to sleep. 263129198Scognet */ 264129198Scognet if (error) 265129198Scognet goto done; 266129198Scognet } 267129198Scognet TAILQ_REMOVE(&sf_buf_freelist, sf, free_entry); 268129198Scognet if (sf->m != NULL) 269129198Scognet LIST_REMOVE(sf, list_entry); 270129198Scognet LIST_INSERT_HEAD(hash_list, sf, list_entry); 271129198Scognet sf->ref_count = 1; 272129198Scognet sf->m = m; 273129198Scognet nsfbufsused++; 274129198Scognet nsfbufspeak = imax(nsfbufspeak, nsfbufsused); 275129198Scognet pmap_qenter(sf->kva, &sf->m, 1); 276129198Scognetdone: 277129198Scognet mtx_unlock(&sf_buf_lock); 278129198Scognet return (sf); 279129198Scognet 280129198Scognet} 281129198Scognet 282129198Scognet/* 283129198Scognet * Initialize machine state (pcb and trap frame) for a new thread about to 284129198Scognet * upcall. Put enough state in the new thread's PCB to get it to go back 285129198Scognet * userret(), where we can intercept it again to set the return (upcall) 286129198Scognet * Address and stack, along with those from upcals that are from other sources 287129198Scognet * such as those generated in thread_userret() itself. 288129198Scognet */ 289129198Scognetvoid 290129198Scognetcpu_set_upcall(struct thread *td, struct thread *td0) 291129198Scognet{ 292129198Scognet panic("set upcall\n"); 293129198Scognet} 294129198Scognet 295129198Scognet/* 296129198Scognet * Set that machine state for performing an upcall that has to 297129198Scognet * be done in thread_userret() so that those upcalls generated 298129198Scognet * in thread_userret() itself can be done as well. 299129198Scognet */ 300129198Scognetvoid 301129198Scognetcpu_set_upcall_kse(struct thread *td, struct kse_upcall *ku) 302129198Scognet{ 303129198Scognet panic("setupcallkse\n"); 304129198Scognet} 305129198Scognet 306129198Scognetvoid 307129198Scognetcpu_thread_exit(struct thread *td) 308129198Scognet{ 309129198Scognet} 310129198Scognet 311129198Scognetvoid 312129198Scognetcpu_thread_setup(struct thread *td) 313129198Scognet{ 314129198Scognet td->td_pcb = (struct pcb *)(td->td_kstack + KSTACK_PAGES * 315129198Scognet PAGE_SIZE) - 1; 316129198Scognet td->td_frame = (struct trapframe *) 317129198Scognet ((u_int)td->td_kstack + USPACE_SVC_STACK_TOP) - 1; 318129198Scognet} 319129198Scognetvoid 320129198Scognetcpu_thread_clean(struct thread *td) 321129198Scognet{ 322129198Scognet} 323129198Scognet 324129198Scognet/* 325129198Scognet * Intercept the return address from a freshly forked process that has NOT 326129198Scognet * been scheduled yet. 327129198Scognet * 328129198Scognet * This is needed to make kernel threads stay in kernel mode. 329129198Scognet */ 330129198Scognetvoid 331129198Scognetcpu_set_fork_handler(struct thread *td, void (*func)(void *), void *arg) 332129198Scognet{ 333129198Scognet struct switchframe *sf; 334129198Scognet struct trapframe *tf; 335129198Scognet 336129198Scognet tf = td->td_frame; 337129198Scognet sf = (struct switchframe *)tf - 1; 338129198Scognet sf->sf_r4 = (u_int)func; 339129198Scognet sf->sf_r5 = (u_int)arg; 340129198Scognet td->td_pcb->un_32.pcb32_sp = (u_int)sf; 341129198Scognet} 342129198Scognet 343129198Scognet/* 344129198Scognet * Software interrupt handler for queued VM system processing. 345129198Scognet */ 346129198Scognetvoid 347129198Scognetswi_vm(void *dummy) 348129198Scognet{ 349129198Scognet} 350129198Scognet 351129198Scognetvoid 352129198Scognetcpu_exit(struct thread *td) 353129198Scognet{ 354129198Scognet} 355