|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /* HISTORY
26:
27: 1997/05/16 Rene Vega -- cleanup sync/isync usage.
28: */
29:
30: #import <machdep/ppc/exception.h>
31: #import <mach/mach_types.h>
32: #import <kern/mach_param.h>
33: #import <kern/thread.h>
34: #import <kern/kernel_stack.h>
35: #import <machdep/ppc/thread.h>
36: #import <bsd/ppc/psl.h>
37: #import <sys/time.h>
38: #import <bsd/ppc/vmparam.h>
39: #import <kernserv/ppc/spl.h>
40: #import <sys/param.h>
41: #import <sys/proc.h>
42: #import <kern/parallel.h>
43: #include <machdep/ppc/proc_reg.h>
44: #include <ppc/trap.h>
45: #ifdef KDEBUG
46: #include <kern/kdebug.h>
47: #include <mach_counters.h>
48: #include <kern/counters.h>
49: #import <machdep/ppc/frame.h>
50: #endif
51: #import <machdep/ppc/asm.h>
52: #import <assym.h>
53:
54: pcb_t active_pcbs[NCPUS]; /* PCB belonging to the active thread */
55:
56: #if DEBUG
57: int fpu_trap_count = 0;
58: int fpu_switch_count = 0;
59: #endif
60:
61: extern struct per_proc_info per_proc_info[];
62:
63: #define current_pcb() active_pcbs[cpu_number()]
64:
65: zone_t pcb_zone;
66:
67: /*
68: * Initialize pcb allocation zone.
69: */
70: void
71: pcb_module_init(void)
72: {
73: int i;
74: pcb_zone = zinit(
75: sizeof (struct pcb),
76: THREAD_MAX * sizeof (struct pcb),
77: THREAD_CHUNK * sizeof (struct pcb),
78: FALSE, "pcb");
79:
80: for (i=0; i < NCPUS; i++) {
81: active_pcbs[i] = 0;
82: }
83: }
84:
85: /*
86: * Allocated and initialize a pcb for a new thread.
87: */
88: void pcb_init(thread_t thread)
89: {
90: struct pcb *pcb = (void *)zalloc(pcb_zone);
91: pmap_t pmap = thread->task->map->pmap;
92:
93:
94: thread->pcb = pcb;
95:
96: /* all fields default to zero */
97: bzero((caddr_t)pcb, sizeof (struct pcb));
98:
99: /*
100: * User threads will pull their context from the pcb when first
101: * returning to user mode, so fill in all the necessary values.
102: * Kernel threads are initialized from the save state structure
103: * at the base of the kernel stack (see stack_attach()).
104: */
105:
106: pcb->ss.srr1 = MSR_EXPORT_MASK_SET;
107:
108: pcb->sr0 = SEG_REG_PROT | (pmap->space<<4);
109: pcb->ss.sr_copyin = SEG_REG_PROT | SR_COPYIN + (pmap->space<<4);
110: }
111:
112: /*
113: * Release machine dependent resources on
114: * thread termination.
115: */
116: pcb_terminate(
117: thread_t thread
118: )
119: {
120: struct pcb *pcb = thread->pcb;
121:
122:
123: if (per_proc_info[cpu_number()].fpu_pcb == pcb)
124: {
125: per_proc_info[cpu_number()].fpu_pcb = (pcb_t)0;
126: }
127:
128: thread->pcb = 0;
129: zfree(pcb_zone, pcb);
130: }
131:
132: #define KF_SIZE (FM_SIZE+ARG_SIZE+FM_REDZONE)
133:
134: /*
135: * stack_attach: Attach a kernel stack to a thread.
136: */
137: void stack_attach(thread, stack, continuation)
138: register thread_t thread;
139: vm_offset_t stack;
140: void (*continuation)();
141: {
142: struct ppc_kernel_state *kss;
143: struct pcb *pcb = thread->pcb;
144:
145: #ifdef KDEBUG
146: if (continuation) {
147: KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED,MACH_STACK_ATTACH),
148: thread, thread->priority,
149: thread->sched_pri, continuation,
150: 0);
151: }
152: #endif
153: thread->kernel_stack = stack;
154: kss = STACK_IKS(stack);
155:
156: /*
157: * Build a kernel state area + arg frame on the stack for the initial
158: * switch into the thread. We also store a zero into the kernel
159: * stack pointer so the trap code knows there is already a frame
160: * on the kernel stack.
161: */
162:
163: kss->lr = (unsigned int) continuation;
164: kss->r1 = (vm_offset_t) ((int)kss - KF_SIZE);
165:
166: *((int*)kss->r1) = 0; /* Zero the frame backpointer */
167:
168: pcb->ksp = 0;
169: }
170:
171: vm_offset_t
172: stack_detach(
173: thread_t thread
174: )
175: {
176: vm_offset_t stack;
177:
178: stack = thread->kernel_stack;
179: thread->kernel_stack = 0;
180:
181: return (stack);
182: }
183:
184: /*
185: * stack_handoff: Move the current threads kernel stack to the new thread.
186: */
187: void
188: stack_handoff(
189: thread_t old,
190: thread_t new
191: )
192: {
193: vm_offset_t stack = stack_detach(old);
194:
195: KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED,MACH_STACK_HANDOFF),
196: old, new,
197: old->priority, old->sched_pri,
198: new->sched_pri);
199:
200: stack_attach(new, stack, 0);
201:
202: /*
203: * Change software state.
204: */
205: if (new->task != old->task) {
206: int mycpu = cpu_number();
207:
208: PMAP_DEACTIVATE(vm_map_pmap(old->task->map), old, mycpu);
209: PMAP_ACTIVATE(vm_map_pmap(new->task->map), new, mycpu);
210: pmap_switch(new->task->map->pmap);
211: }
212:
213: // current_thread() = new; // can't use this because it may be inlined!
214: cpu_data[cpu_number()].active_thread = new;
215: current_pcb() = new->pcb;
216: cpu_data[cpu_number()].flags = new->pcb->flags;
217:
218: #if NCPUS > 1
219: /* There is no free lunch!
220: * save the floating point state for the old thread
221: * if the fpu has been used since the last context switch
222: */
223: fp_state_save(old);
224:
225: #endif /* NCPUS > 1 */
226:
227: new->pcb->ksp = 0;
228:
229: }
230:
231: void
232: call_continuation(
233: void (*continuation)(void)
234: )
235: {
236: struct ppc_kernel_state *kss;
237: extern Call_continuation();
238: int tkss;
239:
240:
241: KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED,MACH_CALL_CONT),
242: current_thread(), current_thread()->priority,
243: current_thread()->sched_pri, continuation,
244: 0);
245:
246: kss = STACK_IKS(current_thread()->kernel_stack);
247:
248: *((int*)((int)kss - KF_SIZE)) = 0; /* Zero the frame backpointer */
249: tkss = (int)kss - KF_SIZE;
250:
251: Call_continuation(continuation, tkss);
252: }
253:
254:
255: /*
256: * switch_context: Switch from one thread to another.
257: */
258: thread_t
259: switch_context(
260: thread_t old,
261: void (*continuation)(void),
262: thread_t new
263: )
264: {
265: thread_t ret_thread;
266: extern thread_t Switch_context();
267: #ifdef KDEBUG
268: struct linkage_area *frame_ptr;
269: uint i;
270: uint lr[4];
271: #endif
272:
273: if (new->task != old->task) {
274: int mycpu = cpu_number();
275:
276: PMAP_DEACTIVATE(vm_map_pmap(old->task->map), old, mycpu);
277: PMAP_ACTIVATE(vm_map_pmap(new->task->map), new, mycpu);
278:
279: pmap_switch(new->task->map->pmap);
280: }
281:
282: // current_thread() = new; // can't use this because it may be inlined!
283: cpu_data[cpu_number()].active_thread = new;
284: //current_stack() = new->kernel_stack; // assembly does this
285: current_pcb()= new->pcb;
286: cpu_data[cpu_number()].flags = new->pcb->flags;
287:
288: #if NCPUS > 1
289: /* There is no free lunch!
290: * Save the floating point state for the old thread
291: * if the fpu has been used since the last context switch.
292: * Otherwise we need to broadcast an interrupt to the
293: * old fpu to get the state.
294: */
295: fp_state_save(old);
296:
297: #else
298: //disable_fpu();
299: #endif
300:
301: #ifdef KDEBUG
302: KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED,MACH_SCHED) | DBG_FUNC_END,
303: old, new,
304: old->priority, old->sched_pri,
305: new->sched_pri);
306:
307: frame_ptr = STACK_IKS(new->kernel_stack)->r1;
308: lr[0] = lr[1] = lr[2] = lr[3] = 0;
309: lr[0] = STACK_IKS(new->kernel_stack)->lr;
310: for (i=1;i<4;i++) {
311: if (frame_ptr == NULL) break;
312: lr[i] = frame_ptr->saved_lr;
313: frame_ptr = frame_ptr->saved_sp;
314: }
315: KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED,MACH_SCHED) | DBG_FUNC_START,
316: new, lr[0], lr[1], lr[2], lr[3]);
317:
318: lr[0] = lr[1] = lr[2] = lr[3] = 0;
319: for (i=0;i<4;i++) {
320: if (frame_ptr == NULL) break;
321: lr[i] = frame_ptr->saved_lr;
322: frame_ptr = frame_ptr->saved_sp;
323: }
324: if (lr[0]) {
325: KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED,MACH_SCHED),
326: 0, lr[0], lr[1], lr[2], lr[3]);
327: };
328: #endif
329: ret_thread = Switch_context(old, continuation, new);
330:
331: return(ret_thread);
332: }
333:
334: void
335: start_initial_context(
336: thread_t thread
337: )
338: {
339: struct pcb *pcb = thread->pcb;
340:
341: /*
342: * Change software state.
343: */
344:
345: PMAP_ACTIVATE(vm_map_pmap(thread->task->map), thread, 0);
346:
347: // current_thread() = thread; // can't use this because it may be inlined!
348: cpu_data[cpu_number()].active_thread = thread;
349: current_stack() = thread->kernel_stack;
350: current_pcb() = thread->pcb;
351: cpu_data[cpu_number()].flags = thread->pcb->flags;
352:
353: /*
354: * Change hardware state
355: */
356: load_context(thread);
357: /*NOTREACHED*/
358: }
359:
360: /*
361: * Duplicate parent state in child
362: * for U**X fork.
363: */
364: thread_dup(
365: thread_t parent,
366: thread_t child
367: )
368: {
369: struct ppc_saved_state *parent_state, *child_state;
370: struct ppc_float_state *parent_float_state, *child_float_state;
371: struct ppc_exception_state *parent_exception_state,
372: *child_exception_state;
373:
374: /* Save the FPU state */
375: if (per_proc_info[cpu_number()].fpu_pcb == parent->pcb) {
376: fp_state_save(parent);
377: }
378:
379: parent_state = &parent->pcb->ss;
380: child_state = &child->pcb->ss;
381:
382: /* rely on compiler structure assignment */
383: *child_state = *parent_state;
384:
385: parent_float_state = &parent->pcb->fs;
386: child_float_state = &child->pcb->fs;
387:
388: /* rely on compiler structure assignment */
389: *child_float_state = *parent_float_state;
390: #if 0
391: parent_exception_state = &parent->pcb->es;
392: child_exception_state = &child->pcb->es;
393:
394: /* rely on compiler structure assignment */
395: *child_exception_state = *parent_exception_state;
396: #endif
397: child_state->r3 = child->task->proc->p_pid;
398: child_state->r4 = 1;
399:
400: child_state->sr_copyin = child->pcb->sr0 + SR_COPYIN;
401: }
402:
403: /*
404: * Set thread integer state
405: */
406: kern_return_t
407: set_thread_state(
408: thread_t thread,
409: thread_state_t tstate,
410: unsigned int count
411: )
412: {
413: struct ppc_saved_state *saved_state;
414: struct ppc_thread_state *state;
415:
416: if (count < PPC_THREAD_STATE_COUNT)
417: return (KERN_INVALID_ARGUMENT);
418:
419: if (thread->task->kernel_privilege) {
420: /*
421: * State for kernel threads
422: * can only be set before thread
423: * is first started.
424: *
425: * XXX This hack is due to the
426: * fact that the &^%$#@! kernel loader
427: * uses the thread_set_state() call to
428: * start a thread in kernel mode.
429: */
430: if (thread->swap_func != thread_bootstrap_return)
431: return (KERN_INVALID_ARGUMENT);
432: }
433:
434: state = (struct ppc_thread_state *)tstate;
435: saved_state = &thread->pcb->ss;
436:
437: /*
438: * structure assignment - depends on
439: * ppc_thread_state being a prefix of ppc_saved_state !
440: */
441:
442: *((struct ppc_thread_state *)saved_state) = *state;
443:
444: saved_state->sr_copyin = thread->pcb->sr0 + SR_COPYIN;
445:
446: saved_state->srr1 |= MSR_EXPORT_MASK_SET;
447:
448: if (thread->task->kernel_privilege) {
449: saved_state->srr1 &= ~ MASK(MSR_PR);
450: thread_start(thread, state->srr0);
451: }
452:
453: return (KERN_SUCCESS);
454: }
455:
456: /*
457: * Set thread floating point state
458: */
459: kern_return_t
460: set_thread_fpstate(
461: thread_t thread,
462: thread_state_t tstate,
463: unsigned int count
464: )
465: {
466: struct ppc_float_state *state;
467:
468: if (count < PPC_FLOAT_STATE_COUNT)
469: return (KERN_INVALID_ARGUMENT);
470:
471: fpu_save();
472: fpu_disable();
473:
474: state = (struct ppc_float_state *)tstate;
475:
476: /* structure assignment */
477: thread->pcb->fs = *state;
478:
479: return (KERN_SUCCESS);
480: }
481:
482: /*
483: * Set thread exception point state
484: */
485: kern_return_t
486: set_thread_exstate(
487: thread_t thread,
488: thread_state_t tstate,
489: unsigned int count
490: )
491: {
492: struct ppc_exception_state *state;
493:
494: if (count < PPC_EXCEPTION_STATE_COUNT)
495: return (KERN_INVALID_ARGUMENT);
496:
497: state = (struct ppc_exception_state *)tstate;
498:
499: /* structure assignment */
500: thread->pcb->es = *state;
501:
502: return (KERN_SUCCESS);
503: }
504:
505: /*
506: * Set externally visible thread
507: * state.
508: */
509: kern_return_t
510: thread_setstatus(
511: thread_t thread,
512: int flavor,
513: thread_state_t tstate,
514: unsigned int count
515: )
516: {
517: switch (flavor) {
518:
519: case PPC_THREAD_STATE:
520: return (set_thread_state(thread, tstate, count));
521:
522: case PPC_FLOAT_STATE:
523: return (set_thread_fpstate(thread, tstate, count));
524:
525: case PPC_EXCEPTION_STATE:
526: return (set_thread_exstate(thread, tstate, count));
527:
528: default:
529: return (KERN_INVALID_ARGUMENT);
530: }
531: }
532:
533: /*
534: * Get thread state flavor list
535: */
536: kern_return_t
537: get_thread_state_flavor_list(
538: thread_state_t tstate,
539: unsigned int *count
540: )
541: {
542: struct thread_state_flavor *state;
543:
544: if (*count < PPC_THREAD_STATE_FLAVOR_LIST_COUNT)
545: return (KERN_INVALID_ARGUMENT);
546:
547: state = (struct thread_state_flavor *)tstate;
548:
549: state->flavor = PPC_THREAD_STATE;
550: state->count = PPC_THREAD_STATE_COUNT;
551:
552: (++state)->flavor = PPC_FLOAT_STATE;
553: state->count = PPC_FLOAT_STATE_COUNT;
554:
555: (++state)->flavor = PPC_EXCEPTION_STATE;
556: state->count = PPC_EXCEPTION_STATE_COUNT;
557:
558: *count = PPC_THREAD_STATE_FLAVOR_LIST_COUNT;
559:
560: return (KERN_SUCCESS);
561: }
562:
563: /*
564: * Get thread integer state
565: */
566: kern_return_t
567: get_thread_state(
568: thread_t thread,
569: thread_state_t tstate,
570: unsigned int *count
571: )
572: {
573: struct ppc_thread_state *saved_state;
574: struct ppc_thread_state *state;
575:
576: if (*count < PPC_THREAD_STATE_COUNT)
577: return (KERN_INVALID_ARGUMENT);
578:
579: state = (struct ppc_thread_state *)tstate;
580: saved_state = (struct ppc_thread_state *) &thread->pcb->ss;
581:
582: /*
583: * structure assignment - depends on
584: * ppc_thread_state being a prefix of ppc_saved_state !
585: */
586: *state = *((struct ppc_thread_state *)saved_state);
587:
588: *count = PPC_THREAD_STATE_COUNT;
589:
590: return (KERN_SUCCESS);
591: }
592:
593: /*
594: * Get thread floating point state
595: */
596: kern_return_t
597: get_thread_fpstate(
598: thread_t thread,
599: thread_state_t tstate,
600: unsigned int *count
601: )
602: {
603: struct ppc_float_state *state;
604:
605: if (*count < PPC_FLOAT_STATE_COUNT)
606: return (KERN_INVALID_ARGUMENT);
607:
608: fpu_save();
609: fpu_disable();
610:
611: state = (struct ppc_float_state *)tstate;
612:
613: /* structure assignment */
614: *state = thread->pcb->fs;
615:
616: *count = PPC_FLOAT_STATE_COUNT;
617:
618: return (KERN_SUCCESS);
619: }
620:
621: /*
622: * Get thread exception point state
623: */
624: kern_return_t
625: get_thread_exstate(
626: thread_t thread,
627: thread_state_t tstate,
628: unsigned int *count
629: )
630: {
631: struct ppc_exception_state *state;
632:
633: if (*count < PPC_EXCEPTION_STATE_COUNT)
634: return (KERN_INVALID_ARGUMENT);
635:
636: state = (struct ppc_exception_state *)tstate;
637:
638: /* structure assignment */
639: *state = thread->pcb->es;
640:
641: *count = PPC_EXCEPTION_STATE_COUNT;
642:
643: return (KERN_SUCCESS);
644: }
645:
646: /*
647: * Return externally visible
648: * thread status.
649: */
650: kern_return_t
651: thread_getstatus(
652: thread_t thread,
653: int flavor,
654: thread_state_t tstate,
655: unsigned int *count
656: )
657: {
658: switch (flavor) {
659:
660: case THREAD_STATE_FLAVOR_LIST:
661: return (get_thread_state_flavor_list(tstate, count));
662:
663: case PPC_THREAD_STATE:
664: return (get_thread_state(thread, tstate, count));
665:
666: case PPC_FLOAT_STATE:
667: return (get_thread_fpstate(thread, tstate, count));
668:
669: case PPC_EXCEPTION_STATE:
670: return (get_thread_exstate(thread, tstate, count));
671:
672: default:
673: return (KERN_INVALID_ARGUMENT);
674: }
675: }
676:
677: /*
678: * thread_userstack:
679: *
680: * Return the user stack pointer from the machine
681: * dependent thread state info.
682: */
683: kern_return_t
684: thread_userstack(
685: thread_t thread,
686: int flavor,
687: thread_state_t tstate,
688: unsigned int count,
689: vm_offset_t *user_stack
690: )
691: {
692: struct ppc_thread_state *state;
693:
694: /*
695: * Set a default.
696: */
697: if (*user_stack == 0)
698: *user_stack = USRSTACK;
699:
700: switch (flavor) {
701: case PPC_THREAD_STATE:
702: if (count < PPC_THREAD_STATE_COUNT)
703: return (KERN_INVALID_ARGUMENT);
704:
705: state = (struct ppc_thread_state *) tstate;
706:
707: /*
708: * If a valid user stack is specified, use it.
709: */
710: *user_stack = state->r1 ? state->r1: USRSTACK;
711: break;
712: default :
713: return (KERN_INVALID_ARGUMENT);
714: }
715:
716: return (KERN_SUCCESS);
717: }
718:
719: kern_return_t
720: thread_entrypoint(
721: thread_t thread,
722: int flavor,
723: thread_state_t tstate,
724: unsigned int count,
725: vm_offset_t *entry_point
726: )
727: {
728: struct ppc_thread_state *state;
729:
730: /*
731: * Set a default.
732: */
733: if (*entry_point == 0)
734: *entry_point = VM_MIN_ADDRESS;
735:
736: switch (flavor) {
737:
738: case PPC_THREAD_STATE:
739: if (count < PPC_THREAD_STATE_COUNT)
740: return (KERN_INVALID_ARGUMENT);
741:
742: state = (struct ppc_thread_state *) tstate;
743:
744: /*
745: * If a valid entry point is specified, use it.
746: */
747: *entry_point = state->srr0 ? state->srr0: VM_MIN_ADDRESS;
748: break;
749: default:
750: return (KERN_INVALID_ARGUMENT);
751: }
752:
753: return (KERN_SUCCESS);
754: }
755:
756:
757: void __volatile__
758: thread_syscall_return(
759: kern_return_t retval)
760: {
761: thread_t thread = current_thread();
762: struct ppc_saved_state *ssp = &thread->pcb->ss;
763:
764: ssp->r3 = retval;
765:
766: thread_exception_return();
767: /* NOTREACHED */
768: }
769:
770: void
771: thread_set_syscall_return(
772: thread_t thread,
773: kern_return_t retval)
774: {
775: struct ppc_saved_state *ssp = &thread->pcb->ss;
776:
777: ssp->r3 = retval;
778: }
779:
780: void
781: pmap_switch(pmap_t map)
782: {
783: unsigned int i;
784:
785: if (map->space == PPC_SID_KERNEL)
786: return;
787:
788: /* sr value has Ks=1, Ku=1, and vsid composed of space+seg num */
789: i = SEG_REG_PROT | (map->space << 4);
790:
791: isync(); /* context sync before */
792: /* mtsr(0x0, i + 0x0); SR0 is part of the kernel address space */
793: /* mtsr(0x1, i + 0x1); SR1 is part of the kernel address space */
794: /* mtsr(0x2, i + 0x2); SR2 is part of the kernel address space */
795: /* mtsr(0x3, i + 0x3); SR3 is part of the kernel address space */
796: mtsr(0x4, i + 0x4);
797: mtsr(0x5, i + 0x5);
798: mtsr(0x6, i + 0x6);
799: mtsr(0x7, i + 0x7);
800: mtsr(0x8, i + 0x8);
801: mtsr(0x9, i + 0x9);
802: mtsr(0xa, i + 0xa);
803: mtsr(0xb, i + 0xb);
804: mtsr(0xc, i + 0xc);
805: mtsr(0xd, i + 0xd);
806: mtsr(0xe, i + 0xe);
807: mtsr(0xf, i + 0xf);
808: isync(); /* context sync after */
809: }
810:
811: /*
812: * task_map_io_ports() is required by the driverkit routines.
813: */
814: kern_return_t
815: task_map_io_ports(
816: task_t task,
817: unsigned int port,
818: unsigned int length,
819: boolean_t unmap
820: )
821: {
822: return (KERN_SUCCESS);
823: }
824:
825:
826: #if MACH_ASSERT
827: void
828: dump_pcb(pcb_t pcb)
829: {
830: printf("pcb @ %8.8x:\n", pcb);
831: printf("ksp = 0x%08x\n\n",pcb->ksp);
832: #if DEBUG
833: regDump(&pcb->ss);
834: #endif /* DEBUG */
835: }
836:
837: void
838: dump_thread(thread_t th)
839: {
840: printf(" thread @ 0x%x:\n", th);
841: }
842: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.