[9fans] some x86 Segment descriptor experiments

[9fans] some x86 Segment descriptor experiments

Post by cinap_lenr » Thu, 15 May 2008 07:14:17


I'm trying to implement TLS support for linuxemu. TLS on
linux works as following:

here is a syscall called set_thread_area() where a struct is
passed containing something like a segment descriptor that
is stored for the process and is switched in the gdt when
the process gets resumed for execution.

the linux thread library allocates some memory, makes an descriptor
with the base address on that memory using set_thread_area, build
segment selector for it and stores that on GS segment register.
that memory is then accessed with the GS segment prefixed so that
every thread ends up with its own TLS block.

For testing, i reserved 2 slots in the Plan9 gdt and wrote a
driver to read/write the slots from userspace. I also needed to comment
out a check that disallows changing the segment register GS and
FS to something other than UDSEG.

This worked fine so far... i could get bash running with libthread and
TLS initialization. (They crash with null-pointer exception when
here is no valid segment descriptor installed)

Things got interesting when i tried to make the descriptors
local for every process. (Thats the whole idea of TLS)

I put a Segdesc tlsdescr[2]; array on the PMMU struct in pc/dat.h
and added code in port/devproc.c to read/write that array from

To switch the gdt entries in when the program gets resumed,
added something like this in pc/main.c:

void procrestore(Proc *p){
+ m->gdt[UTLSSEG0] = p->tlsdescr[0];
+ m->gdt[UTLSSRG1] = p->tlsdescr[1];

void procsetup(Proc *p){
+ p->tlsdescr[0] = (Segdesc){0, 0};
+ p->tlsdescr[1] = (Segdesc){0, 0};

assuming the segment registers get reloaded when the kernel
restores to userspace in pc/l.s:

TEXT _strayintr(SB), $0
/* ... segment registers get saved ... */
PUSHL SP /* Ureg* argument to trap */
CALL trap(SB)

TEXT forkret(SB), $0
POPL GS /* <- here we reload the segment registers right? */
ADDL $8, SP /* pop error code and trap type */

or are here other paths out of the kernel too?

the reloading is required because as i read from thr processor
documentation, the processor caches the effective contents of a
GDT/LDR descriptor in shadow segment registers and only updates
them on LOAD.

OK... after all... doent work and i have no idea why. Program just crashed
as if here was no segment at all. I added a sleep(1) after i wrote
the p->tlsdescr[x] and then it worked for a short time... and then crashed
the whole kernel...

I have never done any kernelhacking so far and never fiddled with
GDT stuff... So some stupid newbie questions :-)

Does the kernel use any other segment selectors other than CS and DS? If
it doent use GS/FS... this should not have any side effects...
also... a process could change the segment descriptor to some invalid
range... paging would protect the process from doing any harm right?

Can the Mach *m->gdt[] be accessed on restoreproc() without problems?
Do i need to disable interrupts or something?
Are all the segment registers reloaded when the kernel switches back
to userspace? (as the thing above)

Any other idea why this doent work?


[9fans] some x86 Segment descriptor experiments

Post by rminnic » Thu, 15 May 2008 08:28:29

it seems reasonable on first glance. What's the stack barf look like?



[9fans] some x86 Segment descriptor experiments

Post by cinap_lenr » Thu, 15 May 2008 09:15:33

This is a multi-part message in MIME format.

arrrg... i found the problem... of course! Plan9 *does* restore/reload the
segment registers! It does it still in kernel mode. So if a segment
register is set (from usermode) with a selector pointing to my TLS
descriptor, and that descriptor gets changed to {0, 0} again, forkret()
restores/reloads the segment register and *kernel* gets a GP fault.

Now the selector checking in trap() makes sense... arrg >_<

sorry for the noise...

Return-Path: <9fans-bounces+cinap_lenrek= XXXX@XXXXX.COM >
X-Flags: 1001
Delivered-To: GMX delivery to XXXX@XXXXX.COM
Received: (qmail invoked by alias); 13 May 2008 23:29:59 -0000
Received: from gouda.swtch.com (EHLO gouda.swtch.com) []
by mx0.gmx.net (mx036) with SMTP; 14 May 2008 01:29:59 +0200
Received: from localhost ([] helo=gouda.swtch.com)
by gouda.swtch.com with esmtp (Exim 4.67)
(envelope-from < XXXX@XXXXX.COM >)
id 1Jw3tE-0004bJ-VF; Tue, 13 May 2008 23:26:37 +0000
Received: from fg-out-1718.google.com ([])
by gouda.swtch.com with esmtp (Exim 4.67)
(envelope-from < XXXX@XXXXX.COM >) id 1Jw3tA-0004bE-My
for XXXX@XXXXX.COM ; Tue, 13 May 2008 23:26:32 +0000
Received: by fg-out-1718.google.com with SMTP id e21so2384137fga.28
for < XXXX@XXXXX.COM >; Tue, 13 May 2008 16:26:31 -0700 (PDT)
Received: by with SMTP id y16mr671952fga.36.1210721191443;
Tue, 13 May 2008 16:26:31 -0700 (PDT)
Received: by with HTTP; Tue, 13 May 2008 16:26:31 -0700 (PDT)
Message-ID: < XXXX@XXXXX.COM >
Date: Tue, 13 May 2008 16:26:31 -0700
From: "ron minnich" < XXXX@XXXXX.COM >
To: "Fans of the OS Plan 9 from Bell Labs" < XXXX@XXXXX.COM >
In-Reply-To: < XXXX@XXXXX.COM >
MIME-Version: 1.0
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
References: < XXXX@XXXXX.COM >
Subject: Re: [9fans] some x86 Segment descriptor experiments
X-Mailman-Version: 2.1.9
Precedence: list
Reply-To: Fans of the OS Plan 9 from Bell Labs < XXXX@XXXXX.COM >
List-Id: Fans of the OS Plan 9 from Bell Labs <9fans.9fans.net>
List-Unsubscribe: < http://www.yqcomputer.com/ ;,
<mailto: XXXX@XXXXX.COM ?subject=unsubscribe>
List-Archive: < http://www.yqcomputer.com/ ;
List-Post: <mailto: XXXX@XXXXX.COM >
List-Help: <mailto: XXXX@XXXXX.COM ?subject=help>
List-Subscribe: < http://www.yqcomputer.com/ ;,
<mailto: XXXX@XXXXX.COM ?subject=subscribe>
Errors-To: 9fans-bounces+cinap_lenrek= XXXX@XXXXX.COM
X-GMX-Antivirus: -1 (not scanned, may not use virus scanner)
X-GMX-Antispam: 0 (Mail was not recognized as spam)

it seems reasonable on first glance. What's the stack barf look like?