|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * @OSF_COPYRIGHT@
24: */
25: /*
26: * Copyright (c) 1990,1991,1992 The University of Utah and
27: * the Center for Software Science (CSS). All rights reserved.
28: *
29: * Permission to use, copy, modify and distribute this software is hereby
30: * granted provided that (1) source code retains these copyright, permission,
31: * and disclaimer notices, and (2) redistributions including binaries
32: * reproduce the notices in supporting documentation, and (3) all advertising
33: * materials mentioning features or use of this software display the following
34: * acknowledgement: ``This product includes software developed by the Center
35: * for Software Science at the University of Utah.''
36: *
37: * THE UNIVERSITY OF UTAH AND CSS ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
38: * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSS DISCLAIM ANY LIABILITY OF
39: * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
40: *
41: * CSS requests users of this software to return to [email protected] any
42: * improvements that they make and grant CSS redistribution rights.
43: *
44: * Utah $Hdr: pcb.c 1.23 92/06/27$
45: */
46:
47: #include <cpus.h>
48: #include <debug.h>
49:
50: #include <types.h>
51: #include <kern/task.h>
52: #include <kern/thread.h>
53: #include <kern/thread_act.h>
54: #include <kern/thread_swap.h>
55: #include <mach/thread_status.h>
56: #include <vm/vm_kern.h>
57: #include <kern/mach_param.h>
58:
59: #include <kern/misc_protos.h>
60: #include <ppc/misc_protos.h>
61: #include <ppc/fpu_protos.h>
62: #include <ppc/exception.h>
63: #include <ppc/proc_reg.h>
64: #include <kern/spl.h>
65: #include <ppc/pmap.h>
66: #include <ppc/trap.h>
67: #include <ppc/mappings.h>
68: #include <ppc/savearea.h>
69: #include <ppc/Firmware.h>
70: #include <ppc/asm.h>
71: #include <ppc/thread_act.h>
72:
73: #include <sys/kdebug.h>
74:
75: extern int real_ncpus; /* Number of actual CPUs */
76: extern struct Saveanchor saveanchor; /* Aliged savearea anchor */
77:
78: /*
79: * These constants are dumb. They should not be in asm.h!
80: */
81:
82: #define KF_SIZE (FM_SIZE+ARG_SIZE+FM_REDZONE)
83:
84: #if DEBUG
85: int fpu_trap_count = 0;
86: int fpu_switch_count = 0;
87: int vec_trap_count = 0;
88: int vec_switch_count = 0;
89: #endif
90:
91: extern struct thread_shuttle *Switch_context(
92: struct thread_shuttle *old,
93: void (*cont)(void),
94: struct thread_shuttle *new);
95:
96:
97: #if MACH_LDEBUG || MACH_KDB
98: void log_thread_action (char *, long, long, long);
99: #endif
100:
101:
102: /*
103: * consider_machine_collect: try to collect machine-dependent pages
104: */
105: void
106: consider_machine_collect()
107: {
108: /*
109: * none currently available
110: */
111: return;
112: }
113:
114: /*
115: * stack_attach: Attach a kernel stack to a thread.
116: */
117: void
118: machine_kernel_stack_init(
119: struct thread_shuttle *thread,
120: void (*continuation)(void))
121: {
122: vm_offset_t stack;
123: unsigned int *kss;
124: struct savearea *sv;
125:
126: assert(thread->top_act->mact.pcb);
127: assert(thread->kernel_stack);
128: stack = thread->kernel_stack;
129:
130: #if MACH_ASSERT
131: if (watchacts & WA_PCB)
132: printf("machine_kernel_stack_init(thr=%x,stk=%x,cont=%x)\n", thread,stack,continuation);
133: #endif /* MACH_ASSERT */
134:
135: kss = (unsigned int *)STACK_IKS(stack);
136: sv=(savearea *)(thread->top_act->mact.pcb); /* This for the sake of C */
137:
138: sv->save_lr = (unsigned int) continuation; /* Set up the execution address */
139: sv->save_srr0 = (unsigned int) continuation; /* Here too */
140: sv->save_srr1 = MSR_SUPERVISOR_INT_ON; /* Set the normal running MSR */
141: sv->save_r1 = (vm_offset_t) ((int)kss - KF_SIZE); /* Point to the top frame on the stack */
142:
143: *((int *)sv->save_r1) = 0; /* Zero the frame backpointer */
144: thread->top_act->mact.ksp = 0; /* Show that the kernel stack is in use already */
145:
146: }
147:
148: /*
149: * switch_context: Switch from one thread to another, needed for
150: * switching of space
151: *
152: */
153: struct thread_shuttle*
154: switch_context(
155: struct thread_shuttle *old,
156: void (*continuation)(void),
157: struct thread_shuttle *new)
158: {
159: register thread_act_t old_act = old->top_act, new_act = new->top_act;
160: register struct thread_shuttle* retval;
161: pmap_t new_pmap;
162: #if MACH_LDEBUG || MACH_KDB
163: log_thread_action("switch",
164: (long)old,
165: (long)new,
166: (long)__builtin_return_address(0));
167: #endif
168: assert(old_act->kernel_loaded ||
169: active_stacks[cpu_number()] == old_act->thread->kernel_stack);
170: assert (get_preemption_level() == 1);
171: check_simple_locks();
172:
173: /* Our context might wake up on another processor, so we must
174: * not keep hot state in our FPU, it must go back to the pcb
175: * so that it can be found by the other if needed
176: */
177: if(real_ncpus > 1) { /* This is potentially slow, so only do when actually SMP */
178: fpu_save(); /* Save floating point if used */
179: vec_save(); /* Save vector if used */
180: }
181:
182: #if DEBUG
183: if (watchacts & WA_PCB) {
184: printf("switch_context(0x%08x, 0x%x, 0x%08x)\n",
185: old,continuation,new);
186: }
187: #endif /* DEBUG */
188:
189: /*
190: * We do not have to worry about the PMAP module, so switch.
191: *
192: * We must not use top_act->map since this may not be the actual
193: * task map, but the map being used for a klcopyin/out.
194: */
195:
196: new_pmap = new_act->task->map->pmap;
197: if (old_act->task->map->pmap != new_pmap) {
198: pmap_switch(new_pmap);
199: }
200:
201: /* Sanity check - is the stack pointer inside the stack that
202: * we're about to switch to? Is the execution address within
203: * the kernel's VM space??
204: */
205: #if 0
206: printf("************* stack=%08X; R1=%08X; LR=%08X; old=%08X; cont=%08X; new=%08X\n",
207: new->kernel_stack, new_act->mact.pcb->ss.r1,
208: new_act->mact.pcb->ss.lr, old, continuation, new); /* (TEST/DEBUG) */
209: assert((new->kernel_stack < new_act->mact.pcb->ss.r1) &&
210: ((unsigned int)STACK_IKS(new->kernel_stack) >
211: new_act->mact.pcb->ss.r1));
212: assert(new_act->mact.pcb->ss.lr < VM_MAX_KERNEL_ADDRESS);
213: #endif
214:
215:
216: KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_SCHED,MACH_SCHED) | DBG_FUNC_NONE,
217: (int)old, (int)new, old->sched_pri, new->sched_pri, 0);
218:
219:
220: retval = Switch_context(old, continuation, new);
221: assert(retval != (struct thread_shuttle*)NULL);
222:
223: /* We've returned from having switched context, so we should be
224: * back in the original context.
225: */
226:
227: return retval;
228: }
229:
230: /*
231: * Alter the thread's state so that a following thread_exception_return
232: * will make the thread return 'retval' from a syscall.
233: */
234: void
235: thread_set_syscall_return(
236: struct thread_shuttle *thread,
237: kern_return_t retval)
238: {
239: struct ppc_saved_state *ssp = &thread->top_act->mact.pcb->ss;
240:
241: #if MACH_ASSERT
242: if (watchacts & WA_PCB)
243: printf("thread_set_syscall_return(thr=%x,retval=%d)\n", thread,retval);
244: #endif /* MACH_ASSERT */
245:
246: ssp->r3 = retval;
247: }
248:
249: /*
250: * Initialize the machine-dependent state for a new thread.
251: */
252: kern_return_t
253: thread_machine_create(
254: struct thread_shuttle *thread,
255: thread_act_t thr_act,
256: void (*start_pos)(void))
257: {
258:
259: savearea *sv; /* Pointer to newly allocated savearea */
260: unsigned int *CIsTooLimited, i;
261:
262:
263: #if MACH_ASSERT
264: if (watchacts & WA_PCB)
265: printf("thread_machine_create(thr=%x,thr_act=%x,st=%x)\n", thread, thr_act, start_pos);
266: #endif /* MACH_ASSERT */
267:
268: hw_atomic_add(&saveanchor.saveneed, 4); /* Account for the number of saveareas we think we "need"
269: for this activation */
270: assert(thr_act->mact.pcb == (pcb_t)0); /* Make sure there was no previous savearea */
271:
272: sv = save_alloc(); /* Go get us a savearea */
273:
274: bzero((char *) sv, sizeof(struct pcb)); /* Clear out the whole shebang */
275:
276: sv->save_act = thr_act; /* Set who owns it */
277: /* XXX: TO BE REMOVED WA for AltiVec compiler bug */
278: sv->save_vrsave = 0xffffffff;
279: thr_act->mact.pcb = (pcb_t)sv; /* Point to the save area */
280:
281: thread->kernel_stack = (int)stack_alloc(thread,start_pos); /* Allocate our kernel stack */
282: assert(thread->kernel_stack); /* Make sure we got it */
283:
284: #if MACH_ASSERT
285: if (watchacts & WA_PCB)
286: printf("pcb_init(%x) pcb=%x\n", thr_act, sv);
287: #endif /* MACH_ASSERT */
288: /*
289: * User threads will pull their context from the pcb when first
290: * returning to user mode, so fill in all the necessary values.
291: * Kernel threads are initialized from the save state structure
292: * at the base of the kernel stack (see stack_attach()).
293: */
294:
295: sv->save_srr1 = MSR_EXPORT_MASK_SET; /* Set the default user MSR */
296:
297: CIsTooLimited = (unsigned int *)(&sv->save_sr0); /* Make a pointer 'cause C can't cast on the left */
298: for(i=0; i<16; i++) { /* Initialize all SRs */
299: CIsTooLimited[i] = SEG_REG_PROT | (i << 20) | thr_act->task->map->pmap->space; /* Set the SR value */
300: }
301: sv->save_sr_copyin = SEG_REG_PROT | (SR_COPYIN_NUM<<20) | thr_act->task->map->pmap->space; /* Default the copyin */
302:
303: return(KERN_SUCCESS);
304: }
305:
306: /*
307: * Machine-dependent cleanup prior to destroying a thread
308: */
309: void
310: thread_machine_destroy( thread_t thread )
311: {
312: spl_t s;
313:
314: assert(thread->kernel_stack);
315: s = splsched();
316: stack_free(thread);
317: splx(s);
318: }
319:
320: /*
321: * flush out any lazily evaluated HW state in the
322: * owning thread's context, before termination.
323: */
324: void
325: thread_machine_flush( thread_act_t cur_act )
326: {
327: }
328:
329: /*
330: * Number of times we needed to swap an activation back in before
331: * switching to it.
332: */
333: int switch_act_swapins = 0;
334:
335: /*
336: * machine_switch_act
337: *
338: * Machine-dependent details of activation switching. Called with
339: * RPC locks held and preemption disabled.
340: */
341: void
342: machine_switch_act(
343: thread_t thread,
344: thread_act_t old,
345: thread_act_t new,
346: int cpu)
347: {
348: pmap_t new_pmap;
349:
350: /* Our context might wake up on another processor, so we must
351: * not keep hot state in our FPU, it must go back to the pcb
352: * so that it can be found by the other if needed
353: */
354: if(real_ncpus > 1) { /* This is potentially slow, so only do when actually SMP */
355: fpu_save(); /* Save floating point if used */
356: vec_save(); /* Save vector if used */
357: }
358:
359: active_stacks[cpu] = thread->kernel_stack;
360:
361: ast_context(new, cpu);
362:
363: /* Activations might have different pmaps
364: * (process->kernel->server, for example).
365: * Change space if needed
366: */
367: new_pmap = new->task->map->pmap;
368: if (old->task->map->pmap != new_pmap) {
369: pmap_switch(new_pmap);
370: }
371: }
372:
373: void
374: pcb_user_to_kernel(thread_act_t act)
375: {
376:
377: return; /* Not needed, I hope... */
378: }
379:
380:
381: /*
382: * act_machine_sv_free
383: * release saveareas associated with an act. if flag is true, release
384: * user level savearea(s) too, else don't
385: *
386: * this code cannot block so we call the proper save area free routine
387: */
388: void
389: act_machine_sv_free(thread_act_t act)
390: {
391: register pcb_t pcb,userpcb,npcb;
392: register savearea *svp;
393: register int i;
394:
395: /*
396: * This next bit insures that any live facility context for this thread is discarded on every processor
397: * that may have it. We go through all per-processor blocks and zero the facility owner if
398: * it is the thread being destroyed. This needs to be done via a compare-and-swap because
399: * some other processor could change the owner while we are clearing it. It turns out that
400: * this is the only place where we need the interlock, normal use of the owner field is cpu-local
401: * and doesn't need the interlock. Because we are called during termintation, and a thread
402: * terminates itself, the context on other processors has been saved (because we save it as
403: * part of the context switch), even if it is still considered live. Since the dead thread is
404: * not running elsewhere, and the context is saved, any other processor looking at the owner
405: * field will not attempt to save context again, meaning that it doesn't matter if the owner
406: * changes out from under it.
407: */
408:
409: /*
410: * free VMX and FPU saveareas. do not free user save areas.
411: * user VMX and FPU saveareas, if any, i'm told are last in
412: * the chain so we just stop if we find them
413: * we identify user VMX and FPU saveareas when we find a pcb
414: * with a save level of 0. we identify user regular save
415: * areas when we find one with MSR_PR set
416: */
417:
418: pcb = act->mact.VMX_pcb; /* Get the top vector savearea */
419: while(pcb) { /* Any VMX saved state? */
420: svp = (savearea *)pcb; /* save lots of casting later */
421: if (svp->save_level_vec == 0) break; /* done when hit user if any */
422: pcb = (pcb_t)svp->save_prev_vector; /* Get one underneath our's */
423: svp->save_flags &= ~SAVvmxvalid; /* Clear the VMX flag */
424: if(!(svp->save_flags & SAVinuse)) { /* Anyone left with this one? */
425:
426: save_ret(svp); /* release it */
427: }
428: }
429: act->mact.VMX_pcb = pcb;
430: if (act->mact.VMX_lvl != 0) {
431: for(i=0; i < real_ncpus; i++) { /* Cycle through processors */
432: (void)hw_compare_and_store((unsigned int)act, 0, &per_proc_info[i].VMX_thread); /* Clear if ours */
433: }
434: }
435:
436: pcb = act->mact.FPU_pcb; /* Get the top floating point savearea */
437: while(pcb) { /* Any floating point saved state? */
438: svp = (savearea *)pcb;
439: if (svp->save_level_fp == 0) break; /* done when hit user if any */
440: pcb = (pcb_t)svp->save_prev_float; /* Get one underneath our's */
441: svp->save_flags &= ~SAVfpuvalid; /* Clear the floating point flag */
442: if(!(svp->save_flags & SAVinuse)) { /* Anyone left with this one? */
443: save_ret(svp); /* Nope, release it */
444: }
445: }
446: act->mact.FPU_pcb = pcb;
447: if (act->mact.FPU_lvl != 0) {
448: for(i=0; i < real_ncpus; i++) { /* Cycle through processors */
449: (void)hw_compare_and_store((unsigned int)act, 0, &per_proc_info[i].FPU_thread); /* Clear if ours */
450: }
451: }
452:
453: /*
454: * free all regular saveareas except a user savearea, if any
455: */
456:
457: pcb = act->mact.pcb;
458: userpcb = (pcb_t)0;
459: while(pcb) {
460: svp = (savearea *)pcb;
461: if ((svp->save_srr1 & MASK(MSR_PR))) {
462: assert(userpcb == (pcb_t)0);
463: userpcb = pcb;
464: svp = (savearea *)userpcb;
465: npcb = (pcb_t)svp->save_prev;
466: svp->save_prev = (struct savearea *)0;
467: } else {
468: svp->save_flags = 0;
469: npcb = (pcb_t)svp->save_prev;
470: save_ret(svp);
471: }
472: pcb = npcb;
473: }
474: act->mact.pcb = userpcb;
475:
476: }
477:
478: /*
479: * act_machine_destroy: Shutdown any state associated with a thread pcb.
480: */
481: void
482: act_machine_destroy(thread_act_t act)
483: {
484: register pcb_t pcb, opcb;
485: int i;
486:
487: #if MACH_ASSERT
488: if (watchacts & WA_PCB)
489: printf("act_machine_destroy(0x%x)\n", act);
490: #endif /* MACH_ASSERT */
491:
492: if(act->mact.bbDescAddr) { /* Check if the Blue box assist is active */
493: (void) vm_map_unwire(act->map, /* Unwire the descriptor in user's address space */
494: (vm_offset_t)act->mact.bbUserDA,
495: (vm_offset_t)act->mact.bbUserDA + PAGE_SIZE,
496: FALSE);
497:
498: kmem_free(kernel_map, (vm_offset_t)act->mact.bbDescAddr, PAGE_SIZE); /* Release the page */
499:
500: act->mact.bbDescAddr = 0; /* Clear kernel pointer to it */
501: act->mact.bbUserDA = 0; /* Clear user pointer to it */
502: act->mact.bbTableStart = 0; /* Clear start of table address */
503:
504: }
505:
506: /*
507: * This next bit insures that any live facility context for this thread is discarded on every processor
508: * that may have it. We go through all per-processor blocks and zero the facility owner if
509: * it is the thread being destroyed. This needs to be done via a compare-and-swap because
510: * some other processor could change the owner while we are clearing it. It turns out that
511: * this is the only place where we need the interlock, normal use of the owner field is cpu-local
512: * and doesn't need the interlock. Because we are called during termintation, and a thread
513: * terminates itself, the context on other processors has been saved (because we save it as
514: * part of the context switch), even if it is still considered live. Since the dead thread is
515: * not running elsewhere, and the context is saved, any other processor looking at the owner
516: * field will not attempt to save context again, meaning that it doesn't matter if the owner
517: * changes out from under it.
518: */
519:
520: for(i=0; i < real_ncpus; i++) { /* Cycle through processors */
521: (void)hw_compare_and_store((unsigned int)act, 0, &per_proc_info[i].FPU_thread); /* Clear if ours */
522: (void)hw_compare_and_store((unsigned int)act, 0, &per_proc_info[i].VMX_thread); /* Clear if ours */
523: }
524:
525: pcb = act->mact.VMX_pcb; /* Get the top vector savearea */
526: while(pcb) { /* Any VMX saved state? */
527: opcb = pcb; /* Save current savearea address */
528: pcb = (pcb_t)(((savearea *)pcb)->save_prev_vector); /* Get one underneath our's */
529: ((savearea *)opcb)->save_flags &= ~SAVvmxvalid; /* Clear the VMX flag */
530:
531: if(!(((savearea *)opcb)->save_flags & SAVinuse)) { /* Anyone left with this one? */
532: save_release((savearea *)opcb); /* Nope, release it */
533: }
534: }
535: act->mact.VMX_pcb = (pcb_t)0; /* Clear pointer */
536:
537: pcb = act->mact.FPU_pcb; /* Get the top floating point savearea */
538: while(pcb) { /* Any floating point saved state? */
539: opcb = pcb; /* Save current savearea address */
540: pcb = (pcb_t)(((savearea *)pcb)->save_prev_float); /* Get one underneath our's */
541: ((savearea *)opcb)->save_flags &= ~SAVfpuvalid; /* Clear the floating point flag */
542:
543: if(!(((savearea *)opcb)->save_flags & SAVinuse)) { /* Anyone left with this one? */
544: save_release((savearea *)opcb); /* Nope, release it */
545: }
546: }
547: act->mact.FPU_pcb = (pcb_t)0; /* Clear pointer */
548:
549: pcb = act->mact.pcb; /* Get the top normal savearea */
550: act->mact.pcb = (pcb_t)0; /* Clear pointer */
551:
552: while(pcb) { /* Any normal saved state left? */
553: opcb = pcb; /* Keep track of what we're working on */
554: pcb = (pcb_t)(((savearea *)pcb)->save_prev); /* Get one underneath our's */
555:
556: ((savearea *)opcb)->save_flags = 0; /* Clear all flags since we release this in any case */
557: save_release((savearea *)opcb); /* Release this one */
558: }
559:
560: hw_atomic_sub(&saveanchor.saveneed, 4); /* Unaccount for the number of saveareas we think we "need"
561: for this activation */
562: }
563:
564: kern_return_t
565: act_machine_create(task_t task, thread_act_t thr_act)
566: {
567: /*
568: * Clear & Init the pcb (sets up user-mode s regs)
569: * We don't use this anymore.
570: */
571:
572: register pcb_t pcb;
573: register int i;
574: unsigned int *CIsTooLimited;
575: pmap_t pmap;
576:
577: return KERN_SUCCESS;
578: }
579:
580: void act_machine_init()
581: {
582: #if MACH_ASSERT
583: if (watchacts & WA_PCB)
584: printf("act_machine_init()\n");
585: #endif /* MACH_ASSERT */
586:
587: /* Good to verify these once */
588: assert( THREAD_MACHINE_STATE_MAX <= THREAD_STATE_MAX );
589:
590: assert( THREAD_STATE_MAX >= PPC_THREAD_STATE_COUNT );
591: assert( THREAD_STATE_MAX >= PPC_EXCEPTION_STATE_COUNT );
592: assert( THREAD_STATE_MAX >= PPC_FLOAT_STATE_COUNT );
593: assert( THREAD_STATE_MAX >= sizeof(struct ppc_saved_state)/sizeof(int));
594:
595: /*
596: * If we start using kernel activations,
597: * would normally create kernel_thread_pool here,
598: * populating it from the act_zone
599: */
600: }
601:
602: void
603: act_machine_return(int code)
604: {
605: thread_act_t thr_act = current_act();
606: thread_act_t cur_act;
607: thread_t cur_thread = current_thread();
608: struct ipc_port *iplock;
609:
610: #if MACH_ASSERT
611: if (watchacts & WA_EXIT)
612: printf("act_machine_return(0x%x) cur_act=%x(%d) thr=%x(%d)\n",
613: code, thr_act, thr_act->ref_count,
614: thr_act->thread, thr_act->thread
615: ? thr_act->thread->ref_count : 0);
616: #endif /* MACH_ASSERT */
617:
618:
619: /*
620: * This code is called with nothing locked.
621: * It also returns with nothing locked, if it returns.
622: *
623: * This routine terminates the current thread activation.
624: * If this is the only activation associated with its
625: * thread shuttle, then the entire thread (shuttle plus
626: * activation) is terminated.
627: */
628: assert( code == KERN_TERMINATED );
629: assert( thr_act );
630:
631: act_lock_thread(thr_act);
632:
633: #ifdef CALLOUT_RPC_MODEL
634: /*
635: * JMM - This needs to get cleaned up to work under the much simpler
636: * return (instead of callout model).
637: */
638: if (thr_act->thread->top_act != thr_act) {
639: /*
640: * this is not the top activation;
641: * if possible, we should clone the shuttle so that
642: * both the root RPC-chain and the soon-to-be-orphaned
643: * RPC-chain have shuttles
644: *
645: * JMM - Cloning is a horrible idea! Instead we should alert
646: * the pieces upstream to return the shuttle. We will use
647: * alerts for this.
648: */
649: act_unlock_thread(thr_act);
650: panic("act_machine_return: ORPHAN CASE NOT YET IMPLEMENTED");
651: }
652:
653: if (thr_act->lower != THR_ACT_NULL) {
654: /* terminate the entire thread (shuttle plus activation) */
655: /* terminate only this activation, send an appropriate */
656: /* return code back to the activation that invoked us. */
657: iplock = thr_act->pool_port; /* remember for unlock call */
658: thr_act->lower->alerts |= SERVER_TERMINATED;
659: install_special_handler(thr_act->lower);
660:
661: /* Return to previous act with error code */
662:
663: act_locked_act_reference(thr_act); /* keep it around */
664: act_switch_swapcheck(cur_thread, (ipc_port_t)0);
665:
666: (void) switch_act(THR_ACT_NULL);
667: /* assert(thr_act->ref_count == 0); */ /* XXX */
668: cur_act = cur_thread->top_act;
669: MACH_RPC_RET(cur_act) = KERN_RPC_SERVER_TERMINATED;
670: machine_kernel_stack_init(cur_thread,
671: (void (*)(void)) mach_rpc_return_error);
672: /*
673: * The following unlocks must be done separately since fields
674: * used by `act_unlock_thread()' have been cleared, meaning
675: * that it would not release all of the appropriate locks.
676: */
677: rpc_unlock(cur_thread);
678: if (iplock) ip_unlock(iplock); /* must be done separately */
679: act_unlock(thr_act);
680: act_deallocate(thr_act); /* free it */
681: Load_context(cur_thread);
682: /*NOTREACHED*/
683:
684: panic("act_machine_return: TALKING ZOMBIE! (2)");
685: }
686:
687: #endif /* CALLOUT_RPC_MODEL */
688:
689: /* This is the only activation attached to the shuttle... */
690:
691: assert(thr_act->thread->top_act == thr_act);
692: act_unlock_thread(thr_act);
693: thread_terminate_self();
694:
695: /*NOTREACHED*/
696: panic("act_machine_return: TALKING ZOMBIE! (1)");
697: }
698:
699: void
700: thread_machine_set_current(struct thread_shuttle *thread)
701: {
702: register int my_cpu = cpu_number();
703:
704: cpu_data[my_cpu].active_thread = thread;
705:
706: active_kloaded[my_cpu] = thread->top_act->kernel_loaded ? thread->top_act : THR_ACT_NULL;
707: }
708:
709: void
710: thread_machine_init(void)
711: {
712: #ifdef MACHINE_STACK
713: #if KERNEL_STACK_SIZE > PPC_PGBYTES
714: panic("KERNEL_STACK_SIZE can't be greater than PPC_PGBYTES\n");
715: #endif
716: #endif
717: }
718:
719: #if MACH_ASSERT
720: void
721: dump_pcb(pcb_t pcb)
722: {
723: printf("pcb @ %8.8x:\n", pcb);
724: #if DEBUG
725: regDump(&pcb->ss);
726: #endif /* DEBUG */
727: }
728:
729: void
730: dump_thread(thread_t th)
731: {
732: printf(" thread @ 0x%x:\n", th);
733: }
734:
735: int
736: dump_act(thread_act_t thr_act)
737: {
738: if (!thr_act)
739: return(0);
740:
741: printf("thr_act(0x%x)(%d): thread=%x(%d) task=%x(%d)\n",
742: thr_act, thr_act->ref_count,
743: thr_act->thread, thr_act->thread ? thr_act->thread->ref_count:0,
744: thr_act->task, thr_act->task ? thr_act->task->ref_count : 0);
745:
746: printf("\talerts=%x mask=%x susp=%x active=%x hi=%x lo=%x\n",
747: thr_act->alerts, thr_act->alert_mask,
748: thr_act->suspend_count, thr_act->active,
749: thr_act->higher, thr_act->lower);
750:
751: return((int)thr_act);
752: }
753:
754: #endif
755:
756: unsigned int
757: get_useraddr()
758: {
759:
760: thread_act_t thr_act = current_act();
761:
762: return(thr_act->mact.pcb->ss.srr0);
763: }
764:
765: /*
766: * detach and return a kernel stack from a thread
767: */
768:
769: vm_offset_t
770: stack_detach(thread_t thread)
771: {
772: vm_offset_t stack;
773:
774: #ifdef KDEBUG
775: KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED,MACH_STACK_DETACH),
776: thread, thread->priority,
777: thread->sched_pri, 0,
778: 0);
779: #endif
780: stack = thread->kernel_stack;
781: thread->kernel_stack = 0;
782: return(stack);
783: }
784:
785: /*
786: * attach a kernel stack to a thread and initialize it
787: *
788: * attaches a stack to a thread. if there is no save
789: * area we allocate one. the top save area is then
790: * loaded with the pc (continuation address), the initial
791: * stack pointer, and a std kernel MSR. if the top
792: * save area is the user save area bad things will
793: * happen
794: *
795: */
796:
797: void
798: stack_attach(struct thread_shuttle *thread,
799: vm_offset_t stack,
800: void (*continuation)(void))
801: {
802: thread_act_t thr_act;
803: unsigned int *kss;
804: struct savearea *sv;
805:
806: #ifdef KDEBUG
807: KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED,MACH_STACK_ATTACH),
808: thread, thread->priority,
809: thread->sched_pri, continuation,
810: 0);
811: #endif
812:
813: assert(stack);
814: kss = (unsigned int *)STACK_IKS(stack);
815: thread->kernel_stack = stack;
816:
817: /* during initialization we sometimes do not have an
818: activation. in that case do not do anything */
819: if ((thr_act = thread->top_act) != 0) {
820: sv = save_get(); /* cannot block */
821: // bzero((char *) sv, sizeof(struct pcb));
822: sv->save_act = thr_act;
823: sv->save_prev = (struct savearea *)thr_act->mact.pcb;
824: thr_act->mact.pcb = (pcb_t)sv;
825:
826: sv->save_srr0 = (unsigned int) continuation;
827: /* sv->save_r3 = ARG ? */
828: sv->save_r1 = (vm_offset_t)((int)kss - KF_SIZE);
829: sv->save_srr1 = MSR_SUPERVISOR_INT_ON;
830: *((int *)sv->save_r1) = 0;
831: thr_act->mact.ksp = 0;
832: }
833:
834: return;
835: }
836:
837: /*
838: * move a stack from old to new thread
839: */
840:
841: void
842: stack_handoff(thread_t old,
843: thread_t new)
844: {
845:
846: vm_offset_t stack;
847: pmap_t new_pmap;
848:
849: assert(new->top_act);
850: assert(old->top_act);
851:
852: stack = stack_detach(old);
853: new->kernel_stack = stack;
854:
855: #if NCPUS > 1
856: if (real_ncpus > 1) {
857: fpu_save();
858: vec_save();
859: }
860: #endif
861:
862: KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_SCHED,MACH_STACK_HANDOFF) | DBG_FUNC_NONE,
863: (int)old, (int)new, old->sched_pri, new->sched_pri, 0);
864:
865: new_pmap = new->top_act->task->map->pmap;
866: if (old->top_act->task->map->pmap != new_pmap) {
867: pmap_switch(new_pmap);
868: }
869:
870: thread_machine_set_current(new);
871: active_stacks[cpu_number()] = new->kernel_stack;
872: per_proc_info[cpu_number()].Uassist = new->top_act->mact.cthread_self;
873: return;
874: }
875:
876: /*
877: * clean and initialize the current kernel stack and go to
878: * the given continuation routine
879: */
880:
881: void
882: call_continuation(void (*continuation)(void) )
883: {
884:
885: unsigned int *kss;
886: vm_offset_t tsp;
887:
888: assert(current_thread()->kernel_stack);
889: kss = (unsigned int *)STACK_IKS(current_thread()->kernel_stack);
890: assert(continuation);
891:
892: tsp = (vm_offset_t)((int)kss - KF_SIZE);
893: assert(tsp);
894: *((int *)tsp) = 0;
895:
896: Call_continuation(continuation, tsp);
897:
898: return;
899: }
900:
901: void
902: thread_swapin_mach_alloc(thread_t thread)
903: {
904: struct savearea *sv;
905:
906: assert(thread->top_act->mact.pcb == 0);
907:
908: sv = save_alloc();
909: assert(sv);
910: // bzero((char *) sv, sizeof(struct pcb));
911: sv->save_act = thread->top_act;
912: thread->top_act->mact.pcb = (pcb_t)sv;
913:
914: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.