Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 30 Apr 1999 14:40:01 -0700 (PDT)
From:      Juergen Lock <nox@jelal.kn-bremen.de>
To:        freebsd-bugs@FreeBSD.org
Subject:   Re: kern/11287: rfork(RFMEM...) doesn't share LDTs set by i386_set_ldt, breaking wine
Message-ID:  <199904302140.OAA88114@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help
The following reply was made to PR kern/11287; it has been noted by GNATS.

From: Juergen Lock <nox@jelal.kn-bremen.de>
To: Luoqi Chen <luoqi@chen.ml.org>
Cc: freebsd-gnats-submit@freebsd.org
Subject: Re: kern/11287: rfork(RFMEM...) doesn't share LDTs set by i386_set_ldt, breaking wine
Date: Fri, 30 Apr 1999 23:25:27 +0200

 On Fri, Apr 30, 1999 at 12:05:13PM -0400, Luoqi Chen wrote:
 > User LDT sharing should really be done in the machine dependent layer.
 
 Well, was my patch not in the machine dependent layer?
 
 > I have an implementation based on -current (I don't have any machine
 > running -stable), you may want to take a look at, the patch is at
 > http://www.freebsd.org/~luoqi
 > 
 > There are still two problems with this implementation:
 > - It is incomplete for SMP. We need something similar to TLB shootdown
 >   when modifying the ldt table.
 > - It doesn't work correctly in the following case:
 >   1. process A initially doesn't have a user ldt table
 >   2. process A forks process B (RFMEM)
 >   3. process B calls i386_set_ldt()
 >   now process B has a user ldt table, but inaccessible to A. I can
 >   see 3 solutions to this problem:
 >   1. Allocate a user ldt table for all processes.
 >        This is not really an acceptable solution, it penalize everyone
 >        else for the benefit of a few.
 >   2. Define another rfork flag RFLDT.
 >        The problem with solution is the flag is too machine-specific.
 >   3. Any process wants to share user ldt with its descendants should
 >      call i386_set_ldt() prior to any fork.
 >        This is a workaround in the user application, but should work
 >        well.
 > 
 > -lq
 
  Anyway I have back-ported your patch to 3.1-stable and it seems
 to work, so whichever one gets committed is ok with me...
 
  I added a diff for pc98/i386/machdep.c, and the cpu_switch_load_{f,g}s
 trap 12 handler. (Sorry no http location, maybe you can add this to
 your page?  thanx.)
 
 cvs diff: Diffing sys/alpha/alpha
 Index: sys/alpha/alpha/vm_machdep.c
 ===================================================================
 RCS file: /home/cvs/cvs/src/sys/alpha/alpha/vm_machdep.c,v
 retrieving revision 1.7.2.1
 diff -u -r1.7.2.1 vm_machdep.c
 --- vm_machdep.c	1999/01/27 20:51:39	1.7.2.1
 +++ vm_machdep.c	1999/04/30 18:37:45
 @@ -114,11 +114,15 @@
   * ready to run and return to user mode.
   */
  void
 -cpu_fork(p1, p2)
 +cpu_fork(p1, p2, flags)
  	register struct proc *p1, *p2;
 +	int flags;
  {
  	struct user *up = p2->p_addr;
  	int i;
 +
 +	if ((flags & RFPROC) == 0)
 +		return;
  
  	p2->p_md.md_tf = p1->p_md.md_tf;
  	p2->p_md.md_flags = p1->p_md.md_flags & MDP_FPUSED;
 cvs diff: Diffing sys/i386/i386
 Index: sys/i386/i386/genassym.c
 ===================================================================
 RCS file: /home/cvs/cvs/src/sys/i386/i386/genassym.c,v
 retrieving revision 1.62.2.1
 diff -u -r1.62.2.1 genassym.c
 --- genassym.c	1999/02/22 15:59:39	1.62.2.1
 +++ genassym.c	1999/04/30 18:38:27
 @@ -125,7 +125,9 @@
  	printf("#define\tPCB_EBX %#x\n", OS(pcb, pcb_ebx));
  	printf("#define\tPCB_EIP %#x\n", OS(pcb, pcb_eip));
  	printf("#define\tTSS_ESP0 %#x\n", OS(i386tss, tss_esp0));
 +#ifdef USER_LDT
  	printf("#define\tPCB_USERLDT %#x\n", OS(pcb, pcb_ldt));
 +#endif
  	printf("#define\tPCB_FS %#x\n", OS(pcb, pcb_fs));
  	printf("#define\tPCB_GS %#x\n", OS(pcb, pcb_gs));
  #ifdef VM86
 Index: sys/i386/i386/machdep.c
 ===================================================================
 RCS file: /home/cvs/cvs/src/sys/i386/i386/machdep.c,v
 retrieving revision 1.322.2.4
 diff -u -r1.322.2.4 machdep.c
 --- machdep.c	1999/02/17 13:08:41	1.322.2.4
 +++ machdep.c	1999/04/30 18:39:41
 @@ -814,15 +814,7 @@
  
  #ifdef USER_LDT
  	/* was i386_user_cleanup() in NetBSD */
 -	if (pcb->pcb_ldt) {
 -		if (pcb == curpcb) {
 -			lldt(_default_ldt);
 -			currentldt = _default_ldt;
 -		}
 -		kmem_free(kernel_map, (vm_offset_t)pcb->pcb_ldt,
 -			pcb->pcb_ldt_len * sizeof(union descriptor));
 -		pcb->pcb_ldt_len = (int)pcb->pcb_ldt = 0;
 - 	}
 +	user_ldt_free(pcb);
  #endif
    
  	bzero((char *)regs, sizeof(struct trapframe));
 Index: sys/i386/i386/sys_machdep.c
 ===================================================================
 RCS file: /home/cvs/cvs/src/sys/i386/i386/sys_machdep.c,v
 retrieving revision 1.38
 diff -u -r1.38 sys_machdep.c
 --- sys_machdep.c	1998/12/07 21:58:19	1.38
 +++ sys_machdep.c	1999/04/30 19:03:34
 @@ -41,6 +41,7 @@
  #include <sys/param.h>
  #include <sys/systm.h>
  #include <sys/sysproto.h>
 +#include <sys/malloc.h>
  #include <sys/proc.h>
  
  #include <vm/vm.h>
 @@ -65,7 +66,6 @@
  
  
  #ifdef USER_LDT
 -void set_user_ldt	__P((struct pcb *pcb));
  static int i386_get_ldt	__P((struct proc *, char *));
  static int i386_set_ldt	__P((struct proc *, char *));
  #endif
 @@ -259,13 +259,72 @@
  void
  set_user_ldt(struct pcb *pcb)
  {
 -	gdt_segs[GUSERLDT_SEL].ssd_base = (unsigned)pcb->pcb_ldt;
 -	gdt_segs[GUSERLDT_SEL].ssd_limit = (pcb->pcb_ldt_len * sizeof(union descriptor)) - 1;
 -	ssdtosd(&gdt_segs[GUSERLDT_SEL], &gdt[GUSERLDT_SEL].sd);
 +	struct pcb_ldt *pcb_ldt = pcb->pcb_ldt;
 +#ifdef SMP
 +	gdt[cpuid * NGDT + GUSERLDT_SEL].sd = pcb_ldt->ldt_sd;
 +#else
 +	gdt[GUSERLDT_SEL].sd = pcb_ldt->ldt_sd;
 +#endif
  	lldt(GSEL(GUSERLDT_SEL, SEL_KPL));
  	currentldt = GSEL(GUSERLDT_SEL, SEL_KPL);
  }
  
 +struct pcb_ldt *
 +user_ldt_alloc(struct pcb *pcb, int len)
 +{
 +	struct pcb_ldt *pcb_ldt, *new_ldt;
 +
 +	MALLOC(new_ldt, struct pcb_ldt *, sizeof(struct pcb_ldt),
 +		M_SUBPROC, M_WAITOK);
 +	if (new_ldt == NULL)
 +		return NULL;
 +
 +	new_ldt->ldt_len = len = NEW_MAX_LD(len);
 +	new_ldt->ldt_base = (caddr_t)kmem_alloc(kernel_map,
 +		len * sizeof(union descriptor));
 +	if (new_ldt->ldt_base == NULL) {
 +		FREE(new_ldt, M_SUBPROC);
 +		return NULL;
 +	}
 +	new_ldt->ldt_refcnt = 1;
 +	new_ldt->ldt_active = 0;
 +
 +	gdt_segs[GUSERLDT_SEL].ssd_base = (unsigned)new_ldt->ldt_base;
 +	gdt_segs[GUSERLDT_SEL].ssd_limit = len * sizeof(union descriptor) - 1;
 +	ssdtosd(&gdt_segs[GUSERLDT_SEL], &new_ldt->ldt_sd);
 +
 +	if ((pcb_ldt = pcb->pcb_ldt)) {
 +		if (len > pcb_ldt->ldt_len)
 +			len = pcb_ldt->ldt_len;
 +		bcopy(pcb_ldt->ldt_base, new_ldt->ldt_base,
 +			len * sizeof(union descriptor));
 +	} else {
 +		bcopy(ldt, new_ldt->ldt_base, sizeof(ldt));
 +	}
 +	return new_ldt;
 +}
 +
 +void
 +user_ldt_free(struct pcb *pcb)
 +{
 +	struct pcb_ldt *pcb_ldt = pcb->pcb_ldt;
 +
 +	if (pcb_ldt == NULL)
 +		return;
 +
 +	if (pcb == curpcb) {
 +		lldt(_default_ldt);
 +		currentldt = _default_ldt;
 +	}
 +
 +	if (--pcb_ldt->ldt_refcnt == 0) {
 +		kmem_free(kernel_map, (vm_offset_t)pcb_ldt->ldt_base,
 +			pcb_ldt->ldt_len * sizeof(union descriptor));
 +		FREE(pcb_ldt, M_SUBPROC);
 +	}
 +	pcb->pcb_ldt = NULL;
 +}
 +
  struct i386_get_ldt_args {
  	int start;
  	union descriptor *desc;
 @@ -279,6 +338,7 @@
  {
  	int error = 0;
  	struct pcb *pcb = &p->p_addr->u_pcb;
 +	struct pcb_ldt *pcb_ldt = pcb->pcb_ldt;
  	int nldt, num;
  	union descriptor *lp;
  	int s;
 @@ -299,10 +359,10 @@
  
  	s = splhigh();
  
 -	if (pcb->pcb_ldt) {
 -		nldt = pcb->pcb_ldt_len;
 +	if (pcb_ldt) {
 +		nldt = pcb_ldt->ldt_len;
  		num = min(uap->num, nldt);
 -		lp = &((union descriptor *)(pcb->pcb_ldt))[uap->start];
 +		lp = &((union descriptor *)(pcb_ldt->ldt_base))[uap->start];
  	} else {
  		nldt = sizeof(ldt)/sizeof(ldt[0]);
  		num = min(uap->num, nldt);
 @@ -335,6 +395,7 @@
  	int error = 0, i, n;
   	int largest_ld;
  	struct pcb *pcb = &p->p_addr->u_pcb;
 +	struct pcb_ldt *pcb_ldt = pcb->pcb_ldt;
  	int s;
  	struct i386_set_ldt_args ua, *uap;
  
 @@ -348,36 +409,37 @@
  	    uap->start, uap->num, (void *)uap->desc);
  #endif
  
 - 	/* verify range of descriptors to modify */
 - 	if ((uap->start < 0) || (uap->start >= MAX_LD) || (uap->num < 0) ||
 - 		(uap->num > MAX_LD))
 - 	{
 +	/* verify range of descriptors to modify */
 +	if ((uap->start < 0) || (uap->start >= MAX_LD) || (uap->num < 0) ||
 +		(uap->num > MAX_LD))
 +	{
 +		return(EINVAL);
 +	}
 +	largest_ld = uap->start + uap->num - 1;
 +	if (largest_ld >= MAX_LD)
   		return(EINVAL);
 - 	}
 - 	largest_ld = uap->start + uap->num - 1;
 - 	if (largest_ld >= MAX_LD)
 -  		return(EINVAL);
 -  
 -  	/* allocate user ldt */
 - 	if (!pcb->pcb_ldt || (largest_ld >= pcb->pcb_ldt_len)) {
 - 		union descriptor *new_ldt = (union descriptor *)kmem_alloc(
 - 			kernel_map, SIZE_FROM_LARGEST_LD(largest_ld));
 - 		if (new_ldt == NULL) {
 - 			return ENOMEM;
 - 		}
 - 		if (pcb->pcb_ldt) {
 - 			bcopy(pcb->pcb_ldt, new_ldt, pcb->pcb_ldt_len
 - 				* sizeof(union descriptor));
 - 			kmem_free(kernel_map, (vm_offset_t)pcb->pcb_ldt,
 - 				pcb->pcb_ldt_len * sizeof(union descriptor));
 - 		} else {
 - 			bcopy(ldt, new_ldt, sizeof(ldt));
 - 		}
 -  		pcb->pcb_ldt = (caddr_t)new_ldt;
 - 		pcb->pcb_ldt_len = NEW_MAX_LD(largest_ld);
 - 		if (pcb == curpcb)
 - 		    set_user_ldt(pcb);
 -  	}
 + 
 + 	/* allocate user ldt */
 +	if (!pcb_ldt || (largest_ld >= pcb_ldt->ldt_len)) {
 +		struct pcb_ldt *new_ldt = user_ldt_alloc(pcb, largest_ld);
 +		if (new_ldt == NULL) {
 +			return ENOMEM;
 +		}
 +	        if (pcb_ldt) {
 +	                pcb_ldt->ldt_sd = new_ldt->ldt_sd;
 +#ifdef SMP
 +		/* signal other cpus to reload ldt */
 +#endif
 +			kmem_free(kernel_map, (vm_offset_t)pcb_ldt->ldt_base,
 +				pcb_ldt->ldt_len * sizeof(union descriptor));
 +			pcb_ldt->ldt_base = new_ldt->ldt_base;
 +			pcb_ldt->ldt_len = new_ldt->ldt_len;
 +			FREE(new_ldt, M_SUBPROC);
 +	        } else
 +			pcb->pcb_ldt = pcb_ldt = new_ldt;
 +		if (pcb == curpcb)
 +			set_user_ldt(pcb);
 +	}
  
  	/* Check descriptors for access violations */
  	for (i = 0, n = uap->start; i < uap->num; i++, n++) {
 @@ -388,70 +450,70 @@
  			return(error);
  
  		switch (desc.sd.sd_type) {
 - 		case SDT_SYSNULL:	/* system null */ 
 - 			desc.sd.sd_p = 0;
 -  			break;
 - 		case SDT_SYS286TSS: /* system 286 TSS available */
 - 		case SDT_SYSLDT:    /* system local descriptor table */
 - 		case SDT_SYS286BSY: /* system 286 TSS busy */
 - 		case SDT_SYSTASKGT: /* system task gate */
 - 		case SDT_SYS286IGT: /* system 286 interrupt gate */
 - 		case SDT_SYS286TGT: /* system 286 trap gate */
 - 		case SDT_SYSNULL2:  /* undefined by Intel */ 
 - 		case SDT_SYS386TSS: /* system 386 TSS available */
 - 		case SDT_SYSNULL3:  /* undefined by Intel */
 - 		case SDT_SYS386BSY: /* system 386 TSS busy */
 - 		case SDT_SYSNULL4:  /* undefined by Intel */ 
 - 		case SDT_SYS386IGT: /* system 386 interrupt gate */
 - 		case SDT_SYS386TGT: /* system 386 trap gate */
 - 		case SDT_SYS286CGT: /* system 286 call gate */ 
 - 		case SDT_SYS386CGT: /* system 386 call gate */
 - 			/* I can't think of any reason to allow a user proc
 - 			 * to create a segment of these types.  They are
 - 			 * for OS use only.
 - 			 */
 -     	    	    	return EACCES;
 - 
 - 		/* memory segment types */
 - 		case SDT_MEMEC:   /* memory execute only conforming */
 - 		case SDT_MEMEAC:  /* memory execute only accessed conforming */
 - 		case SDT_MEMERC:  /* memory execute read conforming */
 - 		case SDT_MEMERAC: /* memory execute read accessed conforming */
 -                         /* Must be "present" if executable and conforming. */
 -                         if (desc.sd.sd_p == 0)
 -                                 return (EACCES);
 +		case SDT_SYSNULL:	/* system null */ 
 +			desc.sd.sd_p = 0;
   			break;
 - 		case SDT_MEMRO:   /* memory read only */
 - 		case SDT_MEMROA:  /* memory read only accessed */
 - 		case SDT_MEMRW:   /* memory read write */
 - 		case SDT_MEMRWA:  /* memory read write accessed */
 - 		case SDT_MEMROD:  /* memory read only expand dwn limit */
 - 		case SDT_MEMRODA: /* memory read only expand dwn lim accessed */
 - 		case SDT_MEMRWD:  /* memory read write expand dwn limit */  
 - 		case SDT_MEMRWDA: /* memory read write expand dwn lim acessed */
 - 		case SDT_MEME:    /* memory execute only */ 
 - 		case SDT_MEMEA:   /* memory execute only accessed */
 - 		case SDT_MEMER:   /* memory execute read */
 - 		case SDT_MEMERA:  /* memory execute read accessed */
 +		case SDT_SYS286TSS: /* system 286 TSS available */
 +		case SDT_SYSLDT:    /* system local descriptor table */
 +		case SDT_SYS286BSY: /* system 286 TSS busy */
 +		case SDT_SYSTASKGT: /* system task gate */
 +		case SDT_SYS286IGT: /* system 286 interrupt gate */
 +		case SDT_SYS286TGT: /* system 286 trap gate */
 +		case SDT_SYSNULL2:  /* undefined by Intel */ 
 +		case SDT_SYS386TSS: /* system 386 TSS available */
 +		case SDT_SYSNULL3:  /* undefined by Intel */
 +		case SDT_SYS386BSY: /* system 386 TSS busy */
 +		case SDT_SYSNULL4:  /* undefined by Intel */ 
 +		case SDT_SYS386IGT: /* system 386 interrupt gate */
 +		case SDT_SYS386TGT: /* system 386 trap gate */
 +		case SDT_SYS286CGT: /* system 286 call gate */ 
 +		case SDT_SYS386CGT: /* system 386 call gate */
 +			/* I can't think of any reason to allow a user proc
 +			 * to create a segment of these types.  They are
 +			 * for OS use only.
 +			 */
 +    	    	    	return EACCES;
 +
 +		/* memory segment types */
 +		case SDT_MEMEC:   /* memory execute only conforming */
 +		case SDT_MEMEAC:  /* memory execute only accessed conforming */
 +		case SDT_MEMERC:  /* memory execute read conforming */
 +		case SDT_MEMERAC: /* memory execute read accessed conforming */
 +			/* Must be "present" if executable and conforming. */
 +			if (desc.sd.sd_p == 0)
 +				return (EACCES);
 +			break;
 +		case SDT_MEMRO:   /* memory read only */
 +		case SDT_MEMROA:  /* memory read only accessed */
 +		case SDT_MEMRW:   /* memory read write */
 +		case SDT_MEMRWA:  /* memory read write accessed */
 +		case SDT_MEMROD:  /* memory read only expand dwn limit */
 +		case SDT_MEMRODA: /* memory read only expand dwn lim accessed */
 +		case SDT_MEMRWD:  /* memory read write expand dwn limit */  
 +		case SDT_MEMRWDA: /* memory read write expand dwn lim acessed */
 +		case SDT_MEME:    /* memory execute only */ 
 +		case SDT_MEMEA:   /* memory execute only accessed */
 +		case SDT_MEMER:   /* memory execute read */
 +		case SDT_MEMERA:  /* memory execute read accessed */
  			break;
  		default:
  			return(EINVAL);
  			/*NOTREACHED*/
  		}
   
 - 		/* Only user (ring-3) descriptors may be present. */
 - 		if ((desc.sd.sd_p != 0) && (desc.sd.sd_dpl != SEL_UPL))
 - 			return (EACCES);
 +		/* Only user (ring-3) descriptors may be present. */
 +		if ((desc.sd.sd_p != 0) && (desc.sd.sd_dpl != SEL_UPL))
 +			return (EACCES);
  	}
  
  	s = splhigh();
  
  	/* Fill in range */
 - 	error = copyin(uap->desc, 
 - 		 &((union descriptor *)(pcb->pcb_ldt))[uap->start],
 - 		uap->num * sizeof(union descriptor));
 - 	if (!error)
 -  		p->p_retval[0] = uap->start;
 +	error = copyin(uap->desc, 
 +		 &((union descriptor *)(pcb_ldt->ldt_base))[uap->start],
 +		uap->num * sizeof(union descriptor));
 +	if (!error)
 + 		p->p_retval[0] = uap->start;
  
  	splx(s);
  	return(error);
 Index: sys/i386/i386/vm_machdep.c
 ===================================================================
 RCS file: /home/cvs/cvs/src/sys/i386/i386/vm_machdep.c,v
 retrieving revision 1.115
 diff -u -r1.115 vm_machdep.c
 --- vm_machdep.c	1999/01/06 23:05:37	1.115
 +++ vm_machdep.c	1999/04/30 19:11:14
 @@ -57,6 +57,7 @@
  #include <sys/vmmeter.h>
  #include <sys/kernel.h>
  #include <sys/sysctl.h>
 +#include <sys/unistd.h>
  
  #include <machine/clock.h>
  #include <machine/cpu.h>
 @@ -113,10 +114,29 @@
   * ready to run and return to user mode.
   */
  void
 -cpu_fork(p1, p2)
 +cpu_fork(p1, p2, flags)
  	register struct proc *p1, *p2;
 +	int flags;
  {
 -	struct pcb *pcb2 = &p2->p_addr->u_pcb;
 +	struct pcb *pcb2;
 + 
 +	if ((flags & RFPROC) == 0) {
 +#ifdef USER_LDT
 +		if ((flags & RFMEM) == 0) {
 +			/* unshare user LDT */
 +			struct pcb *pcb1 = &p1->p_addr->u_pcb;
 +			struct pcb_ldt *pcb_ldt = pcb1->pcb_ldt;
 +			if (pcb_ldt && pcb_ldt->ldt_refcnt > 1) {
 +				pcb_ldt = user_ldt_alloc(pcb1,pcb_ldt->ldt_len);
 +				user_ldt_free(pcb1);
 +				pcb1->pcb_ldt = pcb_ldt;
 +				if (pcb1 == curpcb)
 +					set_user_ldt(pcb1);
 +			}
 +		}
 +#endif
 +	        return;
 +	}
  
  #if NNPX > 0
  	/* Ensure that p1's pcb is up to date. */
 @@ -126,6 +146,7 @@
  
  	/* Copy p1's pcb. */
  	p2->p_addr->u_pcb = p1->p_addr->u_pcb;
 +	pcb2 = &p2->p_addr->u_pcb;
  
  	/*
  	 * Create a new fresh stack for the new process.
 @@ -153,7 +174,6 @@
  	pcb2->pcb_eip = (int)fork_trampoline;
  	/*
  	 * pcb2->pcb_ldt:	duplicated below, if necessary.
 -	 * pcb2->pcb_ldt_len:	cloned above.
  	 * pcb2->pcb_savefpu:	cloned above.
  	 * pcb2->pcb_flags:	cloned above (always 0 here?).
  	 * pcb2->pcb_onfault:	cloned above (always NULL here?).
 @@ -172,12 +192,12 @@
  #ifdef USER_LDT
          /* Copy the LDT, if necessary. */
          if (pcb2->pcb_ldt != 0) {
 -                union descriptor *new_ldt;
 -                size_t len = pcb2->pcb_ldt_len * sizeof(union descriptor);
 -
 -                new_ldt = (union descriptor *)kmem_alloc(kernel_map, len);
 -                bcopy(pcb2->pcb_ldt, new_ldt, len);
 -                pcb2->pcb_ldt = (caddr_t)new_ldt;
 +		if (flags & RFMEM) {
 +			pcb2->pcb_ldt->ldt_refcnt++;
 +		} else {
 +			pcb2->pcb_ldt = user_ldt_alloc(pcb2,
 +				pcb2->pcb_ldt->ldt_len);
 +		}
          }
  #endif
  
 @@ -235,15 +255,7 @@
  	}
  #endif
  #ifdef USER_LDT
 -	if (pcb->pcb_ldt != 0) {
 -		if (pcb == curpcb) {
 -			lldt(_default_ldt);
 -			currentldt = _default_ldt;
 -		}
 -		kmem_free(kernel_map, (vm_offset_t)pcb->pcb_ldt,
 -			pcb->pcb_ldt_len * sizeof(union descriptor));
 -		pcb->pcb_ldt_len = (int)pcb->pcb_ldt = 0;
 -	}
 +	user_ldt_free(pcb);
  #endif
  	cnt.v_swtch++;
  	cpu_switch(p);
 cvs diff: Diffing sys/i386/include
 Index: sys/i386/include/pcb.h
 ===================================================================
 RCS file: /home/cvs/cvs/src/sys/i386/include/pcb.h,v
 retrieving revision 1.26
 diff -u -r1.26 pcb.h
 --- pcb.h	1998/02/03 21:27:50	1.26
 +++ pcb.h	1999/04/30 19:12:53
 @@ -53,8 +53,11 @@
  	int	pcb_esp;
  	int	pcb_ebx;
  	int	pcb_eip;
 -	caddr_t	pcb_ldt;		/* per process (user) LDT */
 -	int	pcb_ldt_len;		/* number of LDT entries */
 +#ifdef USER_LDT
 +	struct  pcb_ldt *pcb_ldt;       /* per process (user) LDT */
 +#else
 +	struct  pcb_ldt *pcb_ldt_dontuse;
 +#endif
  	struct	save87	pcb_savefpu;	/* floating point state for 287/387 */
  	u_char	pcb_flags;
  #define	FP_SOFTFP	0x01	/* process using software fltng pnt emulator */
 @@ -71,7 +74,7 @@
  #else
  	struct	pcb_ext	*pcb_ext_dontuse;
  #endif
 -	u_long	__pcb_spare[1];	/* adjust to avoid core dump size changes */
 +	u_long	__pcb_spare[2];	/* adjust to avoid core dump size changes */
  };
  
  /*
 Index: sys/i386/include/pcb_ext.h
 ===================================================================
 RCS file: /home/cvs/cvs/src/sys/i386/include/pcb_ext.h,v
 retrieving revision 1.1
 diff -u -r1.1 pcb_ext.h
 --- pcb_ext.h	1997/08/09 04:55:05	1.1
 +++ pcb_ext.h	1999/04/30 19:13:58
 @@ -43,4 +43,22 @@
  	struct	vm86_kernel ext_vm86;	/* vm86 area */
  };
  
 +struct pcb_ldt {
 +	caddr_t ldt_base;
 +	int     ldt_len;
 +	int     ldt_refcnt;
 +	u_long  ldt_active;
 +	struct  segment_descriptor ldt_sd;
 +};
 +
 +#ifdef KERNEL
 +
 +#ifdef USER_LDT
 +void set_user_ldt __P((struct pcb *));
 +struct pcb_ldt *user_ldt_alloc __P((struct pcb *, int));
 +void user_ldt_free __P((struct pcb *));
 +#endif
 +
 +#endif
 +
  #endif /* _I386_PCB_EXT_H_ */
 cvs diff: Diffing sys/i386/include/pc
 cvs diff: Diffing sys/kern
 Index: sys/kern/kern_fork.c
 ===================================================================
 RCS file: /home/cvs/cvs/src/sys/kern/kern_fork.c,v
 retrieving revision 1.54.2.2
 diff -u -r1.54.2.2 kern_fork.c
 --- kern_fork.c	1999/03/02 00:42:08	1.54.2.2
 +++ kern_fork.c	1999/04/30 19:14:56
 @@ -162,16 +162,7 @@
  	 */
  	if ((flags & RFPROC) == 0) {
  
 -		/*
 -		 * Divorce the memory, if it is shared, essentially
 -		 * this changes shared memory amongst threads, into
 -		 * COW locally.
 -		 */
 -		if ((flags & RFMEM) == 0) {
 -			if (p1->p_vmspace->vm_refcnt > 1) {
 -				vmspace_unshare(p1);
 -			}
 -		}
 +		vm_fork(p1, 0, flags);
  
  		/*
  		 * Close all file descriptors.
 cvs diff: Diffing sys/sys
 Index: sys/sys/proc.h
 ===================================================================
 RCS file: /home/cvs/cvs/src/sys/sys/proc.h,v
 retrieving revision 1.66.2.2
 diff -u -r1.66.2.2 proc.h
 --- proc.h	1999/02/23 13:44:36	1.66.2.2
 +++ proc.h	1999/04/30 19:15:32
 @@ -375,7 +375,7 @@
  
  void	cpu_exit __P((struct proc *)) __dead2;
  void	exit1 __P((struct proc *, int)) __dead2;
 -void	cpu_fork __P((struct proc *, struct proc *));
 +void	cpu_fork __P((struct proc *, struct proc *, int));
  int	fork1 __P((struct proc *, int));
  int	trace_req __P((struct proc *));
  void	cpu_wait __P((struct proc *));
 cvs diff: Diffing sys/vm
 Index: sys/vm/vm_glue.c
 ===================================================================
 RCS file: /home/cvs/cvs/src/sys/vm/vm_glue.c,v
 retrieving revision 1.80.2.1
 diff -u -r1.80.2.1 vm_glue.c
 --- vm_glue.c	1999/01/27 20:51:43	1.80.2.1
 +++ vm_glue.c	1999/04/30 19:17:19
 @@ -208,6 +208,21 @@
  {
  	register struct user *up;
  
 +	if ((flags & RFPROC) == 0) {
 +		/*
 +		 * Divorce the memory, if it is shared, essentially
 +		 * this changes shared memory amongst threads, into
 +		 * COW locally.
 +		 */
 +		if ((flags & RFMEM) == 0) {
 +			if (p1->p_vmspace->vm_refcnt > 1) {
 +				vmspace_unshare(p1);
 +			}
 +		}
 +		cpu_fork(p1, p2, flags);
 +		return;
 +	}
 +
  	if (flags & RFMEM) {
  		p2->p_vmspace = p1->p_vmspace;
  		p1->p_vmspace->vm_refcnt++;
 @@ -257,7 +272,7 @@
  	 * cpu_fork will copy and update the pcb, set up the kernel stack,
  	 * and make the child ready to run.
  	 */
 -	cpu_fork(p1, p2);
 +	cpu_fork(p1, p2, flags);
  }
  
  /*
 
 Index: sys/pc98/i386/machdep.c
 ===================================================================
 RCS file: /home/cvs/cvs/src/sys/i386/i386/machdep.c,v
 retrieving revision 1.322.2.4
 diff -u -r1.322.2.4 machdep.c
 --- machdep.c	1999/02/17 13:08:41	1.322.2.4
 +++ machdep.c	1999/04/30 18:39:41
 @@ -814,15 +814,7 @@
  
  #ifdef USER_LDT
  	/* was i386_user_cleanup() in NetBSD */
 -	if (pcb->pcb_ldt) {
 -		if (pcb == curpcb) {
 -			lldt(_default_ldt);
 -			currentldt = _default_ldt;
 -		}
 -		kmem_free(kernel_map, (vm_offset_t)pcb->pcb_ldt,
 -			pcb->pcb_ldt_len * sizeof(union descriptor));
 -		pcb->pcb_ldt_len = (int)pcb->pcb_ldt = 0;
 - 	}
 +	user_ldt_free(pcb);
  #endif
    
  	bzero((char *)regs, sizeof(struct trapframe));
 Index: sys/i386/i386/trap.c
 ===================================================================
 RCS file: /home/cvs/cvs/src/sys/i386/i386/trap.c,v
 retrieving revision 1.133
 diff -u -r1.133 trap.c
 --- trap.c	1999/01/06 23:05:36	1.133
 +++ trap.c	1999/04/26 13:44:35
 @@ -434,6 +434,29 @@
  
  		switch (type) {
  		case T_PAGEFLT:			/* page fault */
 +			if (intr_nesting_level == 0) {
 +				/*
 +				 * Invalid %fs's and %gs's can be created using
 +				 * procfs or PT_SETREGS or by invalidating the
 +				 * underlying LDT entry.  This causes a fault
 +				 * in kernel mode when the kernel attempts to
 +				 * switch contexts.  Lose the bad context
 +				 * (XXX) so that we can continue, and generate
 +				 * a signal.
 +				 */
 +				if (frame.tf_eip == (int)cpu_switch_load_fs
 +				    && curpcb->pcb_fs) {
 +					curpcb->pcb_fs = 0;
 +					psignal(p, SIGBUS);
 +					return;
 +				}
 +				if (frame.tf_eip == (int)cpu_switch_load_gs
 +				    && curpcb->pcb_gs) {
 +					curpcb->pcb_gs = 0;
 +					psignal(p, SIGBUS);
 +					return;
 +				}
 +			}
  			(void) trap_pfault(&frame, FALSE, eva);
  			return;
  
  Regards,
 -- 
 Juergen Lock <nox.foo@jelal.kn-bremen.de>
 (remove dot foo from address to reply)
 


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199904302140.OAA88114>