Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 19 Feb 2007 22:56:20 GMT
From:      Jung-uk Kim <jkim@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 114732 for review
Message-ID:  <200702192256.l1JMuKHH029284@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=114732

Change 114732 by jkim@jkim_hammer on 2007/02/19 22:56:14

	Finish TLS on amd64 support.
	It may have rough edges but it seems usable.
	Tested on a real UP machine and QEMU SMP.
	
	<rant>
	PCB_32BIT flag was half-baked and never used from the day one.
	Unfortunately it was confusing me from the beginning. :-(
	</rant>

Affected files ...

.. //depot/projects/linuxolator/src/sys/amd64/amd64/cpu_switch.S#5 edit
.. //depot/projects/linuxolator/src/sys/amd64/amd64/genassym.c#6 edit
.. //depot/projects/linuxolator/src/sys/amd64/ia32/ia32_signal.c#4 edit
.. //depot/projects/linuxolator/src/sys/amd64/include/pcb.h#3 edit
.. //depot/projects/linuxolator/src/sys/amd64/linux32/linux32_locore.s#3 edit
.. //depot/projects/linuxolator/src/sys/amd64/linux32/linux32_machdep.c#37 edit
.. //depot/projects/linuxolator/src/sys/amd64/linux32/linux32_sysvec.c#11 edit

Differences ...

==== //depot/projects/linuxolator/src/sys/amd64/amd64/cpu_switch.S#5 (text+ko) ====

@@ -104,11 +104,11 @@
 	testl	$PCB_32BIT,PCB_FLAGS(%r8)
 	jz	1f				/* no, skip over */
 
-	/* Save segment selector numbers */
-	movl	%ds,PCB_DS(%r8)
-	movl	%es,PCB_ES(%r8)
-	movl	%fs,PCB_FS(%r8)
+	/* Save userland %gs */
 	movl	%gs,PCB_GS(%r8)
+	movq	PCB_GS32P(%r8),%rax
+	movq	(%rax),%rax
+	movq	%rax,PCB_GS32SD(%r8)
 
 1:
 	/* Test if debug registers should be saved. */
@@ -171,30 +171,6 @@
 	 */
 	movq	TD_PCB(%rsi),%r8
 
-	testl	$PCB_32BIT,PCB_FLAGS(%r8)
-	jz	1f				/* no, skip over */
-
-	/* Restore segment selector numbers */
-	movl	PCB_DS(%r8),%ds
-	movl	PCB_ES(%r8),%es
-	movl	PCB_FS(%r8),%fs
-
-	/* Restore userland %gs while preserving kernel gsbase */
-	movl	$MSR_GSBASE,%ecx
-	rdmsr
-	movl	PCB_GS(%r8),%gs
-	wrmsr
-
-	/* Restore userland 32 bit GS descriptor for Linuxulator */
-	movq	PCB_GS32P(%r8),%rax
-	testq	%rax,%rax
-	jz	2f				/* no, skip over */
-
-	movq	PCB_GS32SD(%r8),%rcx
-	movq	%rcx,(%rax)
-	jmp	2f
-
-1:
 	/* Restore userland %fs */
 	movl	$MSR_FSBASE,%ecx
 	movl	PCB_FSBASE(%r8),%eax
@@ -207,7 +183,6 @@
 	movl	PCB_GSBASE+4(%r8),%edx
 	wrmsr
 
-2:
 	/* Update the TSS_RSP0 pointer for the next interrupt */
 	movq	PCPU(TSSP), %rax
 	addq	$COMMON_TSS_RSP0, %rax
@@ -220,6 +195,19 @@
 	movl	%eax, PCPU(CURTID)
 	movq	%rsi, PCPU(CURTHREAD)		/* into next thread */
 
+	testl	$PCB_32BIT,PCB_FLAGS(%r8)
+	jz	1f				/* no, skip over */
+
+	/* Restore userland %gs while preserving kernel gsbase */
+	movq	PCB_GS32P(%r8),%rax
+	movq	PCB_GS32SD(%r8),%rbx
+	movq	%rbx,(%rax)
+	movl	$MSR_GSBASE,%ecx
+	rdmsr
+	movl	PCB_GS(%r8),%gs
+	wrmsr
+
+1:
 	/* Restore context. */
 	movq	PCB_RBX(%r8),%rbx
 	movq	PCB_RSP(%r8),%rsp

==== //depot/projects/linuxolator/src/sys/amd64/amd64/genassym.c#6 (text+ko) ====

@@ -136,20 +136,19 @@
 ASSYM(PCB_DR7, offsetof(struct pcb, pcb_dr7));
 ASSYM(PCB_DBREGS, PCB_DBREGS);
 ASSYM(PCB_32BIT, PCB_32BIT);
+ASSYM(PCB_FULLCTX, PCB_FULLCTX);
 
 ASSYM(PCB_FLAGS, offsetof(struct pcb, pcb_flags));
-ASSYM(PCB_FULLCTX, PCB_FULLCTX);
 ASSYM(PCB_SAVEFPU, offsetof(struct pcb, pcb_save));
 ASSYM(PCB_SAVEFPU_SIZE, sizeof(struct savefpu));
 ASSYM(PCB_ONFAULT, offsetof(struct pcb, pcb_onfault));
+ASSYM(PCB_GS32P, offsetof(struct pcb, pcb_gs32p));
+ASSYM(PCB_GS32SD, offsetof(struct pcb, pcb_gs32sd));
 
 ASSYM(PCB_SIZE, sizeof(struct pcb));
 
 ASSYM(COMMON_TSS_RSP0, offsetof(struct amd64tss, tss_rsp0));
 
-ASSYM(PCB_GS32P, offsetof(struct pcb, pcb_gs32p));
-ASSYM(PCB_GS32SD, offsetof(struct pcb, pcb_gs32sd));
-
 ASSYM(TF_R15, offsetof(struct trapframe, tf_r15));
 ASSYM(TF_R14, offsetof(struct trapframe, tf_r14));
 ASSYM(TF_R13, offsetof(struct trapframe, tf_r13));

==== //depot/projects/linuxolator/src/sys/amd64/ia32/ia32_signal.c#4 (text+ko) ====

@@ -727,7 +727,6 @@
 	pcb->pcb_es = _udatasel;
 	pcb->pcb_fs = _udatasel;
 	pcb->pcb_gs = _udatasel;
-	pcb->pcb_gs32p = NULL;
 
 	bzero((char *)regs, sizeof(struct trapframe));
 	regs->tf_rip = entry;

==== //depot/projects/linuxolator/src/sys/amd64/include/pcb.h#3 (text+ko) ====

@@ -41,6 +41,7 @@
  * AMD64 process control block
  */
 #include <machine/fpu.h>
+#include <machine/segments.h>
 
 struct pcb {
 	register_t	pcb_cr3;
@@ -74,8 +75,9 @@
 
 	caddr_t	pcb_onfault;	/* copyin/out fault recovery */
 
-	caddr_t		pcb_gs32p;	/* XXX pointer to gdt[GUGS32_SEL] */
-	u_int64_t	pcb_gs32sd;	/* 32 bit GS segment descriptor */
+	/* 32-bit segment descriptor */
+	struct user_segment_descriptor	*pcb_gs32p;
+	struct user_segment_descriptor	pcb_gs32sd;
 };
 
 #ifdef _KERNEL

==== //depot/projects/linuxolator/src/sys/amd64/linux32/linux32_locore.s#3 (text+ko) ====

@@ -11,10 +11,6 @@
 NON_GPROF_ENTRY(linux_sigcode)
 	call	*LINUX_SIGF_HANDLER(%esp)
 	leal	LINUX_SIGF_SC(%esp),%ebx	/* linux scp */
-#if 0
-	movl	LINUX_SC_GS(%ebx),%gs
-#endif
-	movl	LINUX_SC_FS(%ebx),%fs
 	movl	LINUX_SC_ES(%ebx),%es
 	movl	LINUX_SC_DS(%ebx),%ds
 	movl	%esp, %ebx			/* pass sigframe */
@@ -27,10 +23,6 @@
 linux_rt_sigcode:
 	call	*LINUX_RT_SIGF_HANDLER(%esp)
 	leal	LINUX_RT_SIGF_UC(%esp),%ebx	/* linux ucp */
-#if 0
-	movl	LINUX_SC_GS(%ebx),%gs
-#endif
-	movl	LINUX_SC_FS(%ebx),%fs
 	movl	LINUX_SC_ES(%ebx),%es
 	movl	LINUX_SC_DS(%ebx),%ds
 	push	%eax				/* fake ret addr */

==== //depot/projects/linuxolator/src/sys/amd64/linux32/linux32_machdep.c#37 (text+ko) ====

@@ -724,8 +724,9 @@
 				    sd.sd_gran);
 #endif
 			td2->td_pcb->pcb_gsbase = (register_t)info.base_addr;
-			td2->td_pcb->pcb_gs32p = (caddr_t)&gdt[GUGS32_SEL];
-			memcpy(&td2->td_pcb->pcb_gs32sd, &sd, sizeof(sd));
+			td2->td_pcb->pcb_gs32sd = sd;
+			td2->td_pcb->pcb_gs32p = &gdt[GUGS32_SEL];
+			td2->td_pcb->pcb_flags |= PCB_32BIT;
 		}
 	}
 
@@ -1350,11 +1351,11 @@
 
 	critical_enter();
 	td->td_pcb->pcb_gsbase = (register_t)info.base_addr;
-	td->td_pcb->pcb_gs32p = (caddr_t)&gdt[GUGS32_SEL];
-	memcpy(&td->td_pcb->pcb_gs32sd, &sd, sizeof(sd));
+	td->td_pcb->pcb_gs32sd = gdt[GUGS32_SEL] = sd;
+	td->td_pcb->pcb_gs32p = &gdt[GUGS32_SEL];
+	td->td_pcb->pcb_flags |= PCB_32BIT;
 	wrmsr(MSR_KGSBASE, td->td_pcb->pcb_gsbase);
-	gdt[GUGS32_SEL] = sd;
 	critical_exit();
-   
+
 	return (0);
 }

==== //depot/projects/linuxolator/src/sys/amd64/linux32/linux32_sysvec.c#11 (text+ko) ====

@@ -408,6 +408,7 @@
 	td->td_pcb->pcb_ds = _udatasel;
 	load_es(_udatasel);
 	td->td_pcb->pcb_es = _udatasel;
+	/* leave user %fs and %gs untouched */
 	PROC_LOCK(p);
 	mtx_lock(&psp->ps_mtx);
 }
@@ -528,6 +529,7 @@
 	td->td_pcb->pcb_ds = _udatasel;
 	load_es(_udatasel);
 	td->td_pcb->pcb_es = _udatasel;
+	/* leave user %fs and %gs untouched */
 	PROC_LOCK(p);
 	mtx_lock(&psp->ps_mtx);
 }
@@ -813,10 +815,12 @@
 	struct trapframe *regs = td->td_frame;
 	struct pcb *pcb = td->td_pcb;
 
+	critical_enter();
 	wrmsr(MSR_FSBASE, 0);
 	wrmsr(MSR_KGSBASE, 0);	/* User value while we're in the kernel */
 	pcb->pcb_fsbase = 0;
 	pcb->pcb_gsbase = 0;
+	critical_exit();
 	load_ds(_udatasel);
 	load_es(_udatasel);
 	load_fs(_udatasel);
@@ -825,7 +829,6 @@
 	pcb->pcb_es = _udatasel;
 	pcb->pcb_fs = _udatasel;
 	pcb->pcb_gs = _udatasel;
-	pcb->pcb_gs32p = NULL;
 
 	bzero((char *)regs, sizeof(struct trapframe));
 	regs->tf_rip = entry;



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