11dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/*
21dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
31dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * All rights reserved.
41dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
51dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Redistribution and use in source and binary forms, with or without
61dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * modification, are permitted provided that the following conditions
71dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * are met:
81dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *  * Redistributions of source code must retain the above copyright
91dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    notice, this list of conditions and the following disclaimer.
101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *  * Redistributions in binary form must reproduce the above copyright
111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    notice, this list of conditions and the following disclaimer in
121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    the documentation and/or other materials provided with the
131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    distribution.
141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * SUCH DAMAGE.
271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <pthread.h>
291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstruct user_desc {
321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned int    entry_number;
331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned long   base_addr;
341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned int    limit;
351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned int    seg_32bit:1;
361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned int    contents:2;
371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned int    read_exec_only:1;
381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned int    limit_in_pages:1;
391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned int    seg_not_present:1;
401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned int    useable:1;
411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned int    empty:25;
421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project};
431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectextern int __set_thread_area(struct user_desc *u_info);
451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* the following can't be const, since the first call will
471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * update the 'entry_number' field
481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic struct user_desc  _tls_desc =
501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    -1,
521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    0,
531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    0x1000,
541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    1,
551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    0,
561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    0,
571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    1,
581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    0,
591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    1,
601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    0
611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project};
621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6331e72bc3289acdd85b0b745fbf64c5949ca33432Jack Renstatic pthread_mutex_t  _tls_desc_lock = PTHREAD_MUTEX_INITIALIZER;
6431e72bc3289acdd85b0b745fbf64c5949ca33432Jack Ren
651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstruct _thread_area_head {
661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    void *self;
671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project};
681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* we implement thread local storage through the gs: segment descriptor
701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * we create a segment descriptor for the tls
711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint __set_tls(void *ptr)
731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int   rc, segment;
751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7631e72bc3289acdd85b0b745fbf64c5949ca33432Jack Ren    pthread_mutex_lock(&_tls_desc_lock);
771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    _tls_desc.base_addr = (unsigned long)ptr;
781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* We also need to write the location of the tls to ptr[0] */
801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    ((struct _thread_area_head *)ptr)->self = ptr;
811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    rc = __set_thread_area( &_tls_desc );
831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (rc != 0)
841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    {
851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* could not set thread local area */
86c5393b23f6b7837d3b775e447573180fac4923fcJin Wei        pthread_mutex_unlock(&_tls_desc_lock);
871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return -1;
881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* this weird computation comes from GLibc */
911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    segment = _tls_desc.entry_number*8 + 3;
921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    asm __volatile__ (
931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        "   movw %w0, %%gs" :: "q"(segment)
941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    );
9531e72bc3289acdd85b0b745fbf64c5949ca33432Jack Ren    pthread_mutex_unlock(&_tls_desc_lock);
9631e72bc3289acdd85b0b745fbf64c5949ca33432Jack Ren
971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return 0;
981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
102