xref: /386bsd/usr/src/kernel/kern/i386/cpu.c (revision dc8b130e)
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 Locker: bill $
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
cpu_tfork(struct proc * p1,register struct proc * p2)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 final_swtch(void);
167 volatile void
cpu_texit(register struct proc * p)168 cpu_texit(register struct proc *p)
169 {
170 	extern int Exit_stack;
171 
172 	/* release coprocessor if we have it */
173 	if (p == npxproc)
174 		npxproc = 0;
175 
176 	/* release the tss, and cut over to a temporary static tss(exit_tss) */
177 	freetss((sel_t)p->p_md.md_tsel);
178 
179 	/* change our stack to temporary exit stack. */
180 	asm ("movl $%0, %%esp" : : "m"(Exit_stack));
181 
182 	/* drop pcb and kernel stack. No more automatic references allowed. */
183 	/* if (p->p_stksz >= NBPG) */
184 		kmem_free(kernel_map, (vm_offset_t)p->p_addr, p->p_stksz);
185 	/* else
186 		free(p->p_addr, M_TEMP); */
187 
188 	/* context switch, never to return */
189 	final_swtch();
190 #ifdef	DIAGNOSTIC
191 	panic("cpu_exit");
192 #endif
193 }
194 
195 /*
196  * Setup processes registers for execve()
197  */
198 void
cpu_execsetregs(struct proc * p,caddr_t eip,caddr_t esp)199 cpu_execsetregs(struct proc *p, caddr_t eip, caddr_t esp)
200 {
201 
202 	p->p_md.md_regs[sESP] = (int) esp;
203 	p->p_md.md_regs[sEBP] = 0;	/* bottom of the fp chain */
204 	p->p_md.md_regs[sEIP] = (int) eip;
205 
206 	p->p_addr->u_pcb.pcb_flags = 0;	/* no fp at all */
207 }
208 
209 /*
210  * Send an POSIX signal to the program in the process indicated.
211  *
212  * [In this version, the process *must* be the current running process. -wfj]
213  *
214  * This function alters the state of the program by adding a special
215  * stack frame to the stack, which simulates a hardware interrupt to
216  * the program. When the program is restarted, it will continue execution
217  * in the signal handler associated with this signal. If the signal
218  * handler returns, it will be compelled by the sigcode(see locore.s)
219  * present in the user program to execute a sigreturn() (see below) to
220  * reload the register state information saved in the special stack frame.
221  *
222  * If frame cannot be created, return an error code.
223  * N.B. no checks are made for copy-on-write "stacks".
224  */
225 int
cpu_signal(struct proc * p,int sig,int mask)226 cpu_signal(struct proc *p, int sig, int mask)
227 {
228 	sig_t catcher;
229 	int *regs;
230 	struct sigframe *fp;
231 	struct sigacts *ps = p->p_sigacts;
232 	int oonstack, frmtrap;
233 	extern caddr_t sigcode;
234 	extern int szsigcode;
235 
236 #ifdef	DIAGNOSTIC
237 	if (curproc != p)
238 		panic("cpu_signal(): not current process");
239 #endif
240 	catcher = ps->ps_sigact[sig];
241 	regs = p->p_md.md_regs;
242         oonstack = ps->ps_onstack;
243 	frmtrap = p->p_addr->u_pcb.pcb_flags & FM_TRAP;
244 
245 	/*
246 	 * Find the base of the special signal stack frame. If a
247 	 * signal uses the special signal stack, and it's available,
248 	 * use that. Otherwise, use the program's stack.
249 	 */
250         if (ps->ps_onstack == 0 && (ps->ps_sigonstack & sigmask(sig))) {
251 		fp = (struct sigframe *)
252 		    (ps->ps_sigsp - sizeof(struct sigframe));
253                 ps->ps_onstack++;
254 	} else {
255 		/* could be in one of two places */
256 		if (frmtrap)
257 			fp = (struct sigframe *)(regs[tESP]
258 				- sizeof(struct sigframe));
259 		else
260 			fp = (struct sigframe *)(regs[sESP]
261 				- sizeof(struct sigframe));
262 	}
263 
264 	/* is signal the gauranteed bad signal, or is the new stack
265 	   frame inside the user program address space ? */
266 	if (catcher == BADSIG
267 	   || (unsigned) fp + sizeof(struct sigframe) >  USRSTACK) {
268 		asm("cpu_signal_err:");
269 		p->p_md.md_onfault = 0;
270 		return(EFAULT);
271 	}
272 
273 	/*
274 	 * point the fault vector at the error return, so that any
275 	 * failed user process address space reference will cause
276 	 * a terminal error.
277 	 */
278 	asm ("movl $cpu_signal_err, %0 "
279 		: "=o" (p->p_md.md_onfault));
280 
281 	/* construct the program visable portion of the signal frame. */
282 	fp->sf_signum = sig;
283 	fp->sf_code = ps->ps_code;
284 	fp->sf_scp = &fp->sf_sc;
285 	fp->sf_handler = catcher;
286 
287 	/* save scratch registers in the opaque portion of the signal frame. */
288 	if(frmtrap) {
289 		fp->sf_eax = regs[tEAX];
290 		fp->sf_edx = regs[tEDX];
291 		fp->sf_ecx = regs[tECX];
292 	} else {
293 		fp->sf_eax = regs[sEAX];
294 		fp->sf_edx = regs[sEDX];
295 		fp->sf_ecx = regs[sECX];
296 	}
297 
298 	/* record previous program state so sigreturn() can restore it. */
299 	fp->sf_sc.sc_onstack = oonstack;
300 	fp->sf_sc.sc_mask = mask;
301 	memcpy((caddr_t)fp->sf_sigcode, &sigcode, szsigcode);
302 	if(frmtrap) {
303 		fp->sf_sc.sc_sp = regs[tESP];
304 		fp->sf_sc.sc_fp = regs[tEBP];
305 		fp->sf_sc.sc_pc = regs[tEIP];
306 		fp->sf_sc.sc_ps = regs[tEFLAGS];
307 		regs[tESP] = (int)fp;
308 		regs[tEIP] = (int)fp->sf_sigcode;
309 	} else {
310 		fp->sf_sc.sc_sp = regs[sESP];
311 		fp->sf_sc.sc_fp = regs[sEBP];
312 		fp->sf_sc.sc_pc = regs[sEIP];
313 		fp->sf_sc.sc_ps = regs[sEFLAGS];
314 		regs[sESP] = (int)fp;
315 		regs[sEIP] = (int)fp->sf_sigcode;
316 	}
317 
318 	/* clear fault vector, return success */
319 	p->p_md.md_onfault = 0;
320 	return(0);
321 }
322 
323 /*
324  * Function to restore signal context prior to signal.
325  * This function is just an implementation detail to clean up
326  * the special stack frame installed by cpu_signal(). To avoid
327  * being spoofed, the contents of the frame are "sanity checked"
328  * to insure that the kernel program is not comprimised.
329  * This function is normally called from a hidden system call.
330  */
331 int
cpu_signalreturn(struct proc * p)332 cpu_signalreturn(struct proc *p)
333 {	struct sigcontext *scp;
334 	struct sigframe *fp;
335 	int *regs = p->p_md.md_regs;
336 
337 	/* signal state is current top of stack contents */
338 	fp = (struct sigframe *) regs[sESP] ;
339 
340 	/* is new stack frame inside the user program address space ? */
341 	if ((unsigned) fp + sizeof(struct sigframe) >  USRSTACK) {
342 		asm("cpu_signalreturn_err:");
343 		p->p_md.md_onfault = 0;
344 		return(EFAULT);
345 	}
346 
347 	/*
348 	 * point the fault vector at the error return, so that any
349 	 * failed user process address space reference will cause
350 	 * a terminal error.
351 	 */
352 	asm ("movl $cpu_signalreturn_err, %0 " : "=o" (p->p_md.md_onfault));
353 
354 	/* check to see if this is a valid context generated by cpu_signal() */
355 	if (fp->sf_scp != &fp->sf_sc) {
356 		p->p_md.md_onfault = 0;
357 		return(EINVAL);
358 	}
359 	scp = fp->sf_scp;
360 	if ((scp->sc_ps & PSL_MBZ) != 0 || (scp->sc_ps & PSL_MBO) != PSL_MBO) {
361 		p->p_md.md_onfault = 0;
362 		return(EINVAL);
363 	}
364 
365 	/* restore previous program state and signal state */
366         p->p_sigacts->ps_onstack = scp->sc_onstack & 1;
367 	p->p_sigmask = scp->sc_mask & ~sigcantmask;
368 	regs[sEBP] = scp->sc_fp;
369 	regs[sESP] = scp->sc_sp;
370 	regs[sEIP] = scp->sc_pc;
371 	regs[sEFLAGS] = (scp->sc_ps | PSL_USERSET) & ~PSL_USERCLR;
372 
373 	/* restore scratch registers */
374 	regs[sEAX] = fp->sf_eax;
375 	regs[sEDX] = fp->sf_edx;
376 	regs[sECX] = fp->sf_ecx;
377 
378 	p->p_md.md_onfault = 0;
379 	return(EJUSTRETURN);
380 }
381 
382 /*
383  * Force reset the processor by invalidating the entire address space!
384  */
385 void
cpu_reset(void)386 cpu_reset(void) {
387 
388 	/* force a shutdown by unmapping entire address space ! */
389 	(void)memset((caddr_t) PTD, 0, NBPG);
390 
391 	/* "good night, sweet prince .... <THUNK!>" */
392 	tlbflush();
393 
394 	asm("	movl	$0, %esp ");
395 
396 	/* NOTREACHED */
397 }
398 
399 static int sipcreg[NIPCREG] =
400   { 0,0,sEDI,sESI,sEBP,sEBX,sEDX,sECX,sEAX,sEIP,sCS,sEFLAGS,sESP,sSS };
401 static int ipcreg[NIPCREG] =
402   { tES,tDS,tEDI,tESI,tEBP,tEBX,tEDX,tECX,tEAX,tEIP,tCS,tEFLAGS,tESP,tSS };
403 
404 /*
405  * Return address of desired register for ptrace() XXX
406  */
407 int *
cpu_ptracereg(struct proc * p,int reg)408 cpu_ptracereg(struct proc *p, int reg) {
409 
410 	/*if (p->p_addr->u_pcb.pcb_flags & FM_TRAP)
411 		return (p->p_md.md_regs + ipcreg[reg]);
412 	else
413 		return (p->p_md.md_regs + sipcreg[reg]); */
414 	return (p->p_md.md_regs + reg);
415 }
416 
417