1 /* 2 * Copyright (c) 1989, 1990, 1991, 1992, 1993, 1994 William F. Jolitz, TeleMuse 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This software is a component of "386BSD" developed by 16 * William F. Jolitz, TeleMuse. 17 * 4. Neither the name of the developer nor the name "386BSD" 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 5. Non-commercial distribution of this complete file in either source and/or 21 * binary form at no charge to the user (such as from an official Internet 22 * archive site) is permitted. 23 * 6. Commercial distribution and sale of this complete file in either source 24 * and/or binary form on any media, including that of floppies, tape, or 25 * CD-ROM, or through a per-charge download such as that of a BBS, is not 26 * permitted without specific prior written permission. 27 * 7. Non-commercial and/or commercial distribution of an incomplete, altered, 28 * or otherwise modified file in either source and/or binary form is not 29 * permitted. 30 * 31 * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ 32 * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS 33 * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT. 34 * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT 35 * NOT MAKE USE OF THIS WORK. 36 * 37 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND 38 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 39 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 40 * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER BE LIABLE 41 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 42 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 43 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 44 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 45 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 46 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 47 * SUCH DAMAGE. 48 * 49 * $Id: cpu.c,v 1.1 94/10/19 17:39:55 bill Exp $ 50 * 51 * This file contains functions that implement the machine-dependant 52 * portions of the kernel's internal facilities. 53 */ 54 55 #include "sys/param.h" 56 #include "sys/user.h" 57 #include "signalvar.h" 58 /* #include "malloc.h" */ 59 #include "proc.h" 60 #include "kmem.h" 61 #include "prototypes.h" 62 63 64 #include "machine/cpu.h" 65 #define IPCREG 66 #include "machine/reg.h" 67 #include "machine/psl.h" 68 69 #include "segments.h" 70 #include "specialreg.h" 71 #include "sigframe.h" 72 73 /* 74 * Implement the innermost part of a fork() operation, by building 75 * a new kernel execution thread (consisting of a process control block 76 * and new kernel stack). When the new thread runs, it's kernel context will 77 * appear to be identical to it's copy, except that in the copy's thread 78 * cpu_tfork() will return the value of 0, and in the new thread it will 79 * return the value of 1. 80 */ 81 int 82 cpu_tfork(struct proc *p1, register struct proc *p2) 83 { 84 int diff; 85 struct user *up; 86 unsigned *fp, nfp; 87 88 #ifdef DIAGNOSTICx /*XXX proc0 not initialized */ 89 if (p2->p_stksz < sizeof(struct pcb)) 90 panic("invalid kernel stack size"); 91 #endif 92 p2->p_addr = up = (struct user *) kmem_alloc(kernel_map, ctob(UPAGES), 0); 93 p2->p_stksz = ctob(UPAGES); /* XXX */ 94 p1->p_stksz = ctob(UPAGES); /* XXX */ 95 diff = ((caddr_t)p2->p_addr + p2->p_stksz) 96 - ((caddr_t)p1->p_addr + p1->p_stksz); 97 98 /* copy the pcb to the new process. */ 99 up->u_pcb = p1->p_addr->u_pcb; 100 101 /* update the new pcb to reflect this process current status. */ 102 /* if (curproc == p1) { */ 103 asm volatile ("movl %%esp, %0" : "=m" (up->u_pcb.pcb_tss.tss_esp)); 104 asm volatile ("movl %%ebp, %0" : "=m" (up->u_pcb.pcb_tss.tss_ebp)); 105 /* } */ 106 107 up->u_pcb.pcb_tss.tss_esp += diff; 108 up->u_pcb.pcb_tss.tss_ebp += diff; 109 110 /* copy the kernel stack */ 111 asm volatile (" cld ; repe ; movsl " : : 112 "D" ((caddr_t)up->u_pcb.pcb_tss.tss_esp /*+ diff*/), 113 "S" ((caddr_t)up->u_pcb.pcb_tss.tss_esp - diff), 114 "c" (((unsigned)p1->p_addr + p1->p_stksz 115 - (up->u_pcb.pcb_tss.tss_esp- diff) ) / sizeof(int))); 116 117 /* relocate the stack and frame pointers to the new kernel stack. */ 118 /*up->u_pcb.pcb_tss.tss_esp += diff; 119 up->u_pcb.pcb_tss.tss_ebp += diff;*/ 120 121 /* relocate the frame pointers in the new kernel stack */ 122 fp = (unsigned *) up->u_pcb.pcb_tss.tss_ebp; 123 while ((nfp = *fp) >= (unsigned) fp - (unsigned) diff) { 124 nfp += diff; 125 *fp = nfp; 126 fp = (unsigned *)nfp; 127 } 128 129 /* relocate md_reg pointer. */ 130 (int)p2->p_md.md_regs = (int) p1->p_md.md_regs + diff; 131 p2->p_md.md_flags = 0; 132 133 /* allocate a TSS for this thread. */ 134 alloctss(p2); 135 136 /* set the stack's starting location on entry into kernel mode. */ 137 up->u_pcb.pcb_tss.tss_esp0 = (unsigned) up + p2->p_stksz; 138 139 /* inherit only the shared kernel address space. */ 140 up->u_pcb.pcb_ptd = KernelPTD; 141 142 /* update the new pcb to reflect this process current status. */ 143 /* if (curproc == p1) { */ 144 asm volatile ("movl %%ebx, %0" : "=m" (up->u_pcb.pcb_tss.tss_ebx)); 145 asm volatile ("movl %%edi, %0" : "=m" (up->u_pcb.pcb_tss.tss_edi)); 146 asm volatile ("movl %%esi, %0" : "=m" (up->u_pcb.pcb_tss.tss_esi)); 147 /* } */ 148 149 /* set location of the new thread's first instruction. */ 150 asm volatile ("movl $1f, %0; 1:" : "=m" (up->u_pcb.pcb_tss.tss_eip)); 151 152 /* are we the new thread? */ 153 if (curproc == 0) { 154 asm(".globl _tfork_child ; _tfork_child: "); 155 curproc = p2; 156 splnone(); 157 return (1); /* child */ 158 } 159 return (0); /* parent */ 160 } 161 162 /* 163 * Release any remaining resources of this thread and pass control 164 * to next process or thread. 165 */ 166 volatile void 167 cpu_texit(register struct proc *p) 168 { 169 extern int Exit_stack; 170 171 /* release coprocessor if we have it */ 172 if (p == npxproc) 173 npxproc = 0; 174 175 /* release the tss, and cut over to a temporary static tss(exit_tss) */ 176 freetss((sel_t)p->p_md.md_tsel); 177 178 /* change our stack to temporary exit stack. */ 179 asm ("movl $%0, %%esp" : : "m"(Exit_stack)); 180 181 /* drop pcb and kernel stack. No more automatic references allowed. */ 182 /* if (p->p_stksz >= NBPG) */ 183 kmem_free(kernel_map, (vm_offset_t)p->p_addr, p->p_stksz); 184 /* else 185 free(p->p_addr, M_TEMP); */ 186 187 /* context switch, never to return */ 188 swtch(); 189 #ifdef DIAGNOSTIC 190 panic("cpu_exit"); 191 #endif 192 } 193 194 /* 195 * Setup processes registers for execve() 196 */ 197 void 198 cpu_execsetregs(struct proc *p, caddr_t eip, caddr_t esp) 199 { 200 201 p->p_md.md_regs[sESP] = (int) esp; 202 p->p_md.md_regs[sEBP] = 0; /* bottom of the fp chain */ 203 p->p_md.md_regs[sEIP] = (int) eip; 204 205 p->p_addr->u_pcb.pcb_flags = 0; /* no fp at all */ 206 } 207 208 /* 209 * Send an POSIX signal to the program in the process indicated. 210 * 211 * [In this version, the process *must* be the current running process. -wfj] 212 * 213 * This function alters the state of the program by adding a special 214 * stack frame to the stack, which simulates a hardware interrupt to 215 * the program. When the program is restarted, it will continue execution 216 * in the signal handler associated with this signal. If the signal 217 * handler returns, it will be compelled by the sigcode(see locore.s) 218 * present in the user program to execute a sigreturn() (see below) to 219 * reload the register state information saved in the special stack frame. 220 * 221 * If frame cannot be created, return an error code. 222 * N.B. no checks are made for copy-on-write "stacks". 223 */ 224 int 225 cpu_signal(struct proc *p, int sig, int mask) 226 { 227 sig_t catcher; 228 int *regs; 229 struct sigframe *fp; 230 struct sigacts *ps = p->p_sigacts; 231 int oonstack, frmtrap; 232 extern caddr_t sigcode; 233 extern int szsigcode; 234 235 #ifdef DIAGNOSTIC 236 if (curproc != p) 237 panic("cpu_signal(): not current process"); 238 #endif 239 catcher = ps->ps_sigact[sig]; 240 regs = p->p_md.md_regs; 241 oonstack = ps->ps_onstack; 242 frmtrap = p->p_addr->u_pcb.pcb_flags & FM_TRAP; 243 244 /* 245 * Find the base of the special signal stack frame. If a 246 * signal uses the special signal stack, and it's available, 247 * use that. Otherwise, use the program's stack. 248 */ 249 if (ps->ps_onstack == 0 && (ps->ps_sigonstack & sigmask(sig))) { 250 fp = (struct sigframe *) 251 (ps->ps_sigsp - sizeof(struct sigframe)); 252 ps->ps_onstack++; 253 } else { 254 /* could be in one of two places */ 255 if (frmtrap) 256 fp = (struct sigframe *)(regs[tESP] 257 - sizeof(struct sigframe)); 258 else 259 fp = (struct sigframe *)(regs[sESP] 260 - sizeof(struct sigframe)); 261 } 262 263 /* is signal the gauranteed bad signal, or is the new stack 264 frame inside the user program address space ? */ 265 if (catcher == BADSIG 266 || (unsigned) fp + sizeof(struct sigframe) > USRSTACK) { 267 asm("cpu_signal_err:"); 268 p->p_md.md_onfault = 0; 269 return(EFAULT); 270 } 271 272 /* 273 * point the fault vector at the error return, so that any 274 * failed user process address space reference will cause 275 * a terminal error. 276 */ 277 asm ("movl $cpu_signal_err, %0 " 278 : "=o" (p->p_md.md_onfault)); 279 280 /* construct the program visable portion of the signal frame. */ 281 fp->sf_signum = sig; 282 fp->sf_code = ps->ps_code; 283 fp->sf_scp = &fp->sf_sc; 284 fp->sf_handler = catcher; 285 286 /* save scratch registers in the opaque portion of the signal frame. */ 287 if(frmtrap) { 288 fp->sf_eax = regs[tEAX]; 289 fp->sf_edx = regs[tEDX]; 290 fp->sf_ecx = regs[tECX]; 291 } else { 292 fp->sf_eax = regs[sEAX]; 293 fp->sf_edx = regs[sEDX]; 294 fp->sf_ecx = regs[sECX]; 295 } 296 297 /* record previous program state so sigreturn() can restore it. */ 298 fp->sf_sc.sc_onstack = oonstack; 299 fp->sf_sc.sc_mask = mask; 300 memcpy((caddr_t)fp->sf_sigcode, &sigcode, szsigcode); 301 if(frmtrap) { 302 fp->sf_sc.sc_sp = regs[tESP]; 303 fp->sf_sc.sc_fp = regs[tEBP]; 304 fp->sf_sc.sc_pc = regs[tEIP]; 305 fp->sf_sc.sc_ps = regs[tEFLAGS]; 306 regs[tESP] = (int)fp; 307 regs[tEIP] = (int)fp->sf_sigcode; 308 } else { 309 fp->sf_sc.sc_sp = regs[sESP]; 310 fp->sf_sc.sc_fp = regs[sEBP]; 311 fp->sf_sc.sc_pc = regs[sEIP]; 312 fp->sf_sc.sc_ps = regs[sEFLAGS]; 313 regs[sESP] = (int)fp; 314 regs[sEIP] = (int)fp->sf_sigcode; 315 } 316 317 /* clear fault vector, return success */ 318 p->p_md.md_onfault = 0; 319 return(0); 320 } 321 322 /* 323 * Function to restore signal context prior to signal. 324 * This function is just an implementation detail to clean up 325 * the special stack frame installed by cpu_signal(). To avoid 326 * being spoofed, the contents of the frame are "sanity checked" 327 * to insure that the kernel program is not comprimised. 328 * This function is normally called from a hidden system call. 329 */ 330 int 331 cpu_signalreturn(struct proc *p) 332 { struct sigcontext *scp; 333 struct sigframe *fp; 334 int *regs = p->p_md.md_regs; 335 336 /* signal state is current top of stack contents */ 337 fp = (struct sigframe *) regs[sESP] ; 338 339 /* is new stack frame inside the user program address space ? */ 340 if ((unsigned) fp + sizeof(struct sigframe) > USRSTACK) { 341 asm("cpu_signalreturn_err:"); 342 p->p_md.md_onfault = 0; 343 return(EFAULT); 344 } 345 346 /* 347 * point the fault vector at the error return, so that any 348 * failed user process address space reference will cause 349 * a terminal error. 350 */ 351 asm ("movl $cpu_signalreturn_err, %0 " : "=o" (p->p_md.md_onfault)); 352 353 /* check to see if this is a valid context generated by cpu_signal() */ 354 if (fp->sf_scp != &fp->sf_sc) { 355 p->p_md.md_onfault = 0; 356 return(EINVAL); 357 } 358 scp = fp->sf_scp; 359 if ((scp->sc_ps & PSL_MBZ) != 0 || (scp->sc_ps & PSL_MBO) != PSL_MBO) { 360 p->p_md.md_onfault = 0; 361 return(EINVAL); 362 } 363 364 /* restore previous program state and signal state */ 365 p->p_sigacts->ps_onstack = scp->sc_onstack & 1; 366 p->p_sigmask = scp->sc_mask & ~sigcantmask; 367 regs[sEBP] = scp->sc_fp; 368 regs[sESP] = scp->sc_sp; 369 regs[sEIP] = scp->sc_pc; 370 regs[sEFLAGS] = (scp->sc_ps | PSL_USERSET) & ~PSL_USERCLR; 371 372 /* restore scratch registers */ 373 regs[sEAX] = fp->sf_eax; 374 regs[sEDX] = fp->sf_edx; 375 regs[sECX] = fp->sf_ecx; 376 377 p->p_md.md_onfault = 0; 378 return(EJUSTRETURN); 379 } 380 381 /* 382 * Force reset the processor by invalidating the entire address space! 383 */ 384 void 385 cpu_reset(void) { 386 387 /* force a shutdown by unmapping entire address space ! */ 388 (void)memset((caddr_t) PTD, 0, NBPG); 389 390 /* "good night, sweet prince .... <THUNK!>" */ 391 tlbflush(); 392 393 asm(" movl $0, %esp "); 394 395 /* NOTREACHED */ 396 } 397 398 static int sipcreg[NIPCREG] = 399 { 0,0,sEDI,sESI,sEBP,sEBX,sEDX,sECX,sEAX,sEIP,sCS,sEFLAGS,sESP,sSS }; 400 static int ipcreg[NIPCREG] = 401 { tES,tDS,tEDI,tESI,tEBP,tEBX,tEDX,tECX,tEAX,tEIP,tCS,tEFLAGS,tESP,tSS }; 402 403 /* 404 * Return address of desired register for ptrace() XXX 405 */ 406 int * 407 cpu_ptracereg(struct proc *p, int reg) { 408 409 /*if (p->p_addr->u_pcb.pcb_flags & FM_TRAP) 410 return (p->p_md.md_regs + ipcreg[reg]); 411 else 412 return (p->p_md.md_regs + sipcreg[reg]); */ 413 return (p->p_md.md_regs + reg); 414 } 415 416