1/* $OpenBSD: vm_machdep.c,v 1.11 2023/04/11 00:45:08 jsg Exp $ */ 2 3/*- 4 * Copyright (c) 1995 Charles M. Hannum. All rights reserved. 5 * Copyright (c) 1982, 1986 The Regents of the University of California. 6 * Copyright (c) 1989, 1990 William Jolitz 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 * 3. 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 * @(#)vm_machdep.c 7.3 (Berkeley) 5/13/91 38 */ 39 40#include <sys/param.h> 41#include <sys/systm.h> 42#include <sys/proc.h> 43#include <sys/buf.h> 44#include <sys/user.h> 45 46#include <uvm/uvm_extern.h> 47 48#include <machine/cpu.h> 49 50/* 51 * Finish a fork operation, with process p2 nearly set up. 52 * Copy and update the kernel stack and pcb, making the child 53 * ready to run, and marking it so that it can return differently 54 * than the parent. Returns 1 in the child process, 0 in the parent. 55 */ 56void 57cpu_fork(struct proc *p1, struct proc *p2, void *stack, void *tcb, 58 void (*func)(void *), void *arg) 59{ 60 struct pcb *pcb = &p2->p_addr->u_pcb; 61 struct pcb *pcb1 = &p1->p_addr->u_pcb; 62 struct trapframe *tf; 63 struct switchframe *sf; 64 65 /* Ensure proper stack alignment. */ 66 CTASSERT((sizeof(struct trapframe) & STACKALIGNBYTES) == 0); 67 CTASSERT((sizeof(struct switchframe) & STACKALIGNBYTES) == 0); 68 69 /* Save FPU state to PCB if necessary. */ 70 if (pcb1->pcb_flags & PCB_FPU) 71 fpu_save(p1, pcb1->pcb_tf); 72 73 /* Copy the pcb. */ 74 *pcb = p1->p_addr->u_pcb; 75 76 pmap_activate(p2); 77 78 tf = (struct trapframe *)((u_long)p2->p_addr 79 + USPACE 80 - sizeof(struct trapframe) 81 - sizeof(register_t) /* for holding curcpu */ 82 - 0x10); 83 84 tf = (struct trapframe *)STACKALIGN(tf); 85 pcb->pcb_tf = tf; 86 *tf = *p1->p_addr->u_pcb.pcb_tf; 87 88 if (stack != NULL) 89 tf->tf_sp = STACKALIGN(stack); 90 if (tcb != NULL) 91 tf->tf_tp = (register_t)tcb; 92 93 /* Arguments for child */ 94 tf->tf_a[0] = 0; 95 tf->tf_a[1] = 0; 96 tf->tf_sstatus |= (SSTATUS_SPIE); /* Enable interrupts. */ 97 tf->tf_sstatus &= ~(SSTATUS_SPP); /* Enter user mode. */ 98 99 sf = (struct switchframe *)tf - 1; 100 sf->sf_s[0] = 0; /* Terminate chain of call frames. */ 101 sf->sf_s[1] = (uint64_t)func; 102 sf->sf_s[2] = (uint64_t)arg; 103 sf->sf_ra = (u_int64_t)&proc_trampoline; 104 pcb->pcb_sp = (uint64_t)sf; 105} 106 107/* 108 * cpu_exit is called as the last action during exit. 109 * 110 * We clean up a little and then call sched_exit() with the old proc as an 111 * argument. 112 */ 113void 114cpu_exit(struct proc *p) 115{ 116 pmap_deactivate(p); 117 sched_exit(p); 118} 119 120struct kmem_va_mode kv_physwait = { 121 .kv_map = &phys_map, 122 .kv_wait = 1, 123}; 124 125/* 126 * Map a user I/O request into kernel virtual address space. 127 * Note: the pages are already locked by uvm_vslock(), so we 128 * do not need to pass an access_type to pmap_enter(). 129 */ 130void 131vmapbuf(struct buf *bp, vsize_t len) 132{ 133 vaddr_t faddr, taddr, off; 134 paddr_t fpa; 135 136 if ((bp->b_flags & B_PHYS) == 0) 137 panic("vmapbuf"); 138 faddr = trunc_page((vaddr_t)(bp->b_saveaddr = bp->b_data)); 139 off = (vaddr_t)bp->b_data - faddr; 140 len = round_page(off + len); 141 taddr = (vaddr_t)km_alloc(len, &kv_physwait, &kp_none, &kd_waitok); 142 bp->b_data = (caddr_t)(taddr + off); 143 /* 144 * The region is locked, so we expect that pmap_pte() will return 145 * non-NULL. 146 * XXX: unwise to expect this in a multithreaded environment. 147 * anything can happen to a pmap between the time we lock a 148 * region, release the pmap lock, and then relock it for 149 * the pmap_extract(). 150 * 151 * no need to flush TLB since we expect nothing to be mapped 152 * where we just allocated (TLB will be flushed when our 153 * mapping is removed). 154 */ 155 while (len) { 156 (void) pmap_extract(vm_map_pmap(&bp->b_proc->p_vmspace->vm_map), 157 faddr, &fpa); 158 pmap_kenter_pa(taddr, fpa, PROT_READ | PROT_WRITE); 159 faddr += PAGE_SIZE; 160 taddr += PAGE_SIZE; 161 len -= PAGE_SIZE; 162 } 163 pmap_update(pmap_kernel()); 164} 165 166/* 167 * Unmap a previously-mapped user I/O request. 168 */ 169void 170vunmapbuf(struct buf *bp, vsize_t len) 171{ 172 vaddr_t addr, off; 173 174 if ((bp->b_flags & B_PHYS) == 0) 175 panic("vunmapbuf"); 176 addr = trunc_page((vaddr_t)bp->b_data); 177 off = (vaddr_t)bp->b_data - addr; 178 len = round_page(off + len); 179 pmap_kremove(addr, len); 180 pmap_update(pmap_kernel()); 181 km_free((void *)addr, len, &kv_physwait, &kp_none); 182 bp->b_data = bp->b_saveaddr; 183 bp->b_saveaddr = NULL; 184} 185