Subject: Linux emulation bugs ...
To: None <port-i386@NetBSD.ORG>
From: Robert.V.Baron <rvb@gluck.coda.cs.cmu.edu>
List: port-i386
Date: 01/13/1998 12:52:00
Since we are on the topic of linux emulation, I'd like to point out
several problems with the existing linux emulation.  These turn up when
trying to get Caldera Wabi to work.  (This is a linux program that 
emulates the window 3.1 interface.)

First, major problems:
	When a signal is posted to a process, a frame is built which
is essentially a linux frame, BUT the signal type is not correct.  For
a particular hardware trap, linux will produce a different "code" and
SIG than NetBSD.  You must go back to the trap number and redo the
calculation then generate a linux frame.
	The linux frame has two locations for the stack pointer.  The
one we use is wrong.  It is the other one that a linux program sets
when it wants to change the stack frame on a sigreturn.
	Linux passes cr2 to a signal handler; NetBSD does not even store
it in the frame.

Second, amusing problems:
	Linux uses Global Selectors for a process CS/DS/SS rather than
Local Selectors.  NetBSD has both Global and Local Descriptors that map
the same memory.  It is necessary for wabi to use the Global descriptors.
This happens both in setregs and in posting a signal frame
	Linux can set a local segment descriptor to zero.  NetBSD can not.
	The linux stack is 8Meg vs 2Meg for NetBSD; programs that allocate
multiple stacks can need the whole 8Meg.
	Linux has a "cookie" associated with each signal.  This can be
used for wierd things like storing a different stack pointer for the
each handler.  (Wabi needs this since it runs in a segmented world,
but must handle signals in the traditional flat address space.)

These changes are below as a patch to NetBSD 1.3:

-------------------------------------------------------------------
Index: src/sys/arch/i386/i386/linux_machdep.c
diff -c src/sys/arch/i386/i386/linux_machdep.c:1.1.1.1 src/sys/arch/i386/i386/linux_machdep.c:1.2
*** src/sys/arch/i386/i386/linux_machdep.c:1.1.1.1	Thu Oct 16 09:30:28 1997
--- src/sys/arch/i386/i386/linux_machdep.c	Tue Jan 13 07:46:52 1998
***************
*** 93,98 ****
--- 93,153 ----
   * This means just signals for now, will include stuff like
   * I/O map permissions and V86 mode sometime.
   */
+ /* Note 254 & 255 are bogus entries*/
+ int trapno_to_x86vec[] = {
+ 		6,		/*  0 T_PRIVINFLT */
+ 		3,		/*  1 T_BPTFLT */
+ 		16,		/*  2 T_ARITHTRAP */
+ 		254,		/*  3 T_ASTFLT */
+ 		13,		/*  4 T_PROTFLT */
+ 		1,		/*  5 T_TRCTRAP */
+ 		14,		/*  6 T_PAGEFLT */
+ 		17,		/*  7 T_ALIGNFLT */
+ 		0,		/*  8 T_DIVIDE */
+ 		2,		/*  9 T_NMI */
+ 		4,		/* 10 T_OFLOW */
+ 		5,		/* 11 T_BOUND */
+ 		7,		/* 12 T_DNA */
+ 		8,		/* 13 T_DOUBLEFLT */
+ 		9,		/* 14 T_FPOPFLT */
+ 		10,		/* 15 T_TSSFLT */
+ 		11,		/* 16 T_SEGNPFLT */
+ 		12,		/* 17 T_STKFLT */
+ 		255		/* 18 T_RESERVED */
+ };
+ 
+ /* For the nmi and reserved below linux does not post a signal. */
+ int x86vec_to_linux_sig[] = {
+ 	SIGFPE,  SIGTRAP, /*nmi*/ SIGSEGV, SIGTRAP,
+ 	SIGSEGV, SIGSEGV, SIGILL, 	   SIGSEGV,
+ 	SIGSEGV, SIGFPE,  SIGSEGV,	   SIGBUS,
+ 	SIGBUS,  SIGSEGV, SIGSEGV, 	   /* reserved */ SIGSEGV,
+ 	SIGFPE,  SIGSEGV
+ };
+ 
+ /*
+  * Translate a NetBSD hardware signal to the corresponding
+  * linux signal.
+  */
+ void
+ linux_translate_signal(struct proc *p, int *signum, u_long *code);
+ 
+ void
+ linux_translate_signal(p, signum, code)
+ 	struct proc *p;
+ 	int *signum;
+ 	u_long *code;
+ {
+ 	register struct trapframe *tf = p->p_md.md_regs;
+ 
+ #define SIGHDW ((1<<SIGILL)|(1<<SIGTRAP)|(1<<SIGIOT)|(1<<SIGBUS)|(1<<SIGFPE)|(1<<SIGSEGV))
+ 
+ 	if (SIGHDW & (1<<*signum)) {
+ 		tf->tf_trapno = trapno_to_x86vec[tf->tf_trapno];
+ 		*code = tf->tf_trapno;
+ 		*signum=x86vec_to_linux_sig[tf->tf_trapno];
+ 	}
+ }
  
  /*
   * Send an interrupt to process.
***************
*** 104,110 ****
   * frame pointer, it returns to the user
   * specified pc, psl.
   */
- 
  void
  linux_sendsig(catcher, sig, mask, code)
  	sig_t catcher;
--- 159,164 ----
***************
*** 124,129 ****
--- 178,192 ----
  	/*
  	 * Allocate space for the signal handler context.
  	 */
+ 	/*
+ 	 * COMPAT_LINUX is using GDT entries NOT LDT entries
+ 	 */
+ #define USER_DS LSEL(LUDATA_SEL, SEL_UPL)
+ #define GUSER_DS GSEL(GUDATA_SEL, SEL_UPL)
+ 	if ((tf->tf_ss&0xffff) != GUSER_DS) {
+ 		fp = ((struct linux_sigframe *)
+ 			(((int)psp->ps_restorer[sig]) - 64*4));
+ 	} else
  	if ((psp->ps_flags & SAS_ALTSTACK) && !oonstack &&
  	    (psp->ps_sigonstack & sigmask(sig))) {
  		fp = (struct linux_sigframe *)(psp->ps_sigstk.ss_sp +
***************
*** 132,138 ****
  	} else {
  		fp = (struct linux_sigframe *)tf->tf_esp - 1;
  	}
! 
  	frame.sf_handler = catcher;
  	frame.sf_sig = bsd_to_linux_sig[sig];
  
--- 195,203 ----
  	} else {
  		fp = (struct linux_sigframe *)tf->tf_esp - 1;
  	}
! #ifdef	DEBUG
! printf("PROBLEM %d: eip/cs %x/%x -> ", code, tf->tf_eip, tf->tf_cs);
! #endif
  	frame.sf_handler = catcher;
  	frame.sf_sig = bsd_to_linux_sig[sig];
  
***************
*** 159,164 ****
--- 224,230 ----
  	frame.sf_sc.sc_edi = tf->tf_edi;
  	frame.sf_sc.sc_esi = tf->tf_esi;
  	frame.sf_sc.sc_ebp = tf->tf_ebp;
+ 	frame.sf_sc.sc_esp = tf->tf_esp;
  	frame.sf_sc.sc_ebx = tf->tf_ebx;
  	frame.sf_sc.sc_edx = tf->tf_edx;
  	frame.sf_sc.sc_ecx = tf->tf_ecx;
***************
*** 169,174 ****
--- 235,241 ----
  	frame.sf_sc.sc_ss = tf->tf_ss;
  	frame.sf_sc.sc_err = tf->tf_err;
  	frame.sf_sc.sc_trapno = tf->tf_trapno;
+ 	frame.sf_sc.sc_cr2 = p->p_addr->u_pcb.pcb_cr2;
  
  	if (copyout(&frame, fp, sizeof(frame)) != 0) {
  		/*
***************
*** 182,187 ****
--- 249,259 ----
  	/*
  	 * Build context to run handler in.
  	 */
+ 
+ 	/*
+ 	 * If setregs() were using the LDT entries for linux code,
+ 	 * we would use them here too, to be consistent.
+ 	 */
  	tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL);
  	tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL);
  	tf->tf_eip = (int)(((char *)PS_STRINGS) -
***************
*** 190,195 ****
--- 262,273 ----
  	tf->tf_eflags &= ~(PSL_T|PSL_VM|PSL_AC);
  	tf->tf_esp = (int)fp;
  	tf->tf_ss = GSEL(GUDATA_SEL, SEL_UPL);
+ 
+ #ifdef	DEBUG
+ 	printf("REVECTOR: eip/cs = %x/%x, handler %x\n",
+ 		tf->tf_eip, tf->tf_cs, frame.sf_handler);
+ 	printf("SENDSIG SENDSIG SENDSIG SENDSIG SENDSIG\n");
+ #endif
  }
  
  /*
***************
*** 256,273 ****
  	tf->tf_edi = context.sc_edi;
  	tf->tf_esi = context.sc_esi;
  	tf->tf_ebp = context.sc_ebp;
  	tf->tf_ebx = context.sc_ebx;
  	tf->tf_edx = context.sc_edx;
  	tf->tf_ecx = context.sc_ecx;
  	tf->tf_eax = context.sc_eax;
  	tf->tf_eip = context.sc_eip;
  	tf->tf_cs = context.sc_cs;
- 	tf->tf_esp = context.sc_esp_at_signal;
  	tf->tf_ss = context.sc_ss;
  
  	p->p_sigacts->ps_sigstk.ss_flags &= ~SS_ONSTACK;
  	p->p_sigmask = context.sc_mask & ~sigcantmask;
  
  	return (EJUSTRETURN);
  }
  
--- 334,355 ----
  	tf->tf_edi = context.sc_edi;
  	tf->tf_esi = context.sc_esi;
  	tf->tf_ebp = context.sc_ebp;
+ 	tf->tf_esp = context.sc_esp;
  	tf->tf_ebx = context.sc_ebx;
  	tf->tf_edx = context.sc_edx;
  	tf->tf_ecx = context.sc_ecx;
  	tf->tf_eax = context.sc_eax;
  	tf->tf_eip = context.sc_eip;
  	tf->tf_cs = context.sc_cs;
  	tf->tf_ss = context.sc_ss;
  
  	p->p_sigacts->ps_sigstk.ss_flags &= ~SS_ONSTACK;
  	p->p_sigmask = context.sc_mask & ~sigcantmask;
  
+ #ifdef	DEBUG
+ 	printf("RETURN: eip/cs = %x/%x esp/ss = %x/%x\n",
+ 		tf->tf_eip, tf->tf_cs, tf->tf_esp, tf->tf_ss);
+ #endif
  	return (EJUSTRETURN);
  }
  
***************
*** 342,359 ****
  		return (EINVAL);
  
  	sg = stackgap_init(p->p_emul);
! 
! 	sd.sd_lobase = ldt_info.base_addr & 0xffffff;
! 	sd.sd_hibase = (ldt_info.base_addr >> 24) & 0xff;
! 	sd.sd_lolimit = ldt_info.limit & 0xffff;
! 	sd.sd_hilimit = (ldt_info.limit >> 16) & 0xf;
! 	sd.sd_type =
! 	    16 | (ldt_info.contents << 2) | (!ldt_info.read_exec_only << 1);
! 	sd.sd_dpl = SEL_UPL;
! 	sd.sd_p = !ldt_info.seg_not_present;
! 	sd.sd_def32 = ldt_info.seg_32bit;
! 	sd.sd_gran = ldt_info.limit_in_pages;
! 
  	sl.start = ldt_info.entry_number;
  	sl.desc = stackgap_alloc(&sg, sizeof(sd));
  	sl.num = 1;
--- 424,444 ----
  		return (EINVAL);
  
  	sg = stackgap_init(p->p_emul);
! 	if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
! 		/* this means you should zero the ldt */
! 		 bzero(&sd, sizeof (struct segment_descriptor));
! 	} else {
! 		sd.sd_lobase = ldt_info.base_addr & 0xffffff;
! 		sd.sd_hibase = (ldt_info.base_addr >> 24) & 0xff;
! 		sd.sd_lolimit = ldt_info.limit & 0xffff;
! 		sd.sd_hilimit = (ldt_info.limit >> 16) & 0xf;
! 		sd.sd_type =
! 		    16 | (ldt_info.contents << 2) | (!ldt_info.read_exec_only << 1);
! 		sd.sd_dpl = SEL_UPL;
! 		sd.sd_p = !ldt_info.seg_not_present;
! 		sd.sd_def32 = ldt_info.seg_32bit;
! 		sd.sd_gran = ldt_info.limit_in_pages;
! 	}
  	sl.start = ldt_info.entry_number;
  	sl.desc = stackgap_alloc(&sg, sizeof(sd));
  	sl.num = 1;
Index: src/sys/arch/i386/i386/machdep.c
diff -c src/sys/arch/i386/i386/machdep.c:1.1.1.1 src/sys/arch/i386/i386/machdep.c:1.2
*** src/sys/arch/i386/i386/machdep.c:1.1.1.1	Mon Dec  8 07:24:52 1997
--- src/sys/arch/i386/i386/machdep.c	Tue Jan 13 07:46:53 1998
***************
*** 1,4 ****
! /*	$NetBSD: machdep.c,v 1.262.2.5 1997/12/08 05:10:31 thorpej Exp $	*/
  
  /*-
   * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
--- 1,4 ----
! /*	$NetBSD: machdep.c,v 1.262.2.4 1997/11/28 08:50:58 mellon Exp $	*/
  
  /*-
   * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
***************
*** 1388,1393 ****
--- 1388,1395 ----
  {
  	register struct pcb *pcb = &p->p_addr->u_pcb;
  	register struct trapframe *tf;
+ 	int data_seg, code_seg;
+ 	extern struct emul emul_linux_elf;
  
  #if NNPX > 0
  	/* If we were using the FPU, forget about it. */
***************
*** 1404,1413 ****
  	pcb->pcb_flags = 0;
  
  	tf = p->p_md.md_regs;
! 	__asm("movl %w0,%%gs" : : "r" (LSEL(LUDATA_SEL, SEL_UPL)));
! 	__asm("movl %w0,%%fs" : : "r" (LSEL(LUDATA_SEL, SEL_UPL)));
! 	tf->tf_es = LSEL(LUDATA_SEL, SEL_UPL);
! 	tf->tf_ds = LSEL(LUDATA_SEL, SEL_UPL);
  	tf->tf_edi = 0;
  	tf->tf_esi = 0;
  	tf->tf_ebp = 0;
--- 1406,1432 ----
  	pcb->pcb_flags = 0;
  
  	tf = p->p_md.md_regs;
! 
! #ifdef	COMPAT_LINUX
! 	/*
! 	 * What is happening here is that Wabi KNOWS that linux is using
! 	 * GDT entries: 23 & 2b;  So we must too.  Luckily GUCODE/GUDATA
! 	 * was 23/2b in NetBSD.
! 	 */
! 	if (pack->ep_emul == &emul_linux_elf) {
! 		code_seg = GSEL(GUCODE_SEL, SEL_UPL);
! 		data_seg = GSEL(GUDATA_SEL, SEL_UPL);
! 	} else {
! #endif
! 		code_seg = LSEL(LUCODE_SEL, SEL_UPL);
! 		data_seg = LSEL(LUDATA_SEL, SEL_UPL);
! #ifdef	COMPAT_LINUX
! 	}
! #endif
! 	__asm("movl %w0,%%gs" : : "r" (data_seg));
! 	__asm("movl %w0,%%fs" : : "r" (data_seg));
! 	tf->tf_es = data_seg;
! 	tf->tf_ds = data_seg;
  	tf->tf_edi = 0;
  	tf->tf_esi = 0;
  	tf->tf_ebp = 0;
***************
*** 1416,1425 ****
  	tf->tf_ecx = 0;
  	tf->tf_eax = 0;
  	tf->tf_eip = pack->ep_entry;
! 	tf->tf_cs = LSEL(LUCODE_SEL, SEL_UPL);
  	tf->tf_eflags = PSL_USERSET;
  	tf->tf_esp = stack;
! 	tf->tf_ss = LSEL(LUDATA_SEL, SEL_UPL);
  }
  
  /*
--- 1435,1444 ----
  	tf->tf_ecx = 0;
  	tf->tf_eax = 0;
  	tf->tf_eip = pack->ep_entry;
! 	tf->tf_cs = code_seg;
  	tf->tf_eflags = PSL_USERSET;
  	tf->tf_esp = stack;
! 	tf->tf_ss = data_seg;
  }
  
  /*
***************
*** 1429,1434 ****
--- 1448,1456 ----
  union descriptor static_gdt[NGDT], *gdt = static_gdt;
  union descriptor static_ldt[NLDT];
  struct gate_descriptor static_idt[NIDT], *idt = static_idt;
+ #ifdef	USER_LDT
+ struct segment_descriptor zsd;
+ #endif	/* USER_LDT */
  
  extern  struct user *proc0paddr;
  
Index: src/sys/arch/i386/i386/sys_machdep.c
diff -c src/sys/arch/i386/i386/sys_machdep.c:1.1.1.1 src/sys/arch/i386/i386/sys_machdep.c:1.2
*** src/sys/arch/i386/i386/sys_machdep.c:1.1.1.1	Thu Nov 13 08:33:22 1997
--- src/sys/arch/i386/i386/sys_machdep.c	Tue Jan 13 07:46:54 1998
***************
*** 140,145 ****
--- 140,147 ----
  #endif
  
  #ifdef USER_LDT
+ extern struct segment_descriptor zsd;
+ 
  /*
   * If the process has a local LDT, deallocate it, and restore the default from
   * proc0.     
***************
*** 275,280 ****
--- 277,285 ----
  		if ((error = copyin(&ua.desc[i], &desc, sizeof(desc))) != 0)
  			return (error);
  
+ 		if (!bcmp(&desc.sd, &zsd, sizeof (struct segment_descriptor)))
+ 			continue;
+ 
  		switch (desc.sd.sd_type) {
  		case SDT_SYSNULL:
  			desc.sd.sd_p = 0;
***************
*** 326,333 ****
  	for (i = 0, n = ua.start; i < ua.num; i++, n++) {
  		if ((error = copyin(&ua.desc[i], &desc, sizeof(desc))) != 0)
  			goto out;
! 
! 		pcb->pcb_ldt[n] = desc;
  	}
  
  	*retval = ua.start;
--- 331,340 ----
  	for (i = 0, n = ua.start; i < ua.num; i++, n++) {
  		if ((error = copyin(&ua.desc[i], &desc, sizeof(desc))) != 0)
  			goto out;
! 		if (!bcmp(&desc.sd, &zsd, sizeof (struct segment_descriptor)))
! 			bzero(&pcb->pcb_ldt[n], sizeof (union descriptor));
! 		else
! 			pcb->pcb_ldt[n] = desc;
  	}
  
  	*retval = ua.start;
Index: src/sys/arch/i386/i386/trap.c
diff -c src/sys/arch/i386/i386/trap.c:1.1.1.1 src/sys/arch/i386/i386/trap.c:1.2
*** src/sys/arch/i386/i386/trap.c:1.1.1.1	Thu Dec 11 07:26:42 1997
--- src/sys/arch/i386/i386/trap.c	Tue Jan 13 07:46:55 1998
***************
*** 1,4 ****
! /*	$NetBSD: trap.c,v 1.104.2.2 1997/12/09 19:59:54 thorpej Exp $	*/
  
  /*-
   * Copyright (c) 1995 Charles M. Hannum.  All rights reserved.
--- 1,4 ----
! /*	$NetBSD: trap.c,v 1.104.2.1 1997/11/13 19:00:15 mellon Exp $	*/
  
  /*-
   * Copyright (c) 1995 Charles M. Hannum.  All rights reserved.
***************
*** 79,88 ****
--- 79,91 ----
  #include <sys/exec.h>
  #include <compat/linux/linux_syscall.h>
  extern struct emul emul_linux_aout, emul_linux_elf;
+ void linux_translate_signal __P((struct proc *p, int *signum, u_long *code));
+ 
  #endif
  #ifdef COMPAT_FREEBSD
  extern struct emul emul_freebsd;
  #endif
+ void emul_trapsignal __P((struct proc *, int, u_long));
  
  #include "npx.h"
  
***************
*** 163,168 ****
--- 166,172 ----
  #ifdef DEBUG
  int	trapdebug = 0;
  #endif
+ int dont_step_on_user = 0;
  
  /*
   * trap(frame):
***************
*** 194,199 ****
--- 198,204 ----
  		    frame.tf_trapno, frame.tf_err, frame.tf_eip, frame.tf_cs,
  		    frame.tf_eflags, rcr2(), cpl);
  		printf("curproc %p\n", curproc);
+ 		delay(5000000);
  	}
  #endif
  
***************
*** 201,206 ****
--- 206,212 ----
  		type |= T_USER;
  		sticks = p->p_sticks;
  		p->p_md.md_regs = &frame;
+ 		p->p_addr->u_pcb.pcb_cr2 = 0;
  	}
  	else
  		sticks = 0;
***************
*** 298,309 ****
  	case T_STKFLT|T_USER:
  	case T_ALIGNFLT|T_USER:
  	case T_NMI|T_USER:
! 		trapsignal(p, SIGBUS, type &~ T_USER);
  		goto out;
  
  	case T_PRIVINFLT|T_USER:	/* privileged instruction fault */
  	case T_FPOPFLT|T_USER:		/* coprocessor operand fault */
! 		trapsignal(p, SIGILL, type &~ T_USER);
  		goto out;
  
  	case T_ASTFLT|T_USER:		/* Allow process switch */
--- 304,315 ----
  	case T_STKFLT|T_USER:
  	case T_ALIGNFLT|T_USER:
  	case T_NMI|T_USER:
! 		emul_trapsignal(p, SIGBUS, type &~ T_USER);
  		goto out;
  
  	case T_PRIVINFLT|T_USER:	/* privileged instruction fault */
  	case T_FPOPFLT|T_USER:		/* coprocessor operand fault */
! 		emul_trapsignal(p, SIGILL, type &~ T_USER);
  		goto out;
  
  	case T_ASTFLT|T_USER:		/* Allow process switch */
***************
*** 322,333 ****
  				goto trace;
  			return;
  		}
! 		trapsignal(p, rv, type &~ T_USER);
  		goto out;
  #else
  		printf("pid %d killed due to lack of floating point\n",
  		    p->p_pid);
! 		trapsignal(p, SIGKILL, type &~ T_USER);
  		goto out;
  #endif
  	}
--- 328,339 ----
  				goto trace;
  			return;
  		}
! 		emul_trapsignal(p, rv, type &~ T_USER);
  		goto out;
  #else
  		printf("pid %d killed due to lack of floating point\n",
  		    p->p_pid);
! 		emul_trapsignal(p, SIGKILL, type &~ T_USER);
  		goto out;
  #endif
  	}
***************
*** 335,345 ****
  	case T_BOUND|T_USER:
  	case T_OFLOW|T_USER:
  	case T_DIVIDE|T_USER:
! 		trapsignal(p, SIGFPE, type &~ T_USER);
  		goto out;
  
  	case T_ARITHTRAP|T_USER:
! 		trapsignal(p, SIGFPE, frame.tf_err);
  		goto out;
  
  	case T_PAGEFLT:			/* allow page faults in kernel mode */
--- 341,351 ----
  	case T_BOUND|T_USER:
  	case T_OFLOW|T_USER:
  	case T_DIVIDE|T_USER:
! 		emul_trapsignal(p, SIGFPE, type &~ T_USER);
  		goto out;
  
  	case T_ARITHTRAP|T_USER:
! 		emul_trapsignal(p, SIGFPE, frame.tf_err);
  		goto out;
  
  	case T_PAGEFLT:			/* allow page faults in kernel mode */
***************
*** 368,373 ****
--- 374,380 ----
  		extern vm_map_t kernel_map;
  		unsigned nss, v;
  
+ 		p->p_addr->u_pcb.pcb_cr2 = rcr2();
  		va = trunc_page((vm_offset_t)rcr2());
  		/*
  		 * It is only a kernel address space fault iff:
***************
*** 377,382 ****
--- 384,391 ----
  		 * The last can occur during an exec() copyin where the
  		 * argument space is lazy-allocated.
  		 */
+ 		if ((int)vm == 0)
+ 			goto we_re_toast;
  		if (type == T_PAGEFLT && va >= KERNBASE)
  			map = kernel_map;
  		else
***************
*** 443,449 ****
  			    map, va, ftype, rv);
  			goto we_re_toast;
  		}
! 		trapsignal(p, SIGSEGV, T_PAGEFLT);
  		break;
  	}
  
--- 452,464 ----
  			    map, va, ftype, rv);
  			goto we_re_toast;
  		}
! #ifdef	COMPAT_LINUX
! 		emul_trapsignal(p, (rv == KERN_PROTECTION_FAILURE
!  		    && (p->p_emul == &emul_linux_aout || p->p_emul == &emul_linux_elf))
! 					? SIGBUS : SIGSEGV, T_PAGEFLT);
! #else
! 		emul_trapsignal(p, SIGSEGV, T_PAGEFLT);
! #endif
  		break;
  	}
  
***************
*** 456,465 ****
  
  	case T_BPTFLT|T_USER:		/* bpt instruction fault */
  	case T_TRCTRAP|T_USER:		/* trace trap */
  #ifdef MATH_EMULATE
  	trace:
  #endif
! 		trapsignal(p, SIGTRAP, type &~ T_USER);
  		break;
  
  #include "isa.h"
--- 471,492 ----
  
  	case T_BPTFLT|T_USER:		/* bpt instruction fault */
  	case T_TRCTRAP|T_USER:		/* trace trap */
+ #ifdef DDB
+ 		if (dont_step_on_user) {
+ 			extern int db_run_mode;
+ 			#define STEP_RETURN 2
+ 			#define STEP_CALLT  3
+ 			if (db_run_mode != STEP_RETURN &&
+ 			    db_run_mode != STEP_CALLT)
+ 				printf ("Dont Step On User ... ");
+ 			if (kdb_trap (type & ~T_USER, 0, &frame))
+ 				return;
+ 		}
+ #endif
  #ifdef MATH_EMULATE
  	trace:
  #endif
! 		emul_trapsignal(p, SIGTRAP, type &~ T_USER);
  		break;
  
  #include "isa.h"
***************
*** 489,494 ****
--- 516,535 ----
  		return;
  out:
  	userret(p, frame.tf_eip, sticks);
+ }
+ 
+ void
+ emul_trapsignal(p, signum, code)
+ 	struct proc *p;
+ 	int signum;
+ 	u_long code;
+ {
+ 
+ #ifdef COMPAT_LINUX
+ 	if (p->p_emul == &emul_linux_aout || p->p_emul == &emul_linux_elf)
+ 		linux_translate_signal(p, &signum, &code);
+ #endif
+ 	trapsignal(p, signum, code);
  }
  
  /*
Index: src/sys/arch/i386/include/pcb.h
diff -c src/sys/arch/i386/include/pcb.h:1.1.1.1 src/sys/arch/i386/include/pcb.h:1.2
*** src/sys/arch/i386/include/pcb.h:1.1.1.1	Tue Jan  9 07:23:06 1996
--- src/sys/arch/i386/include/pcb.h	Tue Jan 13 07:46:58 1998
***************
*** 67,72 ****
--- 67,73 ----
          union	descriptor *pcb_ldt;	/* per process (user) LDT */
          int	pcb_ldt_len;		/*      number of LDT entries */
  	int	pcb_cr0;		/* saved image of CR0 */
+ 	int	pcb_cr2;		/* page fault address */
  	struct	save87 pcb_savefpu;	/* floating point state for 287/387 */
  	struct	emcsts pcb_saveemc;	/* Cyrix EMC state */
  /*
Index: src/sys/arch/i386/include/vmparam.h
diff -c src/sys/arch/i386/include/vmparam.h:1.1.1.1 src/sys/arch/i386/include/vmparam.h:1.2
*** src/sys/arch/i386/include/vmparam.h:1.1.1.1	Mon Oct 20 10:10:56 1997
--- src/sys/arch/i386/include/vmparam.h	Tue Jan 13 07:46:59 1998
***************
*** 68,74 ****
--- 68,78 ----
  #define	MAXDSIZ		(1*1024*1024*1024)	/* max data size */
  #endif
  #ifndef	DFLSSIZ
+ #ifdef	COMPAT_LINUX
+ #define	DFLSSIZ		(8*1024*1024)		/* initial stack size limit */
+ #else
  #define	DFLSSIZ		(2*1024*1024)		/* initial stack size limit */
+ #endif
  #endif
  #ifndef	MAXSSIZ
  #define	MAXSSIZ		(32*1024*1024)		/* max stack size */
Index: src/sys/arch/i386/isa/npx.c
diff -c src/sys/arch/i386/isa/npx.c:1.1.1.1 src/sys/arch/i386/isa/npx.c:1.2
*** src/sys/arch/i386/isa/npx.c:1.1.1.1	Thu Oct 16 09:30:55 1997
--- src/sys/arch/i386/isa/npx.c	Tue Jan 13 07:47:00 1998
***************
*** 65,70 ****
--- 65,72 ----
  #include <dev/isa/isavar.h>
  #include <i386/isa/icu.h>
  
+ void emul_trapsignal __P((struct proc *, int, u_long));
+ 
  /*
   * 387 and 287 Numeric Coprocessor Extension (NPX) Driver.
   *
***************
*** 446,452 ****
  #else
  		code = 0;	/* XXX */
  #endif
! 		trapsignal(p, SIGFPE, code);
  	} else {
  		/*
  		 * Nested interrupt.  These losers occur when:
--- 448,454 ----
  #else
  		code = 0;	/* XXX */
  #endif
! 		emul_trapsignal(p, SIGFPE, code);
  	} else {
  		/*
  		 * Nested interrupt.  These losers occur when:
Index: src/sys/compat/linux/linux_exec.c
diff -c src/sys/compat/linux/linux_exec.c:1.1.1.1 src/sys/compat/linux/linux_exec.c:1.2
*** src/sys/compat/linux/linux_exec.c:1.1.1.1	Mon Oct 14 12:31:27 1996
--- src/sys/compat/linux/linux_exec.c	Tue Jan 13 07:47:05 1998
***************
*** 446,452 ****
--- 446,456 ----
  		free(bp, M_TEMP);
  	}
  	epp->ep_emul = &emul_linux_elf;
+ #ifdef	someday
+ 	*pos = 0x40000000;		/* just like linux */
+ #else
  	*pos = ELF32_NO_ADDR;
+ #endif
  	return 0;
  }
  
Index: src/sys/compat/linux/linux_ioctl.c
diff -c src/sys/compat/linux/linux_ioctl.c:1.1.1.1 src/sys/compat/linux/linux_ioctl.c:1.2
*** src/sys/compat/linux/linux_ioctl.c:1.1.1.1	Sat Apr  5 08:02:31 1997
--- src/sys/compat/linux/linux_ioctl.c	Tue Jan 13 07:47:05 1998
***************
*** 36,42 ****
  #include <sys/systm.h>
  #include <sys/ioctl.h>
  #include <sys/mount.h>
! 
  #include <sys/socket.h>
  #include <net/if.h>
  #include <sys/sockio.h>
--- 36,43 ----
  #include <sys/systm.h>
  #include <sys/ioctl.h>
  #include <sys/mount.h>
! #include <sys/file.h>
! #include <sys/filedesc.h>
  #include <sys/socket.h>
  #include <net/if.h>
  #include <sys/sockio.h>
***************
*** 51,56 ****
--- 52,58 ----
  #include <compat/ossaudio/ossaudio.h>
  #define LINUX_TO_OSS(v) (v)	/* do nothing, same ioctl() encoding */
  
+ int linux_fdioctl __P((dev_t dev, u_long cmd, caddr_t addr, struct proc *p));
  /*
   * Most ioctl command are just converted to their NetBSD values,
   * and passed on. The ones that take structure pointers and (flag)
***************
*** 69,76 ****
  		syscallarg(u_long) com;
  		syscallarg(caddr_t) data;
  	} */ *uap = v;
! 
! 	switch (LINUX_IOCGROUP(SCARG(uap, com))) {
  	case 'M':
  		return oss_ioctl_mixer(p, LINUX_TO_OSS(v), retval);
  	case 'Q':
--- 71,79 ----
  		syscallarg(u_long) com;
  		syscallarg(caddr_t) data;
  	} */ *uap = v;
! 	u_long com = SCARG(uap, com);
!   
! 	switch (LINUX_IOCGROUP(com)) {
  	case 'M':
  		return oss_ioctl_mixer(p, LINUX_TO_OSS(v), retval);
  	case 'Q':
***************
*** 81,87 ****
--- 84,190 ----
  		return linux_ioctl_termios(p, uap, retval);
  	case 0x89:
  		return linux_ioctl_socket(p, uap, retval);
+ 	case 0: {
+ 		struct filedesc *fdp = p->p_fd;
+ 		struct file *fp;
+ 		switch(com & 0xff) {
+ 		case 3:
+ 			if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles ||
+ 			    (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL ||
+ 			    (fp->f_type == DTYPE_SOCKET))
+ 			    	return (EBADF);
+ 			/* I should verify this vnode is a fd inode ... */
+ 			/* Of course I'd also like the op to work to a
+ 			   file that is a floppy image ... */
+ 			/* Finally, first arg should be a dev not fp ... */
+ 			return (linux_fdioctl(0, com, SCARG(uap, data), p));
+ 		}
+ 	}
  	default:
  		return linux_machdepioctl(p, uap, retval);
  	}
+ }
+ 
+ /*
+  * Geometry
+  */
+ struct floppy_struct {
+ 	unsigned int	size,		/* nr of sectors total */
+ 			sect,		/* sectors per track */
+ 			head,		/* nr of heads */
+ 			track,		/* nr of tracks */
+ 			stretch;	/* !=0 means double track steps */
+ 	unsigned char	gap,		/* gap1 size */
+ 			rate,		/* data rate. |= 0x40 perpendicular */
+ 			spec1,		/* stepping rate, head unload time */
+ 			fmt_gap;	/* gap2 size */
+ 	const char	* name; /* used only for predefined formats */
+ };
+ 
+ /*
+  * This struct defines the different floppy types.
+  *
+  * Bit 0 of 'stretch' tells if the tracks need to be doubled for some
+  * types (e.g. 360kB diskette in 1.2MB drive, etc.).  Bit 1 of 'stretch'
+  * tells if the disk is in Commodore 1581 format, which means side 0 sectors
+  * are located on side 1 of the disk but with a side 0 ID, and vice-versa.
+  * This is the same as the Sharp MZ-80 5.25" CP/M disk format, except that the
+  * 1581's logical side 0 is on physical side 1, whereas the Sharp's logical
+  * side 0 is on physical side 0 (but with the misnamed sector IDs).
+  * 'stretch' should probably be renamed to something more general, like
+  * 'options'.  Other parameters should be self-explanatory (see also
+  * setfdprm(8)).
+  */
+ static struct floppy_struct floppy_type[32] = {
+ 	{    0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL    },	/*  0 no testing    */
+ 	{  720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"d360"  }, /*  1 360KB PC      */
+ 	{ 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"h1200" },	/*  2 1.2MB AT      */
+ 	{  720, 9,1,80,0,0x2A,0x02,0xDF,0x50,"D360"  },	/*  3 360KB SS 3.5" */
+ 	{ 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"D720"  },	/*  4 720KB 3.5"    */
+ 	{  720, 9,2,40,1,0x23,0x01,0xDF,0x50,"h360"  },	/*  5 360KB AT      */
+ 	{ 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,"h720"  },	/*  6 720KB AT      */
+ 	{ 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"H1440" },	/*  7 1.44MB 3.5"   */
+ 	{ 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"E2880" },	/*  8 2.88MB 3.5"   */
+ 	{ 6240,39,2,80,0,0x1B,0x43,0xAF,0x28,"E3120"},	/*  9 3.12MB 3.5"   */
+ 
+ 	{ 2880,18,2,80,0,0x25,0x00,0xDF,0x02,"h1440" }, /* 10 1.44MB 5.25"  */
+ 	{ 3360,21,2,80,0,0x1C,0x00,0xCF,0x0C,"H1680" }, /* 11 1.68MB 3.5"   */
+ 	{  820,10,2,41,1,0x25,0x01,0xDF,0x2E,"h410"  },	/* 12 410KB 5.25"   */
+ 	{ 1640,10,2,82,0,0x25,0x02,0xDF,0x2E,"H820"  },	/* 13 820KB 3.5"    */
+ 	{ 2952,18,2,82,0,0x25,0x00,0xDF,0x02,"h1476" },	/* 14 1.48MB 5.25"  */
+ 	{ 3444,21,2,82,0,0x25,0x00,0xDF,0x0C,"H1722" },	/* 15 1.72MB 3.5"   */
+ 	{  840,10,2,42,1,0x25,0x01,0xDF,0x2E,"h420"  },	/* 16 420KB 5.25"   */
+ 	{ 1660,10,2,83,0,0x25,0x02,0xDF,0x2E,"H830"  },	/* 17 830KB 3.5"    */
+ 	{ 2988,18,2,83,0,0x25,0x00,0xDF,0x02,"h1494" },	/* 18 1.49MB 5.25"  */
+ 	{ 3486,21,2,83,0,0x25,0x00,0xDF,0x0C,"H1743" }, /* 19 1.74 MB 3.5"  */
+ 
+ 	{ 1760,11,2,80,0,0x1C,0x09,0xCF,0x00,"h880"  }, /* 20 880KB 5.25"   */
+ 	{ 2080,13,2,80,0,0x1C,0x01,0xCF,0x00,"D1040" }, /* 21 1.04MB 3.5"   */
+ 	{ 2240,14,2,80,0,0x1C,0x19,0xCF,0x00,"D1120" }, /* 22 1.12MB 3.5"   */
+ 	{ 3200,20,2,80,0,0x1C,0x20,0xCF,0x2C,"h1600" }, /* 23 1.6MB 5.25"   */
+ 	{ 3520,22,2,80,0,0x1C,0x08,0xCF,0x2e,"H1760" }, /* 24 1.76MB 3.5"   */
+ 	{ 3840,24,2,80,0,0x1C,0x20,0xCF,0x00,"H1920" }, /* 25 1.92MB 3.5"   */
+ 	{ 6400,40,2,80,0,0x25,0x5B,0xCF,0x00,"E3200" }, /* 26 3.20MB 3.5"   */
+ 	{ 7040,44,2,80,0,0x25,0x5B,0xCF,0x00,"E3520" }, /* 27 3.52MB 3.5"   */
+ 	{ 7680,48,2,80,0,0x25,0x63,0xCF,0x00,"E3840" }, /* 28 3.84MB 3.5"   */
+ 
+ 	{ 3680,23,2,80,0,0x1C,0x10,0xCF,0x00,"H1840" }, /* 29 1.84MB 3.5"   */
+ 	{ 1600,10,2,80,0,0x25,0x02,0xDF,0x2E,"D800"  },	/* 30 800KB 3.5"    */
+ 	{ 3200,20,2,80,0,0x1C,0x00,0xCF,0x2C,"H1600" }, /* 31 1.6MB 3.5"    */
+ };
+ 
+ int
+ linux_fdioctl(dev, cmd, addr, p)
+ 	dev_t dev;
+ 	u_long cmd;
+ 	caddr_t addr;
+ 	struct proc *p;
+ {
+ 	switch (cmd) {
+ 	case 3:
+ 		return (copyout(&floppy_type[7], addr, sizeof (struct floppy_struct)));
+ 	default:
+ 		printf("linux_fdioctl: cmd = %lx\n", cmd);
+ 		return EINVAL;
+   	}
  }
Index: src/sys/compat/linux/linux_misc.c
diff -c src/sys/compat/linux/linux_misc.c:1.1.1.1 src/sys/compat/linux/linux_misc.c:1.2
*** src/sys/compat/linux/linux_misc.c:1.1.1.1	Tue Oct 21 04:18:05 1997
--- src/sys/compat/linux/linux_misc.c	Tue Jan 13 07:47:06 1998
***************
*** 82,87 ****
--- 82,88 ----
  int linux_select1 __P((struct proc *, register_t *, int, fd_set *, fd_set *,
  		       fd_set *, struct timeval *));
  
+ char lostype[] = "Linux";
  /*
   * The information on a terminated (or stopped) process needs
   * to be converted in order for Linux binaries to get a valid signal
***************
*** 384,396 ****
  	struct linux_sys_uname_args /* {
  		syscallarg(struct linux_utsname *) up;
  	} */ *uap = v;
! 	extern char ostype[], hostname[], osrelease[], version[], machine[],
  	    domainname[];
  	struct linux_utsname luts;
  	int len;
  	char *cp;
  
! 	strncpy(luts.l_sysname, ostype, sizeof(luts.l_sysname));
  	strncpy(luts.l_nodename, hostname, sizeof(luts.l_nodename));
  	strncpy(luts.l_release, osrelease, sizeof(luts.l_release));
  	strncpy(luts.l_version, version, sizeof(luts.l_version));
--- 385,397 ----
  	struct linux_sys_uname_args /* {
  		syscallarg(struct linux_utsname *) up;
  	} */ *uap = v;
! 	extern char ostype[] __attribute__((unused)), hostname[], osrelease[], version[], machine[],
  	    domainname[];
  	struct linux_utsname luts;
  	int len;
  	char *cp;
  
! 	strncpy(luts.l_sysname, lostype, sizeof(luts.l_sysname));
  	strncpy(luts.l_nodename, hostname, sizeof(luts.l_nodename));
  	strncpy(luts.l_release, osrelease, sizeof(luts.l_release));
  	strncpy(luts.l_version, version, sizeof(luts.l_version));
***************
*** 418,429 ****
  	struct linux_sys_uname_args /* {
  		syscallarg(struct linux_oldutsname *) up;
  	} */ *uap = v;
! 	extern char ostype[], hostname[], osrelease[], version[], machine[];
  	struct linux_oldutsname luts;
  	int len;
  	char *cp;
  
! 	strncpy(luts.l_sysname, ostype, sizeof(luts.l_sysname));
  	strncpy(luts.l_nodename, hostname, sizeof(luts.l_nodename));
  	strncpy(luts.l_release, osrelease, sizeof(luts.l_release));
  	strncpy(luts.l_version, version, sizeof(luts.l_version));
--- 419,430 ----
  	struct linux_sys_uname_args /* {
  		syscallarg(struct linux_oldutsname *) up;
  	} */ *uap = v;
! 	extern char ostype[] __attribute__((unused)), hostname[], osrelease[], version[], machine[];
  	struct linux_oldutsname luts;
  	int len;
  	char *cp;
  
! 	strncpy(luts.l_sysname, lostype, sizeof(luts.l_sysname));
  	strncpy(luts.l_nodename, hostname, sizeof(luts.l_nodename));
  	strncpy(luts.l_release, osrelease, sizeof(luts.l_release));
  	strncpy(luts.l_version, version, sizeof(luts.l_version));
***************
*** 450,461 ****
  	struct linux_sys_uname_args /* {
  		syscallarg(struct linux_oldoldutsname *) up;
  	} */ *uap = v;
! 	extern char ostype[], hostname[], osrelease[], version[], machine[];
  	struct linux_oldoldutsname luts;
  	int len;
  	char *cp;
  
! 	strncpy(luts.l_sysname, ostype, sizeof(luts.l_sysname));
  	strncpy(luts.l_nodename, hostname, sizeof(luts.l_nodename));
  	strncpy(luts.l_release, osrelease, sizeof(luts.l_release));
  	strncpy(luts.l_version, version, sizeof(luts.l_version));
--- 451,462 ----
  	struct linux_sys_uname_args /* {
  		syscallarg(struct linux_oldoldutsname *) up;
  	} */ *uap = v;
! 	extern char ostype[] __attribute__((unused)), hostname[], osrelease[], version[], machine[];
  	struct linux_oldoldutsname luts;
  	int len;
  	char *cp;
  
! 	strncpy(luts.l_sysname, lostype, sizeof(luts.l_sysname));
  	strncpy(luts.l_nodename, hostname, sizeof(luts.l_nodename));
  	strncpy(luts.l_release, osrelease, sizeof(luts.l_release));
  	strncpy(luts.l_version, version, sizeof(luts.l_version));
***************
*** 722,728 ****
  	else
  		SCARG(&ua, tptr) = NULL;
  
! 	return sys_utimes(p, uap, retval);
  }
  
  /*
--- 723,729 ----
  	else
  		SCARG(&ua, tptr) = NULL;
  
! 	return sys_utimes(p, &ua, retval);
  }
  
  /*
***************
*** 882,887 ****
--- 883,892 ----
  				goto out;
  			}
  			idb.d_off = (linux_off_t)off;
+ 			/* fs/readdir.c offset is computed as the offset to
+ 			 * the next record -- NOT this record
+ 			 */
+ 			idb.d_off += reclen;
  			idb.d_reclen = (u_short)linux_reclen;
  		}
  		strcpy(idb.d_name, bdp->d_name);
Index: src/sys/compat/linux/linux_signal.c
diff -c src/sys/compat/linux/linux_signal.c:1.1.1.1 src/sys/compat/linux/linux_signal.c:1.2
*** src/sys/compat/linux/linux_signal.c:1.1.1.1	Fri Apr  5 07:35:24 1996
--- src/sys/compat/linux/linux_signal.c	Tue Jan 13 07:47:07 1998
***************
*** 245,258 ****
  	struct sys_sigaction_args sa;
  	caddr_t sg;
  	int error;
  
  	sg = stackgap_init(p->p_emul);
  	nlsa = SCARG(uap, nsa);
  	olsa = SCARG(uap, osa);
  
! 	if (olsa != NULL)
  		obsa = stackgap_alloc(&sg, sizeof(struct sigaction));
! 	else
  		obsa = NULL;
  
  	if (nlsa != NULL) {
--- 245,261 ----
  	struct sys_sigaction_args sa;
  	caddr_t sg;
  	int error;
+ 	int signum = linux_to_bsd_sig[SCARG(uap, signum)];
+ 	void (*sa_restorer)(void) = (void (*)(void))NULL;
  
  	sg = stackgap_init(p->p_emul);
  	nlsa = SCARG(uap, nsa);
  	olsa = SCARG(uap, osa);
  
! 	if (olsa != NULL) {
  		obsa = stackgap_alloc(&sg, sizeof(struct sigaction));
! 		sa_restorer = p->p_sigacts->ps_restorer[signum];
! 	} else
  		obsa = NULL;
  
  	if (nlsa != NULL) {
***************
*** 265,281 ****
  	} else
  		nbsa = NULL;
  
! 	SCARG(&sa, signum) = linux_to_bsd_sig[SCARG(uap, signum)];
  	SCARG(&sa, nsa) = nbsa;
  	SCARG(&sa, osa) = obsa;
  
  	if ((error = sys_sigaction(p, &sa, retval)) != 0)
  		return error;
! 
  	if (olsa != NULL) {
  		if ((error = copyin(obsa, &tmpbsa, sizeof(tmpbsa))) != 0)
  			return error;
  		bsd_to_linux_sigaction(&tmpbsa, &tmplsa);
  		if ((error = copyout(&tmplsa, olsa, sizeof(tmplsa))) != 0)
  			return error;
  	}
--- 268,287 ----
  	} else
  		nbsa = NULL;
  
! 	SCARG(&sa, signum) = signum;
  	SCARG(&sa, nsa) = nbsa;
  	SCARG(&sa, osa) = obsa;
  
  	if ((error = sys_sigaction(p, &sa, retval)) != 0)
  		return error;
! 	if (nbsa) {
! 		p->p_sigacts->ps_restorer[signum] = tmplsa.sa_restorer;
! 	}
  	if (olsa != NULL) {
  		if ((error = copyin(obsa, &tmpbsa, sizeof(tmpbsa))) != 0)
  			return error;
  		bsd_to_linux_sigaction(&tmpbsa, &tmplsa);
+ 		tmplsa.sa_restorer = sa_restorer;
  		if ((error = copyout(&tmplsa, olsa, sizeof(tmplsa))) != 0)
  			return error;
  	}
Index: src/sys/sys/signalvar.h
diff -c src/sys/sys/signalvar.h:1.1.1.1 src/sys/sys/signalvar.h:1.2
*** src/sys/sys/signalvar.h:1.1.1.1	Mon Apr 22 07:51:07 1996
--- src/sys/sys/signalvar.h	Tue Jan 13 07:47:18 1998
***************
*** 50,55 ****
--- 50,56 ----
  struct	sigacts {
  	sig_t	ps_sigact[NSIG];	/* disposition of signals */
  	sigset_t ps_catchmask[NSIG];	/* signals to be blocked */
+ 	void (*ps_restorer[NSIG])(void);/* needed by linux (Wabi) */
  	sigset_t ps_sigonstack;		/* signals to take on sigstack */
  	sigset_t ps_sigintr;		/* signals that interrupt syscalls */
  	sigset_t ps_sigreset;		/* signals that reset when caught */