nathanw_sa changes for sh3

Jason R Thorpe <[email protected]>
Newsgroups gmane.os.netbsd.ports.sh3
Organization Wasabi Systems, Inc.
Message-ID <[email protected]>
Tonight I wrote the sh3-specific changes for nathanw_sa for sh3.  The
kernel links, but I have not yet booted it (my test machine will be
a Dreamcast).

I'll do a test boot tomorrow, but I'd like to get some feedback from
folks who might be more familiar w/ SH than me.

My concerns:

	* changes to locore_subr.S follow register saving
	  rules.

	* cpu_setfunc() is correct

	* cpu_exit(): I'm worried that the stack changes in
	  the middle of this function.

Anyway, if it boots on my DC, I'll check it in, and then make the
other SH ports compile.

-- 
        -- Jason R. Thorpe <[email protected]>
sh3-sa-patch (text/plain, 52.5 KB)
Index: include/cpu.h
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/sh3/include/cpu.h,v
retrieving revision 1.29
diff -c -r1.29 cpu.h
*** include/cpu.h	2002/05/07 04:01:59	1.29
--- include/cpu.h	2002/06/21 06:11:17
***************
*** 80,85 ****
--- 80,86 ----
   */
  #define	cpu_swapin(p)			/* nothing */
  #define	cpu_swapout(p)			panic("cpu_swapout: can't get here");
+ #define	cpu_proc_fork(p1, p2)		/* nothing */
  
  /*
   * Arguments to hardclock and gatherstats encapsulate the previous
***************
*** 111,117 ****
  do {									\
  	want_resched = 1;						\
  	if (curproc != NULL)						\
! 		aston(curproc);						\
  } while (/*CONSTCOND*/0)
  
  /*
--- 112,118 ----
  do {									\
  	want_resched = 1;						\
  	if (curproc != NULL)						\
! 		aston(curproc->l_proc);					\
  } while (/*CONSTCOND*/0)
  
  /*
Index: include/frame.h
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/sh3/include/frame.h,v
retrieving revision 1.8
diff -c -r1.8 frame.h
*** include/frame.h	2002/05/09 12:25:41	1.8
--- include/frame.h	2002/06/21 06:11:17
***************
*** 44,49 ****
--- 44,50 ----
  #define	_SH3_FRAME_H_
  
  #include <sys/signal.h>
+ #include <sys/sa.h>
  
  /*
   * Exception Stack Frame
***************
*** 103,108 ****
--- 104,123 ----
  	struct	sigcontext *sf_scp;
  	sig_t	sf_handler;
  	struct	sigcontext sf_sc;
+ };
+ 
+ /*
+  * Scheduler activations upcall frame
+  */
+ struct saframe {
+ #if 0 /* in registers on entry to upcallcode */
+ 	int		sa_type;	/* r4 */
+ 	struct sa_t **	sa_sas;		/* r5 */
+ 	int		sa_events;	/* r6 */
+ 	int		sa_interrupted;	/* r7 */
+ #endif
+ 	void *		sa_arg;
+ 	sa_upcall_t	sa_upcall;
  };
  
  #endif /* !_SH3_FRAME_H_ */
Index: include/locore.h
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/sh3/include/locore.h,v
retrieving revision 1.7
diff -c -r1.7 locore.h
*** include/locore.h	2002/05/09 12:25:41	1.7
--- include/locore.h	2002/06/21 06:11:18
***************
*** 198,206 ****
  	ldc	Rm,	sr	/* unmask all interrupt */
  
  #ifndef _LOCORE
! void sh3_switch_setup(struct proc *);
! void sh4_switch_setup(struct proc *);
! void sh3_switch_resume(struct proc *);
! void sh4_switch_resume(struct proc *);
! extern void (*__sh_switch_resume)(struct proc *);
  #endif /* !_LOCORE */
--- 198,206 ----
  	ldc	Rm,	sr	/* unmask all interrupt */
  
  #ifndef _LOCORE
! void sh3_switch_setup(struct lwp *);
! void sh4_switch_setup(struct lwp *);
! void sh3_switch_resume(struct lwp *);
! void sh4_switch_resume(struct lwp *);
! extern void (*__sh_switch_resume)(struct lwp *);
  #endif /* !_LOCORE */
Index: include/proc.h
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/sh3/include/proc.h,v
retrieving revision 1.4
diff -c -r1.4 proc.h
*** include/proc.h	2002/05/09 12:28:08	1.4
--- include/proc.h	2002/06/21 06:11:18
***************
*** 38,43 ****
--- 38,44 ----
  
  #ifndef _SH3_PROC_H_
  #define	_SH3_PROC_H_
+ 
  /*
   * Machine-dependent part of the proc structure for sh3.
   */
***************
*** 48,64 ****
  	u_int32_t data;
  };
  
! struct mdproc {
  	struct trapframe *md_regs;	/* user context */
  	struct pcb *md_pcb;		/* pcb access address */
  	int md_flags;			/* machine-dependent flags */
  	/* u-area PTE: *2 .. SH4 data/address data array access */
  	struct md_upte md_upte[UPAGES * 2];
- 	__volatile int md_astpending;	/* AST pending on return to userland */
  };
  
  /* md_flags */
  #define	MDP_USEDFPU	0x0001	/* has used the FPU */
  
  #ifdef _KERNEL
  #ifndef _LOCORE
--- 49,68 ----
  	u_int32_t data;
  };
  
! struct mdlwp {
  	struct trapframe *md_regs;	/* user context */
  	struct pcb *md_pcb;		/* pcb access address */
  	int md_flags;			/* machine-dependent flags */
  	/* u-area PTE: *2 .. SH4 data/address data array access */
  	struct md_upte md_upte[UPAGES * 2];
  };
  
  /* md_flags */
  #define	MDP_USEDFPU	0x0001	/* has used the FPU */
+ 
+ struct mdproc {
+ 	__volatile int md_astpending;	/* AST pending on return to userland */
+ };
  
  #ifdef _KERNEL
  #ifndef _LOCORE
Index: include/userret.h
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/sh3/include/userret.h,v
retrieving revision 1.3
diff -c -r1.3 userret.h
*** include/userret.h	2002/05/09 12:31:19	1.3
--- include/userret.h	2002/06/21 06:11:18
***************
*** 46,55 ****
  #define	_SH3_USERRET_H_
  
  static __inline void
! userret(struct proc *p)
  {
  
! 	curcpu()->ci_schedstate.spc_curpriority = p->p_priority = p->p_usrpri;
  }
  
  #endif /* !_SH3_USERRET_H_ */
--- 46,69 ----
  #define	_SH3_USERRET_H_
  
  static __inline void
! userret(struct lwp *l)
  {
+ 	struct proc *p = l->l_proc;
+ 	int sig;
  
! 	/* Take pending signals. */
! 	while ((sig = CURSIG(l)) != 0)
! 		postsig(sig);
! 
! 	/* Invoke per-process kernel-exit handling, if any. */
! 	if (p->p_userret)
! 		(*p->p_userret)(l, p->p_userret_arg);
! 
! 	/* Invoke any pending upcalls. */
! 	if (l->l_flag & L_SA_UPCALL)
! 		sa_upcall_userret(l);
! 
! 	curcpu()->ci_schedstate.spc_curpriority = l->l_priority = l->l_usrpri;
  }
  
  #endif /* !_SH3_USERRET_H_ */
Index: sh3/Locore.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/sh3/sh3/Locore.c,v
retrieving revision 1.12
diff -c -r1.12 Locore.c
*** sh3/Locore.c	2002/05/09 12:28:08	1.12
--- sh3/Locore.c	2002/06/21 06:11:18
***************
*** 94,101 ****
  #include <sh3/mmu_sh3.h>
  #include <sh3/mmu_sh4.h>
  
! void (*__sh_switch_resume)(struct proc *);
! struct proc *cpu_switch_search(struct proc *);
  void idle(void);
  int want_resched;
  
--- 94,101 ----
  #include <sh3/mmu_sh3.h>
  #include <sh3/mmu_sh4.h>
  
! void (*__sh_switch_resume)(struct lwp *);
! struct lwp *cpu_switch_search(struct lwp *);
  void idle(void);
  int want_resched;
  
***************
*** 111,121 ****
   * struct proc *cpu_switch_search(struct proc *oldproc):
   *	Find the highest priority process.
   */
! struct proc *
! cpu_switch_search(struct proc *oldproc)
  {
  	struct prochd *q;
! 	struct proc *p;
  
  	curproc = 0;
  
--- 111,121 ----
   * struct proc *cpu_switch_search(struct proc *oldproc):
   *	Find the highest priority process.
   */
! struct lwp *
! cpu_switch_search(struct lwp *oldlwp)
  {
  	struct prochd *q;
! 	struct lwp *l;
  
  	curproc = 0;
  
***************
*** 127,146 ****
  	}
  
  	q = &sched_qs[ffs(sched_whichqs) - 1];
! 	p = q->ph_link;
! 	remrunqueue(p);
  	want_resched = 0;
  	SCHED_UNLOCK_IDLE();
  
! 	p->p_stat = SONPROC;
  
! 	if (p != oldproc) {
! 		curpcb = p->p_md.md_pcb;
! 		pmap_activate(p);
  	}
! 	curproc = p;
  
! 	return (p);
  }
  
  /*
--- 127,146 ----
  	}
  
  	q = &sched_qs[ffs(sched_whichqs) - 1];
! 	l = q->ph_link;
! 	remrunqueue(l);
  	want_resched = 0;
  	SCHED_UNLOCK_IDLE();
  
! 	l->l_stat = LSONPROC;
  
! 	if (l != oldlwp) {
! 		curpcb = l->l_md.md_pcb;
! 		pmap_activate(l);
  	}
! 	curproc = l;
  
! 	return (l);
  }
  
  /*
***************
*** 159,176 ****
  }
  
  /*
!  * Put process p on the run queue indicated by its priority.
!  * Calls should be made at splstatclock(), and p->p_stat should be SRUN.
   */
  void
! setrunqueue(struct proc *p)
  {
  	struct prochd *q;
! 	struct proc *oldlast;
! 	int which = p->p_priority >> 2;
  
  #ifdef DIAGNOSTIC
! 	if (p->p_back || which >= 32 || which < 0)
  		panic("setrunqueue");
  #endif
  	q = &sched_qs[which];
--- 159,176 ----
  }
  
  /*
!  * Put lwp p on the run queue indicated by its priority.
!  * Calls should be made at splstatclock(), and l->l_stat should be SRUN.
   */
  void
! setrunqueue(struct lwp *l)
  {
  	struct prochd *q;
! 	struct lwp *oldlast;
! 	int which = l->l_priority >> 2;
  
  #ifdef DIAGNOSTIC
! 	if (l->l_back || which >= 32 || which < 0)
  		panic("setrunqueue");
  #endif
  	q = &sched_qs[which];
***************
*** 178,225 ****
  	if (sched_whichqs == 0) {
  		panic("setrunqueue[whichqs == 0 ]");
  	}
! 	p->p_forw = (struct proc *)q;
! 	p->p_back = oldlast = q->ph_rlink;
! 	q->ph_rlink = p;
! 	oldlast->p_forw = p;
  }
  
  /*
!  * Remove process p from its run queue, which should be the one
   * indicated by its priority.
   * Calls should be made at splstatclock().
   */
  void
! remrunqueue(struct proc *p)
  {
! 	int which = p->p_priority >> 2;
  	struct prochd *q;
  
  #ifdef DIAGNOSTIC
  	if (!(sched_whichqs & (0x00000001 << which)))
  		panic("remrunqueue");
  #endif
! 	p->p_forw->p_back = p->p_back;
! 	p->p_back->p_forw = p->p_forw;
! 	p->p_back = NULL;
  	q = &sched_qs[which];
! 	if (q->ph_link == (struct proc *)q)
  		sched_whichqs &= ~(0x00000001 << which);
  }
  
  /*
!  * void sh3_switch_setup(struct proc *p):
   *	prepare kernel stack PTE table. TLB miss handler check these.
   */
  void
! sh3_switch_setup(struct proc *p)
  {
  	pt_entry_t *pte;
! 	struct md_upte *md_upte = p->p_md.md_upte;
  	u_int32_t vpn;
  	int i;
  
! 	vpn = (u_int32_t)p->p_addr;
  	vpn &= ~PGOFSET;
  	for (i = 0; i < UPAGES; i++, vpn += NBPG, md_upte++) {
  		pte = __pmap_kpte_lookup(vpn);
--- 178,225 ----
  	if (sched_whichqs == 0) {
  		panic("setrunqueue[whichqs == 0 ]");
  	}
! 	l->l_forw = (struct lwp *)q;
! 	l->l_back = oldlast = q->ph_rlink;
! 	q->ph_rlink = l;
! 	oldlast->l_forw = l;
  }
  
  /*
!  * Remove process l from its run queue, which should be the one
   * indicated by its priority.
   * Calls should be made at splstatclock().
   */
  void
! remrunqueue(struct lwp *l)
  {
! 	int which = l->l_priority >> 2;
  	struct prochd *q;
  
  #ifdef DIAGNOSTIC
  	if (!(sched_whichqs & (0x00000001 << which)))
  		panic("remrunqueue");
  #endif
! 	l->l_forw->l_back = l->l_back;
! 	l->l_back->l_forw = l->l_forw;
! 	l->l_back = NULL;
  	q = &sched_qs[which];
! 	if (q->ph_link == (struct lwp *)q)
  		sched_whichqs &= ~(0x00000001 << which);
  }
  
  /*
!  * void sh3_switch_setup(struct lwp *l):
   *	prepare kernel stack PTE table. TLB miss handler check these.
   */
  void
! sh3_switch_setup(struct lwp *l)
  {
  	pt_entry_t *pte;
! 	struct md_upte *md_upte = l->l_md.md_upte;
  	u_int32_t vpn;
  	int i;
  
! 	vpn = (u_int32_t)l->l_addr;
  	vpn &= ~PGOFSET;
  	for (i = 0; i < UPAGES; i++, vpn += NBPG, md_upte++) {
  		pte = __pmap_kpte_lookup(vpn);
***************
*** 231,248 ****
  }
  
  /*
!  * void sh4_switch_setup(struct proc *p):
   *	prepare kernel stack PTE table. sh4_switch_resume wired this PTE.
   */
  void
! sh4_switch_setup(struct proc *p)
  {
  	pt_entry_t *pte;
! 	struct md_upte *md_upte = p->p_md.md_upte;
  	u_int32_t vpn;
  	int i, e;
  
! 	vpn = (u_int32_t)p->p_addr;
  	vpn &= ~PGOFSET;
  	e = SH4_UTLB_ENTRY - UPAGES;
  	for (i = 0; i < UPAGES; i++, e++, vpn += NBPG) {
--- 231,248 ----
  }
  
  /*
!  * void sh4_switch_setup(struct lwp *l):
   *	prepare kernel stack PTE table. sh4_switch_resume wired this PTE.
   */
  void
! sh4_switch_setup(struct lwp *l)
  {
  	pt_entry_t *pte;
! 	struct md_upte *md_upte = l->l_md.md_upte;
  	u_int32_t vpn;
  	int i, e;
  
! 	vpn = (u_int32_t)l->l_addr;
  	vpn &= ~PGOFSET;
  	e = SH4_UTLB_ENTRY - UPAGES;
  	for (i = 0; i < UPAGES; i++, e++, vpn += NBPG) {
Index: sh3/exception.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/sh3/sh3/exception.c,v
retrieving revision 1.2
diff -c -r1.2 exception.c
*** sh3/exception.c	2002/06/17 16:33:17	1.2
--- sh3/exception.c	2002/06/21 06:11:19
***************
*** 55,64 ****
--- 55,67 ----
  #include <sys/param.h>
  #include <sys/systm.h>
  #include <sys/proc.h>
+ #include <sys/pool.h>
  #include <sys/user.h>
  #include <sys/kernel.h>
  #include <sys/signal.h>
  #include <sys/syscall.h>
+ #include <sys/sa.h>
+ #include <sys/savar.h>
  
  #ifdef KTRACE
  #include <sys/ktrace.h>
***************
*** 100,128 ****
  };
  const int exp_types = sizeof exp_type / sizeof exp_type[0];
  
! void general_exception(struct proc *, struct trapframe *);
! void tlb_exception(struct proc *, struct trapframe *, u_int32_t);
! void syscall(struct proc *, struct trapframe *);
! void ast(struct proc *, struct trapframe *);
  
  /*
!  * void general_exception(struct proc *p, struct trapframe *tf):
!  *	p  ... curproc when exception occur.
   *	tf ... full user context.
   */
  void
! general_exception(struct proc *p, struct trapframe *tf)
  {
  	int expevt = tf->tf_expevt;
  	boolean_t usermode = !KERNELMODE(tf->tf_ssr);
  
  	uvmexp.traps++;
  
! 	if (p == NULL)
   		goto do_panic;
  
  	if (usermode) {
! 		KDASSERT(p->p_md.md_regs == tf); /* check exception depth */
  		expevt |= EXP_USER;
  	}
  
--- 103,131 ----
  };
  const int exp_types = sizeof exp_type / sizeof exp_type[0];
  
! void general_exception(struct lwp *, struct trapframe *);
! void tlb_exception(struct lwp *, struct trapframe *, u_int32_t);
! void syscall(struct lwp *, struct trapframe *);
! void ast(struct lwp *, struct trapframe *);
  
  /*
!  * void general_exception(struct lwp *l, struct trapframe *tf):
!  *	l  ... curproc when exception occur.
   *	tf ... full user context.
   */
  void
! general_exception(struct lwp *l, struct trapframe *tf)
  {
  	int expevt = tf->tf_expevt;
  	boolean_t usermode = !KERNELMODE(tf->tf_ssr);
  
  	uvmexp.traps++;
  
! 	if (l == NULL)
   		goto do_panic;
  
  	if (usermode) {
! 		KDASSERT(l->l_md.md_regs == tf); /* check exception depth */
  		expevt |= EXP_USER;
  	}
  
***************
*** 130,146 ****
  	case EXPEVT_TRAPA | EXP_USER:
  		/* Check for debugger break */
  		if (_reg_read_4(SH_(TRA)) == (_SH_TRA_BREAK << 2)) {
! 			trapsignal(p, SIGTRAP, tf->tf_expevt);
  		} else {
! 			syscall(p, tf);
  			return;
  		}
  		break;
  	case EXPEVT_ADDR_ERR_LD:
  		/*FALLTHROUGH*/
  	case EXPEVT_ADDR_ERR_ST:
! 		KDASSERT(p->p_md.md_pcb->pcb_onfault != NULL);
! 		tf->tf_spc = (int)p->p_md.md_pcb->pcb_onfault;
  		if (tf->tf_spc == NULL)
  			goto do_panic;
  		break;
--- 133,149 ----
  	case EXPEVT_TRAPA | EXP_USER:
  		/* Check for debugger break */
  		if (_reg_read_4(SH_(TRA)) == (_SH_TRA_BREAK << 2)) {
! 			trapsignal(l, SIGTRAP, tf->tf_expevt);
  		} else {
! 			syscall(l, tf);
  			return;
  		}
  		break;
  	case EXPEVT_ADDR_ERR_LD:
  		/*FALLTHROUGH*/
  	case EXPEVT_ADDR_ERR_ST:
! 		KDASSERT(l->l_md.md_pcb->pcb_onfault != NULL);
! 		tf->tf_spc = (int)l->l_md.md_pcb->pcb_onfault;
  		if (tf->tf_spc == NULL)
  			goto do_panic;
  		break;
***************
*** 148,171 ****
  	case EXPEVT_ADDR_ERR_LD | EXP_USER:
  		/*FALLTHROUGH*/
  	case EXPEVT_ADDR_ERR_ST | EXP_USER:
! 		trapsignal(p, SIGSEGV, tf->tf_expevt);
  		break;
  
  	case EXPEVT_RES_INST | EXP_USER:
  		/*FALLTHROUGH*/
  	case EXPEVT_SLOT_INST | EXP_USER:
! 		trapsignal(p, SIGILL, tf->tf_expevt);
  		break;
  
  	case EXPEVT_BREAK | EXP_USER:
! 		trapsignal(p, SIGTRAP, tf->tf_expevt);
  		break;
  	default:
  		goto do_panic;
  	}
  
  	if (usermode)
! 		userret(p);
  	return;
  
   do_panic:
--- 151,174 ----
  	case EXPEVT_ADDR_ERR_LD | EXP_USER:
  		/*FALLTHROUGH*/
  	case EXPEVT_ADDR_ERR_ST | EXP_USER:
! 		trapsignal(l, SIGSEGV, tf->tf_expevt);
  		break;
  
  	case EXPEVT_RES_INST | EXP_USER:
  		/*FALLTHROUGH*/
  	case EXPEVT_SLOT_INST | EXP_USER:
! 		trapsignal(l, SIGILL, tf->tf_expevt);
  		break;
  
  	case EXPEVT_BREAK | EXP_USER:
! 		trapsignal(l, SIGTRAP, tf->tf_expevt);
  		break;
  	default:
  		goto do_panic;
  	}
  
  	if (usermode)
! 		userret(l);
  	return;
  
   do_panic:
***************
*** 191,204 ****
  }
  
  /*
!  * void syscall(struct proc *p, struct trapframe *tf):
!  *	p  ... curproc when exception occur.
   *	tf ... full user context.
   *	System call request from POSIX system call gate interface to kernel.
   */
  void
! syscall(struct proc *p, struct trapframe *tf)
  {
  	caddr_t params;
  	const struct sysent *callp;
  	int error, opc, nsys;
--- 194,208 ----
  }
  
  /*
!  * void syscall(struct lwp *l, struct trapframe *tf):
!  *	l  ... curproc when exception occur.
   *	tf ... full user context.
   *	System call request from POSIX system call gate interface to kernel.
   */
  void
! syscall(struct lwp *l, struct trapframe *tf)
  {
+ 	struct proc *p = l->l_proc;
  	caddr_t params;
  	const struct sysent *callp;
  	int error, opc, nsys;
***************
*** 292,310 ****
  	if (error)
  		goto bad;
  
! 	if ((error = trace_enter(p, code, args, rval)) != 0)
  		goto bad;
  
  	rval[0] = 0;
  	rval[1] = tf->tf_r1;
! 	error = (*callp->sy_call)(p, args, rval);
  	switch (error) {
  	case 0:
- 		/*
- 		 * Reinitialize proc pointer `p' as it may be different
- 		 * if this is a child returning from fork syscall.
- 		 */
- 		p = curproc;
  		tf->tf_r0 = rval[0];
  		tf->tf_r1 = rval[1];
  		tf->tf_ssr |= PSL_TBIT;	/* T bit */
--- 296,309 ----
  	if (error)
  		goto bad;
  
! 	if ((error = trace_enter(l, code, args, rval)) != 0)
  		goto bad;
  
  	rval[0] = 0;
  	rval[1] = tf->tf_r1;
! 	error = (*callp->sy_call)(l, args, rval);
  	switch (error) {
  	case 0:
  		tf->tf_r0 = rval[0];
  		tf->tf_r1 = rval[1];
  		tf->tf_ssr |= PSL_TBIT;	/* T bit */
***************
*** 329,347 ****
  	}
  
  
! 	trace_exit(p, code, args, rval, error);
  
! 	userret(p);
  }
  
  /*
!  * void tlb_exception(struct proc *p, struct trapframe *tf, u_int32_t va):
!  *	p  ... curproc when exception occur.
   *	tf ... full user context.
   *	va ... fault address.
   */
  void
! tlb_exception(struct proc *p, struct trapframe *tf, u_int32_t va)
  {
  #define	TLB_ASSERT(assert, msg)						\
  do {									\
--- 328,346 ----
  	}
  
  
! 	trace_exit(l, code, args, rval, error);
  
! 	userret(l);
  }
  
  /*
!  * void tlb_exception(struct lwp *l, struct trapframe *tf, u_int32_t va):
!  *	l  ... curproc when exception occur.
   *	tf ... full user context.
   *	va ... fault address.
   */
  void
! tlb_exception(struct lwp *l, struct trapframe *tf, u_int32_t va)
  {
  #define	TLB_ASSERT(assert, msg)						\
  do {									\
***************
*** 382,393 ****
  		TLB_ASSERT((int)va > 0,
  		    "kernel virtual protection fault (load)");
  		if (usermode) {
! 			trapsignal(p, SIGSEGV, tf->tf_expevt);
  			goto user_fault;
  		} else {
! 			TLB_ASSERT(p && p->p_md.md_pcb->pcb_onfault != NULL,
  			    "no copyin/out fault handler (load protection)");
! 			tf->tf_spc = (int)p->p_md.md_pcb->pcb_onfault;
  		}
  		return;
  
--- 381,392 ----
  		TLB_ASSERT((int)va > 0,
  		    "kernel virtual protection fault (load)");
  		if (usermode) {
! 			trapsignal(l, SIGSEGV, tf->tf_expevt);
  			goto user_fault;
  		} else {
! 			TLB_ASSERT(l && l->l_md.md_pcb->pcb_onfault != NULL,
  			    "no copyin/out fault handler (load protection)");
! 			tf->tf_spc = (int)l->l_md.md_pcb->pcb_onfault;
  		}
  		return;
  
***************
*** 399,416 ****
  
  	/* Select address space */
  	if (usermode) {
! 		TLB_ASSERT(p != NULL, "no curproc");
! 		map = &p->p_vmspace->vm_map;
  		pmap = map->pmap;
  	} else {
  		if ((int)va < 0) {
  			map = kernel_map;
  			pmap = pmap_kernel();
  		} else {
! 			TLB_ASSERT(va != 0 && p != NULL &&
! 			    p->p_md.md_pcb->pcb_onfault != NULL,
  			    "invalid user-space access from kernel mode");
! 			map = &p->p_vmspace->vm_map;
  			pmap = map->pmap;
  		}
  	}
--- 398,415 ----
  
  	/* Select address space */
  	if (usermode) {
! 		TLB_ASSERT(l != NULL, "no curproc");
! 		map = &l->l_proc->p_vmspace->vm_map;
  		pmap = map->pmap;
  	} else {
  		if ((int)va < 0) {
  			map = kernel_map;
  			pmap = pmap_kernel();
  		} else {
! 			TLB_ASSERT(va != 0 && l != NULL &&
! 			    l->l_md.md_pcb->pcb_onfault != NULL,
  			    "invalid user-space access from kernel mode");
! 			map = &l->l_proc->p_vmspace->vm_map;
  			pmap = map->pmap;
  		}
  	}
***************
*** 418,433 ****
  	/* Lookup page table. if entry found, load it. */
  	if (track && __pmap_pte_load(pmap, va, track)) {
  		if (usermode)
! 			userret(p);
  		return;
  	}
  
  	/* Page not found. call fault handler */
  	if (!usermode && pmap != pmap_kernel() &&
! 	    p->p_md.md_pcb->pcb_faultbail) {
! 		TLB_ASSERT(p->p_md.md_pcb->pcb_onfault != NULL,
  		    "no copyin/out fault handler (interrupt context)");
! 		tf->tf_spc = (int)p->p_md.md_pcb->pcb_onfault;
  		return;
  	}
  
--- 417,432 ----
  	/* Lookup page table. if entry found, load it. */
  	if (track && __pmap_pte_load(pmap, va, track)) {
  		if (usermode)
! 			userret(l);
  		return;
  	}
  
  	/* Page not found. call fault handler */
  	if (!usermode && pmap != pmap_kernel() &&
! 	    l->l_md.md_pcb->pcb_faultbail) {
! 		TLB_ASSERT(l->l_md.md_pcb->pcb_onfault != NULL,
  		    "no copyin/out fault handler (interrupt context)");
! 		tf->tf_spc = (int)l->l_md.md_pcb->pcb_onfault;
  		return;
  	}
  
***************
*** 435,443 ****
  
  	/* User stack extension */
  	if (map != kernel_map &&
! 	    (va >= (vaddr_t)p->p_vmspace->vm_maxsaddr) && (va < USRSTACK)) {
  		if (err == 0) {
! 			struct vmspace *vm = p->p_vmspace;
  			u_int32_t nss;
  			nss = btoc(USRSTACK - va);
  			if (nss > vm->vm_ssize)
--- 434,443 ----
  
  	/* User stack extension */
  	if (map != kernel_map &&
! 	    (va >= (vaddr_t)l->l_proc->p_vmspace->vm_maxsaddr) &&
! 	    (va < USRSTACK)) {
  		if (err == 0) {
! 			struct vmspace *vm = l->l_proc->p_vmspace;
  			u_int32_t nss;
  			nss = btoc(USRSTACK - va);
  			if (nss > vm->vm_ssize)
***************
*** 452,501 ****
  		boolean_t loaded = __pmap_pte_load(pmap, va, track);
  		TLB_ASSERT(loaded, "page table entry not found");
  		if (usermode)
! 			userret(p);
  		return;
  	}
  
  	/* Page not found. */
  	if (usermode) {
! 		trapsignal(p, err == ENOMEM ? SIGKILL : SIGSEGV, tf->tf_expevt);
  		goto user_fault;
  	} else {
! 		TLB_ASSERT(p->p_md.md_pcb->pcb_onfault,
  		    "no copyin/out fault handler (page not found)");
! 		tf->tf_spc = (int)p->p_md.md_pcb->pcb_onfault;
  	}
  	return;
  
   user_fault:
! 	userret(p);
! 	ast(p, tf);
  	return;
  
   tlb_panic:
  	panic("tlb_handler: %s va=0x%08x, ssr=0x%08x, spc=0x%08x"
! 	    "  proc=%p onfault=%p", panic_msg, va, tf->tf_ssr, tf->tf_spc,
! 	    p, p ? p->p_md.md_pcb->pcb_onfault : 0);
  #undef	TLB_ASSERT
  }
  
  /*
!  * void ast(struct proc *p, struct trapframe *tf):
!  *	p  ... curproc when exception occur.
   *	tf ... full user context.
   *	This is called when exception return. if return from kernel to user,
   *	handle asynchronous software traps and context switch if needed.
   */
  void
! ast(struct proc *p, struct trapframe *tf)
  {
! 	int sig;
  
  	if (KERNELMODE(tf->tf_ssr))
  		return;
! 	KDASSERT(p != NULL);
! 	KDASSERT(p->p_md.md_regs == tf);
  
  	while (p->p_md.md_astpending) {
  		uvmexp.softs++;
  		p->p_md.md_astpending = 0;
--- 452,503 ----
  		boolean_t loaded = __pmap_pte_load(pmap, va, track);
  		TLB_ASSERT(loaded, "page table entry not found");
  		if (usermode)
! 			userret(l);
  		return;
  	}
  
  	/* Page not found. */
  	if (usermode) {
! 		trapsignal(l, err == ENOMEM ? SIGKILL : SIGSEGV, tf->tf_expevt);
  		goto user_fault;
  	} else {
! 		TLB_ASSERT(l->l_md.md_pcb->pcb_onfault,
  		    "no copyin/out fault handler (page not found)");
! 		tf->tf_spc = (int)l->l_md.md_pcb->pcb_onfault;
  	}
  	return;
  
   user_fault:
! 	userret(l);
! 	ast(l, tf);
  	return;
  
   tlb_panic:
  	panic("tlb_handler: %s va=0x%08x, ssr=0x%08x, spc=0x%08x"
! 	    "  lwp=%p onfault=%p", panic_msg, va, tf->tf_ssr, tf->tf_spc,
! 	    l, l ? l->l_md.md_pcb->pcb_onfault : 0);
  #undef	TLB_ASSERT
  }
  
  /*
!  * void ast(struct lwp *l, struct trapframe *tf):
!  *	l  ... curproc when exception occur.
   *	tf ... full user context.
   *	This is called when exception return. if return from kernel to user,
   *	handle asynchronous software traps and context switch if needed.
   */
  void
! ast(struct lwp *l, struct trapframe *tf)
  {
! 	struct proc *p;
  
  	if (KERNELMODE(tf->tf_ssr))
  		return;
! 	KDASSERT(l != NULL);
! 	KDASSERT(l->p_md.md_regs == tf);
  
+ 	p = l->l_proc;
+ 
  	while (p->p_md.md_astpending) {
  		uvmexp.softs++;
  		p->p_md.md_astpending = 0;
***************
*** 505,520 ****
  			ADDUPROF(p);
  		}
  
- 		/* Take pending signals. */
- 		while ((sig = CURSIG(p)) != 0)
- 			postsig(sig);
- 
  		if (want_resched) {
  			/* We are being preempted. */
  			preempt(NULL);
  		}
  
! 		userret(p);
  	}
  }
  
--- 507,518 ----
  			ADDUPROF(p);
  		}
  
  		if (want_resched) {
  			/* We are being preempted. */
  			preempt(NULL);
  		}
  
! 		userret(l);
  	}
  }
  
***************
*** 527,541 ****
  void
  child_return(void *arg)
  {
! 	struct proc *p = arg;
! 	struct trapframe *tf = p->p_md.md_regs;
  
  	tf->tf_r0 = 0;
  	tf->tf_ssr |= PSL_TBIT; /* This indicates no error. */
  
! 	userret(p);
  #ifdef KTRACE
  	if (KTRPOINT(p, KTR_SYSRET))
  		ktrsysret(p, SYS_fork, 0, 0);
  #endif
  }
--- 525,577 ----
  void
  child_return(void *arg)
  {
! 	struct lwp *l = arg;
! #ifdef KTRACE
! 	struct proc *p = l->l_proc;
! #endif
! 	struct trapframe *tf = l->l_md.md_regs;
  
  	tf->tf_r0 = 0;
  	tf->tf_ssr |= PSL_TBIT; /* This indicates no error. */
  
! 	userret(l);
  #ifdef KTRACE
  	if (KTRPOINT(p, KTR_SYSRET))
  		ktrsysret(p, SYS_fork, 0, 0);
  #endif
+ }
+ 
+ /*
+  * void startlwp(void *arg):
+  *
+  *	Start a new LWP.
+  */
+ void
+ startlwp(void *arg)
+ {
+ 	ucontext_t *uc = arg;
+ 	struct lwp *l = curproc;
+ 	int error;
+ 
+ 	error = cpu_setmcontext(l, &uc->uc_mcontext, uc->uc_flags);
+ #ifdef DIAGNOSTIC
+ 	if (error)
+ 		printf("startlwp: error %d from cpu_setmcontext()", error);
+ #endif
+ 	pool_put(&lwp_uc_pool, uc);
+ 
+ 	userret(l);
+ }
+ 
+ /*
+  * void upcallret(struct lwp *l):
+  *
+  *	Perform userret() for an LWP.
+  *	XXX This is a terrible name.
+  */
+ void
+ upcallret(struct lwp *l)
+ {
+ 
+ 	userret(l);
  }
Index: sh3/genassym.cf
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/sh3/sh3/genassym.cf,v
retrieving revision 1.5
diff -c -r1.5 genassym.cf
*** sh3/genassym.cf	2002/05/09 12:29:16	1.5
--- sh3/genassym.cf	2002/06/21 06:11:19
***************
*** 67,82 ****
  define	TF_R0			offsetof(struct trapframe, tf_r0)
  define	TF_R15			offsetof(struct trapframe, tf_r15)
  
! define	P_ADDR			offsetof(struct proc, p_addr)
! define	P_BACK			offsetof(struct proc, p_back)
! define	P_FORW			offsetof(struct proc, p_forw)
! define	P_STAT			offsetof(struct proc, p_stat)
! define	P_WCHAN			offsetof(struct proc, p_wchan)
! define	P_MD			offsetof(struct proc, p_md)
  
! define	MD_UPTE			offsetof(struct mdproc, md_upte)
! define	MD_PCB			offsetof(struct mdproc,	md_pcb)
  
  define	SF_SIZE			sizeof(struct switchframe)
  define	SF_SR			offsetof(struct switchframe, sf_sr)
  define	SF_R15			offsetof(struct switchframe, sf_r15)
--- 67,85 ----
  define	TF_R0			offsetof(struct trapframe, tf_r0)
  define	TF_R15			offsetof(struct trapframe, tf_r15)
  
! define	L_ADDR			offsetof(struct lwp, l_addr)
! define	L_BACK			offsetof(struct lwp, l_back)
! define	L_FORW			offsetof(struct lwp, l_forw)
! define	L_STAT			offsetof(struct lwp, l_stat)
! define	L_WCHAN			offsetof(struct lwp, l_wchan)
  
! define	L_MD_UPTE		offsetof(struct lwp, l_md.md_upte)
! define	L_MD_PCB		offsetof(struct lwp, l_md.md_pcb)
  
+ #define	P_MD			offsetof(struct proc, p_md)
+ #define	MD_UPTE			offsetof(struct mdproc, md_upte)
+ #define	MD_PCB			offsetof(struct mdproc,	md_pcb)
+ 
  define	SF_SIZE			sizeof(struct switchframe)
  define	SF_SR			offsetof(struct switchframe, sf_sr)
  define	SF_R15			offsetof(struct switchframe, sf_r15)
***************
*** 93,102 ****
  define	SIGF_HANDLER		offsetof(struct sigframe, sf_handler)
  define	SIGF_SC			offsetof(struct sigframe, sf_sc)
  define	SC_EFLAGS		offsetof(struct sigcontext, sc_ssr)
  
! # can't include sys/proc.h directly.
! define	SONPROC			SONPROC
! define	SRUN			SRUN
  
  define	UVMEXP_INTRS		offsetof(struct uvmexp, intrs)
  
--- 96,106 ----
  define	SIGF_HANDLER		offsetof(struct sigframe, sf_handler)
  define	SIGF_SC			offsetof(struct sigframe, sf_sc)
  define	SC_EFLAGS		offsetof(struct sigcontext, sc_ssr)
+ 
+ define	SAF_UPCALL		offsetof(struct saframe, sa_upcall)
  
! define	LSONPROC		LSONPROC
! define	LSRUN			LSRUN
  
  define	UVMEXP_INTRS		offsetof(struct uvmexp, intrs)
  
Index: sh3/locore_subr.S
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/sh3/sh3/locore_subr.S,v
retrieving revision 1.10
diff -c -r1.10 locore_subr.S
*** sh3/locore_subr.S	2002/05/09 12:28:08	1.10
--- sh3/locore_subr.S	2002/06/21 06:11:19
***************
*** 48,54 ****
  	.text
  	.align 5	/* align cache line size (32B) */
  /*
!  * void cpu_switch(struct proc *):
   *	Find a runnable process and switch to it.  Wait if necessary.
   */
  ENTRY(cpu_switch)
--- 48,54 ----
  	.text
  	.align 5	/* align cache line size (32B) */
  /*
!  * void cpu_switch(struct lwp *):
   *	Find a runnable process and switch to it.  Wait if necessary.
   */
  ENTRY(cpu_switch)
***************
*** 79,84 ****
--- 79,85 ----
  	bt/s	1f
  	 mov	r0,	r4	/* new proc */
  
+ _L.doswitch:
  	/* Setup kernel stack */
  	mov.l	_L.SF,	r0
  	mov.l	@(r0, r4), r1		/* switch frame */
***************
*** 100,107 ****
  	__EXCEPTION_UNBLOCK(r0, r1)
  	/* Now OK to use kernel stack. */
  
  	/* Restore new process's context from switchframe */
! 1:	mov.l	_L.SF,	r0
  	mov.l	@(r0, r4), r1
  	add	#4,	r1		/* r15 already restored */
  	mov.l	@r1+,	r14
--- 101,116 ----
  	__EXCEPTION_UNBLOCK(r0, r1)
  	/* Now OK to use kernel stack. */
  
+ 	/* Return 1 indicating "we switched". */
+ 	bra	2f
+ 	 mov	#1, r2
+ 
+ 1:	/* Return 0 indicating "didn't switch". */
+ 	mov	#0, r2
+ 
  	/* Restore new process's context from switchframe */
! 	/* NOTE: r2 has return value! */
! 2:	mov.l	_L.SF,	r0
  	mov.l	@(r0, r4), r1
  	add	#4,	r1		/* r15 already restored */
  	mov.l	@r1+,	r14
***************
*** 114,126 ****
  	lds.l	@r1+,	pr
  	add	#4,	r1		/* r6_bank already restored */
  	ldc.l	@r1+,	sr
  	rts
! 	 nop
  	.align	2
! _L.SF:			.long	(P_MD + MD_PCB)
  _L.cpu_switch_search:	.long	_C_LABEL(cpu_switch_search)
  FUNC_SYMBOL(switch_resume)
  
  #ifdef SH3
  /*
   * void sh3_switch_resume(sturct proc *p)
--- 123,182 ----
  	lds.l	@r1+,	pr
  	add	#4,	r1		/* r6_bank already restored */
  	ldc.l	@r1+,	sr
+ 
+ 	/* r2 has the return value; stuff it into r0 now. */
  	rts
! 	 mov	r2, r0
  	.align	2
! _L.SF:			.long	(L_MD_PCB)
  _L.cpu_switch_search:	.long	_C_LABEL(cpu_switch_search)
  FUNC_SYMBOL(switch_resume)
  
+ /*
+  * void cpu_preempt(struct lwp *current, struct lwp *next)
+  *	Switch to the specified next LWP.
+  */
+ ENTRY(cpu_preempt)
+ 	/* Save current process's context to switchframe. */
+ 	mov.l	_L.SFp,	r0
+ 	mov.l	@(r0, r4), r1
+ 	add	#SF_SIZE, r1
+ 	stc.l	r7_bank,@-r1
+ 	stc.l	sr,	@-r1
+ 	stc.l	r6_bank,@-r1
+ 	sts.l	pr,	@-r1
+ 	mov.l	r8,	@-r1
+ 	mov.l	r9,	@-r1
+ 	mov.l	r10,	@-r1
+ 	mov.l	r11,	@-r1
+ 	mov.l	r12,	@-r1
+ 	mov.l	r13,	@-r1
+ 	mov.l	r14,	@-r1
+ 	mov.l	r15,	@-r1
+ 
+ 	/*
+ 	 * Don't need the outgoing LWP anymore.  Stash the incoming
+ 	 * LWP into a callee-saved register.
+ 	 */
+ 	mov	r5, r8
+ 
+ 	/* Unlink the new LWP from its run queue. */
+ 	mov.l	_L.remrunqueue, r0
+ 	jsr	@r0
+ 	 mov	r8, r4
+ 
+ 	/*
+ 	 * Put the incoming proc in r4 and jump into the middle
+ 	 * of cpu_switch(), and let it do the work to restore the
+ 	 * incoming LWP's context.
+ 	 */
+ 	bra	_L.doswitch
+ 	 mov	r8, r4
+ 
+ 	.align	2
+ _L.SFp:			.long	(L_MD_PCB)
+ _L.remrunqueue:		.long	_C_LABEL(remrunqueue)
+ 
  #ifdef SH3
  /*
   * void sh3_switch_resume(sturct proc *p)
***************
*** 211,217 ****
  _L.VPN_MASK:		.long	0xfffff000
  _L.P2BASE:		.long	0xa0000000
  #endif /* SH4 */
! _L.UPTE:		.long	(P_MD + MD_UPTE)
  
  /*
   * int _cpu_intr_raise(int s):
--- 267,273 ----
  _L.VPN_MASK:		.long	0xfffff000
  _L.P2BASE:		.long	0xa0000000
  #endif /* SH4 */
! _L.UPTE:		.long	(L_MD_UPTE)
  
  /*
   * int _cpu_intr_raise(int s):
***************
*** 356,361 ****
--- 412,436 ----
  	trapa	#0x80			/* exit if sigreturn fails */
  	.align	2
  _L.SYS___sigreturn14:	.long	SYS___sigreturn14
+ 
+ /*
+  * upcallcode:
+  *	Scheduler activation upcall trampoline.
+  *
+  * r4-r7 are the first 4 upcall arguments.  The rest of the arguments
+  * are on the stack in the right places.  Pointer to the upcall routine
+  * follows args.
+  */
+ NENTRY(upcallcode)
+ 	mov.l	@(SAF_UPCALL,r15), r0	/* fetch upcall routine.. */
+ 	jsr	@r0			/* ..and call it! */
+ 	 nop
+ 
+ 	/* Returned?!  Die! */
+ 	mov.l	_L.SYS_exit, r0
+ 	trapa	#0x80
+ 
+ 	.align	2
  _L.SYS_exit:		.long	SYS_exit
  	.globl	_C_LABEL(esigcode)
  _C_LABEL(esigcode):
Index: sh3/mem.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/sh3/sh3/mem.c,v
retrieving revision 1.11
diff -c -r1.11 mem.c
*** sh3/mem.c	2002/05/09 12:29:48	1.11
--- sh3/mem.c	2002/06/21 06:11:19
***************
*** 159,165 ****
  paddr_t
  mmmmap(dev_t dev, off_t off, int prot)
  {
! 	struct proc *p = curproc;
  
  	if (minor(dev) != DEV_MEM)
  		return (-1);
--- 159,165 ----
  paddr_t
  mmmmap(dev_t dev, off_t off, int prot)
  {
! 	struct proc *p = curproc->l_proc;
  
  	if (minor(dev) != DEV_MEM)
  		return (-1);
Index: sh3/pmap.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/sh3/sh3/pmap.c,v
retrieving revision 1.40
diff -c -r1.40 pmap.c
*** sh3/pmap.c	2002/05/09 12:28:08	1.40
--- sh3/pmap.c	2002/06/21 06:11:20
***************
*** 293,301 ****
  }
  
  void
! pmap_activate(struct proc *p)
  {
! 	pmap_t pmap = p->p_vmspace->vm_map.pmap;
  
  	if (pmap->pm_asid == -1)
  		pmap->pm_asid = __pmap_asid_alloc();
--- 293,301 ----
  }
  
  void
! pmap_activate(struct lwp *l)
  {
! 	pmap_t pmap = l->l_proc->p_vmspace->vm_map.pmap;
  
  	if (pmap->pm_asid == -1)
  		pmap->pm_asid = __pmap_asid_alloc();
***************
*** 305,311 ****
  }
  
  void
! pmap_deactivate(struct proc *p)
  {
  
  	/* Nothing to do */
--- 305,311 ----
  }
  
  void
! pmap_deactivate(struct lwp *l)
  {
  
  	/* Nothing to do */
Index: sh3/process_machdep.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/sh3/sh3/process_machdep.c,v
retrieving revision 1.5
diff -c -r1.5 process_machdep.c
*** sh3/process_machdep.c	2002/04/29 09:33:30	1.5
--- sh3/process_machdep.c	2002/06/21 06:11:20
***************
*** 76,94 ****
  #include <machine/psl.h>
  #include <machine/reg.h>
  
- static __inline struct trapframe *process_frame(struct proc *);
- 
  static __inline struct trapframe *
! process_frame(struct proc *p)
  {
  
! 	return (p->p_md.md_regs);
  }
  
  int
! process_read_regs(struct proc *p, struct reg *regs)
  {
! 	struct trapframe *tf = process_frame(p);
  
  	regs->r_spc = tf->tf_spc;
  	regs->r_ssr = tf->tf_ssr;
--- 76,92 ----
  #include <machine/psl.h>
  #include <machine/reg.h>
  
  static __inline struct trapframe *
! process_frame(struct lwp *l)
  {
  
! 	return (l->l_md.md_regs);
  }
  
  int
! process_read_regs(struct lwp *l, struct reg *regs)
  {
! 	struct trapframe *tf = process_frame(l);
  
  	regs->r_spc = tf->tf_spc;
  	regs->r_ssr = tf->tf_ssr;
***************
*** 116,124 ****
  }
  
  int
! process_write_regs(struct proc *p, struct reg *regs)
  {
! 	struct trapframe *tf = process_frame(p);
  
  	/*
  	 * Check for security violations.
--- 114,122 ----
  }
  
  int
! process_write_regs(struct lwp *l, struct reg *regs)
  {
! 	struct trapframe *tf = process_frame(l);
  
  	/*
  	 * Check for security violations.
***************
*** 154,161 ****
  }
  
  int
! process_sstep(p, sstep)
! 	struct proc *p;
  {
  
  	if (sstep)
--- 152,159 ----
  }
  
  int
! process_sstep(l, sstep)
! 	struct lwp *l;
  {
  
  	if (sstep)
***************
*** 165,173 ****
  }
  
  int
! process_set_pc(struct proc *p, caddr_t addr)
  {
! 	struct trapframe *tf = process_frame(p);
  
  	tf->tf_spc = (int)addr;
  
--- 163,171 ----
  }
  
  int
! process_set_pc(struct lwp *l, caddr_t addr)
  {
! 	struct trapframe *tf = process_frame(l);
  
  	tf->tf_spc = (int)addr;
  
Index: sh3/sh3_machdep.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/sh3/sh3/sh3_machdep.c,v
retrieving revision 1.41.6.1
diff -c -r1.41.6.1 sh3_machdep.c
*** sh3/sh3_machdep.c	2002/06/20 23:00:51	1.41.6.1
--- sh3/sh3_machdep.c	2002/06/21 06:11:20
***************
*** 90,95 ****
--- 90,97 ----
  #include <sys/mount.h>
  #include <sys/proc.h>
  #include <sys/signalvar.h>
+ #include <sys/sa.h>
+ #include <sys/savar.h>
  #include <sys/syscallargs.h>
  #include <sys/ucontext.h>
  #include <sys/user.h>
***************
*** 217,223 ****
  
  	/* Setup proc0 */
  	proc0paddr = (struct user *)u;
! 	proc0.p_addr = proc0paddr;
  	/*
  	 * u-area map:
  	 * |user| .... | ............... |
--- 219,225 ----
  
  	/* Setup proc0 */
  	proc0paddr = (struct user *)u;
! 	lwp0.l_addr = proc0paddr;
  	/*
  	 * u-area map:
  	 * |user| .... | ............... |
***************
*** 227,234 ****
  	 * stack top     ... r7_bank
  	 * current stack ... r15
  	 */
! 	curpcb = proc0.p_md.md_pcb = &proc0.p_addr->u_pcb;
! 	curupte = proc0.p_md.md_upte;
  
  	sf = &curpcb->pcb_sf;
  	sf->sf_r6_bank = u + NBPG;
--- 229,236 ----
  	 * stack top     ... r7_bank
  	 * current stack ... r15
  	 */
! 	curpcb = lwp0.l_md.md_pcb = &lwp0.l_addr->u_pcb;
! 	curupte = lwp0.l_md.md_upte;
  
  	sf = &curpcb->pcb_sf;
  	sf->sf_r6_bank = u + NBPG;
***************
*** 236,242 ****
  	__asm__ __volatile__("ldc %0, r6_bank" :: "r"(sf->sf_r6_bank));
  	__asm__ __volatile__("ldc %0, r7_bank" :: "r"(sf->sf_r7_bank));
  
! 	proc0.p_md.md_regs = (struct trapframe *)sf->sf_r6_bank - 1;
  #ifdef KSTACK_DEBUG
  	memset((char *)(u + sizeof(struct user)), 0x5a,
  	    NBPG - sizeof(struct user));
--- 238,244 ----
  	__asm__ __volatile__("ldc %0, r6_bank" :: "r"(sf->sf_r6_bank));
  	__asm__ __volatile__("ldc %0, r7_bank" :: "r"(sf->sf_r7_bank));
  
! 	lwp0.l_md.md_regs = (struct trapframe *)sf->sf_r6_bank - 1;
  #ifdef KSTACK_DEBUG
  	memset((char *)(u + sizeof(struct user)), 0x5a,
  	    NBPG - sizeof(struct user));
***************
*** 363,368 ****
--- 365,414 ----
  }
  
  /*
+  * void cpu_upcall(struct lwp *l, int type, int nevents, int ninterrupted,
+  *     void *sas, void *ap, void *sp, sa_upcall_t upcall):
+  *
+  * Send an upcall to userland.
+  */
+ void
+ cpu_upcall(struct lwp *l, int type, int nevents, int ninterrupted, void *sas,
+     void *ap, void *sp, sa_upcall_t upcall)
+ {
+ 	struct proc *p = l->l_proc;
+ 	struct trapframe *tf;
+ 	struct saframe *sf, frame;
+ 	extern char sigcode[], upcallcode[];
+ 
+ 	tf = l->l_md.md_regs;
+ 
+ 	/* Build the stack frame. */
+ #if 0 /* First 4 args in regs (see below). */
+ 	frame.sa_type = type;
+ 	frame.sa_sas = sas;
+ 	frame.sa_events = nevents;
+ 	frame.sa_interrupted = ninterrupted;
+ #endif
+ 	frame.sa_arg = ap;
+ 	frame.sa_upcall = upcall;
+ 
+ 	sf = (struct saframe *)sp - 1;
+ 	if (copyout(&frame, sf, sizeof(frame)) != 0) {
+ 		/* Copying onto the stack didn't work.  Die. */
+ 		sigexit(l, SIGILL);
+ 		/* NOTREACHED */
+ 	}
+ 
+ 	tf->tf_r4 = type;
+ 	tf->tf_r5 = (int) sas;
+ 	tf->tf_r6 = nevents;
+ 	tf->tf_r7 = ninterrupted;
+ 
+ 	tf->tf_spc = (int) ((caddr_t)p->p_sigctx.ps_sigcode +
+ 	    ((caddr_t)upcallcode - (caddr_t)sigcode));
+ 	tf->tf_r15 = (int) sf;
+ }
+ 
+ /*
   * Send an interrupt to process.
   *
   * Stack is set up to allow sigcode stored
***************
*** 375,386 ****
  void
  sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
  {
! 	struct proc *p = curproc;
  	struct trapframe *tf;
  	struct sigframe *fp, frame;
  	int onstack;
  
! 	tf = p->p_md.md_regs;
  
  	/* Do we need to jump onto the signal stack? */
  	onstack =
--- 421,433 ----
  void
  sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
  {
! 	struct lwp *l = curproc;
! 	struct proc *p = l->l_proc;
  	struct trapframe *tf;
  	struct sigframe *fp, frame;
  	int onstack;
  
! 	tf = l->l_md.md_regs;
  
  	/* Do we need to jump onto the signal stack? */
  	onstack =
***************
*** 434,440 ****
  		 * Process has trashed its stack; give it an illegal
  		 * instruction to halt it in its tracks.
  		 */
! 		sigexit(p, SIGILL);
  		/* NOTREACHED */
  	}
  
--- 481,487 ----
  		 * Process has trashed its stack; give it an illegal
  		 * instruction to halt it in its tracks.
  		 */
! 		sigexit(l, SIGILL);
  		/* NOTREACHED */
  	}
  
***************
*** 460,472 ****
   * a machine fault.
   */
  int
! sys___sigreturn14(struct proc *p, void *v, register_t *retval)
  {
  	struct sys___sigreturn14_args /* {
  		syscallarg(struct sigcontext *) sigcntxp;
  	} */ *uap = v;
  	struct sigcontext *scp, context;
  	struct trapframe *tf;
  
  	/*
  	 * The trampoline code hands us the context.
--- 507,520 ----
   * a machine fault.
   */
  int
! sys___sigreturn14(struct lwp *l, void *v, register_t *retval)
  {
  	struct sys___sigreturn14_args /* {
  		syscallarg(struct sigcontext *) sigcntxp;
  	} */ *uap = v;
  	struct sigcontext *scp, context;
  	struct trapframe *tf;
+ 	struct proc *p = l->l_proc;
  
  	/*
  	 * The trampoline code hands us the context.
***************
*** 478,484 ****
  		return (EFAULT);
  
  	/* Restore signal context. */
! 	tf = p->p_md.md_regs;
  
  	/* Check for security violations. */
  	if (((context.sc_ssr ^ tf->tf_ssr) & PSL_USERSTATIC) != 0)
--- 526,532 ----
  		return (EFAULT);
  
  	/* Restore signal context. */
! 	tf = l->l_md.md_regs;
  
  	/* Check for security violations. */
  	if (((context.sc_ssr ^ tf->tf_ssr) & PSL_USERSTATIC) != 0)
***************
*** 517,532 ****
  }
  
  void
! cpu_getmcontext(p, mcp, flags)
! 	struct proc *p;
  	mcontext_t *mcp;
  	unsigned int *flags;
  {
! 	const struct trapframe *tf = p->p_md.md_regs;
  	__greg_t *gr = mcp->__gregs;
  
  	/* Save register context. */
! 	gr[_REG_EXPEVT] = tf->tf_trapno;
  	gr[_REG_PC]     = tf->tf_spc;
  	gr[_REG_SR]     = tf->tf_ssr;
  	gr[_REG_MACL]   = tf->tf_macl;
--- 565,580 ----
  }
  
  void
! cpu_getmcontext(l, mcp, flags)
! 	struct lwp *l;
  	mcontext_t *mcp;
  	unsigned int *flags;
  {
! 	const struct trapframe *tf = l->l_md.md_regs;
  	__greg_t *gr = mcp->__gregs;
  
  	/* Save register context. */
! 	gr[_REG_EXPEVT] = tf->tf_expevt;
  	gr[_REG_PC]     = tf->tf_spc;
  	gr[_REG_SR]     = tf->tf_ssr;
  	gr[_REG_MACL]   = tf->tf_macl;
***************
*** 555,566 ****
  }
  
  int
! cpu_setmcontext(p, mcp, flags)
! 	struct proc *p;
  	const mcontext_t *mcp;
  	unsigned int flags;
  {
! 	struct trapframe *tf = p->p_md.md_regs;
  	const __greg_t *gr = mcp->__gregs;
  
  	/* Restore register context, if any. */
--- 603,614 ----
  }
  
  int
! cpu_setmcontext(l, mcp, flags)
! 	struct lwp *l;
  	const mcontext_t *mcp;
  	unsigned int flags;
  {
! 	struct trapframe *tf = l->l_md.md_regs;
  	const __greg_t *gr = mcp->__gregs;
  
  	/* Restore register context, if any. */
***************
*** 600,612 ****
   * Clear registers on exec
   */
  void
! setregs(struct proc *p, struct exec_package *pack, u_long stack)
  {
  	struct trapframe *tf;
  
! 	p->p_md.md_flags &= ~MDP_USEDFPU;
  
! 	tf = p->p_md.md_regs;
  
  	tf->tf_r0 = 0;
  	tf->tf_r1 = 0;
--- 648,660 ----
   * Clear registers on exec
   */
  void
! setregs(struct lwp *l, struct exec_package *pack, u_long stack)
  {
  	struct trapframe *tf;
  
! 	l->l_md.md_flags &= ~MDP_USEDFPU;
  
! 	tf = l->l_md.md_regs;
  
  	tf->tf_r0 = 0;
  	tf->tf_r1 = 0;
***************
*** 617,623 ****
  	tf->tf_r6 = stack + 4 * tf->tf_r4 + 8;	/* envp */
  	tf->tf_r7 = 0;
  	tf->tf_r8 = 0;
! 	tf->tf_r9 = (int)p->p_psstr;
  	tf->tf_r10 = 0;
  	tf->tf_r11 = 0;
  	tf->tf_r12 = 0;
--- 665,671 ----
  	tf->tf_r6 = stack + 4 * tf->tf_r4 + 8;	/* envp */
  	tf->tf_r7 = 0;
  	tf->tf_r8 = 0;
! 	tf->tf_r9 = (int)l->l_proc->p_psstr;
  	tf->tf_r10 = 0;
  	tf->tf_r11 = 0;
  	tf->tf_r12 = 0;
Index: sh3/sys_machdep.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/sh3/sh3/sys_machdep.c,v
retrieving revision 1.7
diff -c -r1.7 sys_machdep.c
*** sh3/sys_machdep.c	2002/05/10 15:28:45	1.7
--- sh3/sys_machdep.c	2002/06/21 06:11:20
***************
*** 43,52 ****
  #include <sys/param.h>
  #include <sys/systm.h>
  #include <sys/mount.h>
  #include <sys/syscallargs.h>
  
  int
! sys_sysarch(struct proc *p, void *v, register_t *retval)
  {
  	struct sys_sysarch_args __attribute__((__unused__)) *uap = v;
  
--- 43,53 ----
  #include <sys/param.h>
  #include <sys/systm.h>
  #include <sys/mount.h>
+ #include <sys/sa.h>
  #include <sys/syscallargs.h>
  
  int
! sys_sysarch(struct lwp *l, void *v, register_t *retval)
  {
  	struct sys_sysarch_args __attribute__((__unused__)) *uap = v;
  
Index: sh3/vm_machdep.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/sh3/sh3/vm_machdep.c,v
retrieving revision 1.33
diff -c -r1.33 vm_machdep.c
*** sh3/vm_machdep.c	2002/05/09 12:28:09	1.33
--- sh3/vm_machdep.c	2002/06/21 06:11:21
***************
*** 67,72 ****
--- 67,74 ----
  #include <sh3/mmu.h>
  #include <sh3/cache.h>
  
+ extern void proc_trampoline(void);
+ 
  /*
   * Finish a fork operation, with process p2 nearly set up.
   * Copy and update the pcb and trap frame, making the child ready to run.
***************
*** 86,105 ****
   * accordingly.
   */
  void
! cpu_fork(struct proc *p1, struct proc *p2, void *stack,
      size_t stacksize, void (*func)(void *), void *arg)
  {
- 	extern void proc_trampoline(void);
  	struct pcb *pcb;
  	struct trapframe *tf;
  	struct switchframe *sf;
  	vaddr_t spbase, fptop;
  #define	P1ADDR(x)	(SH3_PHYS_TO_P1SEG(*__pmap_kpte_lookup(x) & PG_PPN))
  
! 	KDASSERT(!(p1 != curproc && p1 != &proc0));
  
  	/* Copy flags */
! 	p2->p_md.md_flags = p1->p_md.md_flags;
  
  #ifdef SH3
  	/*
--- 88,106 ----
   * accordingly.
   */
  void
! cpu_lwp_fork(struct lwp *l1, struct lwp *l2, void *stack,
      size_t stacksize, void (*func)(void *), void *arg)
  {
  	struct pcb *pcb;
  	struct trapframe *tf;
  	struct switchframe *sf;
  	vaddr_t spbase, fptop;
  #define	P1ADDR(x)	(SH3_PHYS_TO_P1SEG(*__pmap_kpte_lookup(x) & PG_PPN))
  
! 	KDASSERT(!(l1 != curproc && l1 != &lwp0));
  
  	/* Copy flags */
! 	l2->l_md.md_flags = l1->l_md.md_flags;
  
  #ifdef SH3
  	/*
***************
*** 109,130 ****
  	 * cause virtual-aliasing.
  	 */
  	if (CPU_IS_SH3) {
! 		pcb = (struct pcb *)P1ADDR((vaddr_t)&p2->p_addr->u_pcb);
! 		p2->p_md.md_pcb = pcb;
  		fptop = (vaddr_t)pcb + NBPG;
  	}
  #endif /* SH3 */
  #ifdef SH4
  	/* SH4 can make wired entry, no need to convert to P1. */
  	if (CPU_IS_SH4) {
! 		pcb = &p2->p_addr->u_pcb;
! 		p2->p_md.md_pcb = pcb;
  		fptop = (vaddr_t)pcb + NBPG;
  	}
  #endif /* SH4 */
  
  	/* set up the kernel stack pointer */
! 	spbase = (vaddr_t)p2->p_addr + NBPG;
  #ifdef P1_STACK
  	/* Convert to P1 from P3 */
  	/*
--- 110,131 ----
  	 * cause virtual-aliasing.
  	 */
  	if (CPU_IS_SH3) {
! 		pcb = (struct pcb *)P1ADDR((vaddr_t)&l2->l_addr->u_pcb);
! 		l2->l_md.md_pcb = pcb;
  		fptop = (vaddr_t)pcb + NBPG;
  	}
  #endif /* SH3 */
  #ifdef SH4
  	/* SH4 can make wired entry, no need to convert to P1. */
  	if (CPU_IS_SH4) {
! 		pcb = &l2->l_addr->u_pcb;
! 		l2->l_md.md_pcb = pcb;
  		fptop = (vaddr_t)pcb + NBPG;
  	}
  #endif /* SH4 */
  
  	/* set up the kernel stack pointer */
! 	spbase = (vaddr_t)l2->l_addr + NBPG;
  #ifdef P1_STACK
  	/* Convert to P1 from P3 */
  	/*
***************
*** 132,148 ****
  	 * is accessed from P1 instead of P3.
  	 */
  	if (SH_HAS_VIRTUAL_ALIAS)
! 		sh_dcache_wbinv_range((vaddr_t)p2->p_addr, USPACE);
  	spbase = P1ADDR(spbase);
  #else /* P1_STACK */
  	/* Prepare u-area PTEs */
  #ifdef SH3
  	if (CPU_IS_SH3)
! 		sh3_switch_setup(p2);
  #endif
  #ifdef SH4
  	if (CPU_IS_SH4)
! 		sh4_switch_setup(p2);
  #endif
  #endif /* P1_STACK */
  
--- 133,149 ----
  	 * is accessed from P1 instead of P3.
  	 */
  	if (SH_HAS_VIRTUAL_ALIAS)
! 		sh_dcache_wbinv_range((vaddr_t)l2->l_addr, USPACE);
  	spbase = P1ADDR(spbase);
  #else /* P1_STACK */
  	/* Prepare u-area PTEs */
  #ifdef SH3
  	if (CPU_IS_SH3)
! 		sh3_switch_setup(l2);
  #endif
  #ifdef SH4
  	if (CPU_IS_SH4)
! 		sh4_switch_setup(l2);
  #endif
  #endif /* P1_STACK */
  
***************
*** 157,164 ****
  	/*
  	 * Copy the user context.
  	 */
! 	p2->p_md.md_regs = tf = (struct trapframe *)fptop - 1;
! 	memcpy(tf, p1->p_md.md_regs, sizeof(struct trapframe));
  
  	/*
  	 * If specified, give the child a different stack.
--- 158,165 ----
  	/*
  	 * Copy the user context.
  	 */
! 	l2->l_md.md_regs = tf = (struct trapframe *)fptop - 1;
! 	memcpy(tf, l1->l_md.md_regs, sizeof(struct trapframe));
  
  	/*
  	 * If specified, give the child a different stack.
***************
*** 182,204 ****
  	sf->sf_sr = PSL_MD;		/* kernel mode, interrupt enable */
  }
  
  /*
!  * void cpu_exit(sturct proc *p):
!  *	+ Change kernel context to proc0's one.
!  *	+ Schedule freeing process 'p' resources.
   *	+ switch to another process.
   */
  void
! cpu_exit(struct proc *p)
  {
  	struct switchframe *sf;
  
  	splsched();
  	uvmexp.swtch++;
  
! 	/* Switch to proc0 stack */
  	curproc = 0;
! 	curpcb = proc0.p_md.md_pcb;
  	sf = &curpcb->pcb_sf;
  	__asm__ __volatile__(
  		"mov	%0, r15;"	/* current stack */
--- 183,272 ----
  	sf->sf_sr = PSL_MD;		/* kernel mode, interrupt enable */
  }
  
+ /*
+  * void cpu_setfunc(struct lwp *l, void (*func)(void *), void *arg):
+  *	+ Reset the stack pointer for the process.
+  *	+ Arrange to the process to call the specified func
+  *	  with argument via the proc_trampoline.
+  *
+  *	XXX There is a lot of duplicated code here (with cpu_lwp_fork()).
+  */
+ void
+ cpu_setfunc(struct lwp *l, void (*func)(void *), void *arg)
+ {
+ 	struct pcb *pcb;
+ 	struct trapframe *tf;
+ 	struct switchframe *sf;
+ 	vaddr_t spbase;
+ 
+ #ifdef SH3
+ 	/*
+ 	 * Convert frame pointer top to P1. because SH3 can't make
+ 	 * wired TLB entry, context store space accessing must not cause
+ 	 * exception. For SH3, we are 4K page, P3/P1 conversion don't
+ 	 * cause virtual-aliasing.
+ 	 */
+ 	if (CPU_IS_SH3) {
+ 		pcb = (struct pcb *)P1ADDR((vaddr_t)&l->l_addr->u_pcb);
+ 	}
+ #endif /* SH3 */
+ #ifdef SH4
+ 	/* SH4 can make wired entry, no need to convert to P1. */
+ 	if (CPU_IS_SH4) {
+ 		pcb = &l->l_addr->u_pcb;
+ 	}
+ #endif /* SH4 */
+ 
+ 	/* set up the kernel stack pointer */
+ 	spbase = (vaddr_t)l->l_addr + NBPG;
+ #ifdef P1_STACK
+ 	/* Convert to P1 from P3 */
+ 	/*
+ 	 * wbinv u-area to avoid cache-aliasing, since kernel stack
+ 	 * is accessed from P1 instead of P3.
+ 	 *
+ 	 * XXX Is this needed here?
+ 	 */
+ 	if (SH_HAS_VIRTUAL_ALIAS)
+ 		sh_dcache_wbinv_range((vaddr_t)l2->l_addr, USPACE);
+ 	spbase = P1ADDR(spbase);
+ #else /* P1_STACK */
+ 	/* Don't need to set up u-area PTEs again. */
+ #endif /* P1_STACK */
+ 
+ 	/* Setup switch frame */
+ 	sf = &pcb->pcb_sf;
+ 	sf->sf_r11 = (int)arg;		/* proc_trampoline hook func */
+ 	sf->sf_r12 = (int)func;		/* proc_trampoline hook func's arg */
+ 	sf->sf_r15 = spbase + USPACE - NBPG;	/* current stack pointer */
+ 	sf->sf_r7_bank = sf->sf_r15;	/* stack top */
+ 	sf->sf_r6_bank = (vaddr_t)tf;	/* current frame pointer */
+ 	/* when switch to me, jump to proc_trampoline */
+ 	sf->sf_pr  = (int)proc_trampoline;
+ 	/*
+ 	 * Enable interrupt when switch frame is restored, since
+ 	 * kernel thread begin to run without restoring trapframe.
+ 	 */
+ 	sf->sf_sr = PSL_MD;		/* kernel mode, interrupt enable */
+ }
+ 
  /*
!  * void cpu_exit(struct lwp *l):
!  *	+ Change kernel context to lwp0's one.
!  *	+ Schedule freeing process 'l' resources.
   *	+ switch to another process.
   */
  void
! cpu_exit(struct lwp *l, int proc)
  {
  	struct switchframe *sf;
  
  	splsched();
  	uvmexp.swtch++;
  
! 	/* Switch to lwp0 stack */
  	curproc = 0;
! 	curpcb = lwp0.l_md.md_pcb;
  	sf = &curpcb->pcb_sf;
  	__asm__ __volatile__(
  		"mov	%0, r15;"	/* current stack */
***************
*** 210,218 ****
  		"r"(sf->sf_r7_bank));
  
  	/* Schedule freeing process resources */
! 	exit2(p);
  
! 	cpu_switch(p);
  	/* NOTREACHED */
  }
  
--- 278,289 ----
  		"r"(sf->sf_r7_bank));
  
  	/* Schedule freeing process resources */
! 	if (proc)
! 		exit2(l);
! 	else
! 		lwp_exit2(l);
  
! 	cpu_switch(l);
  	/* NOTREACHED */
  }
  
***************
*** 224,230 ****
  };
  
  int
! cpu_coredump(struct proc *p, struct vnode *vp, struct ucred *cred,
      struct core *chdr)
  {
  	struct md_core md_core;
--- 295,301 ----
  };
  
  int
! cpu_coredump(struct lwp *l, struct vnode *vp, struct ucred *cred,
      struct core *chdr)
  {
  	struct md_core md_core;
***************
*** 237,243 ****
  	chdr->c_cpusize = sizeof(md_core);
  
  	/* Save integer registers. */
! 	error = process_read_regs(p, &md_core.intreg);
  	if (error)
  		return error;
  
--- 308,314 ----
  	chdr->c_cpusize = sizeof(md_core);
  
  	/* Save integer registers. */
! 	error = process_read_regs(l, &md_core.intreg);
  	if (error)
  		return error;
  
***************
*** 248,260 ****
  
  	error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&cseg, chdr->c_seghdrsize,
  	    (off_t)chdr->c_hdrsize, UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred,
! 	    (int *)0, p);
  	if (error)
  		return error;
  
  	error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&md_core, sizeof(md_core),
  	    (off_t)(chdr->c_hdrsize + chdr->c_seghdrsize), UIO_SYSSPACE,
! 	    IO_NODELOCKED|IO_UNIT, cred, (int *)0, p);
  	if (error)
  		return error;
  
--- 319,331 ----
  
  	error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&cseg, chdr->c_seghdrsize,
  	    (off_t)chdr->c_hdrsize, UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred,
! 	    (int *)0, l->l_proc);
  	if (error)
  		return error;
  
  	error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&md_core, sizeof(md_core),
  	    (off_t)(chdr->c_hdrsize + chdr->c_seghdrsize), UIO_SYSSPACE,
! 	    IO_NODELOCKED|IO_UNIT, cred, (int *)0, l->l_proc);
  	if (error)
  		return error;
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.