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