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 290d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughes#include <limits.h> 300d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughes#include <pthread.h> 310d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughes#include <stdbool.h> 3231e72bc3289acdd85b0b745fbf64c5949ca33432Jack Ren 330d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughes#include <asm/ldt.h> 341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 350d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughesextern int __set_thread_area(struct user_desc*); 361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 370d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughes__LIBC_HIDDEN__ void __init_user_desc(struct user_desc* result, bool allocate, void* base_addr) { 380d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughes if (allocate) { 390d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughes // Let the kernel choose. 400d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughes result->entry_number = -1; 410d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughes } else { 420d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughes // Get the existing entry number from %gs. 430d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughes uint32_t gs; 440d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughes __asm__ __volatile__("movw %%gs, %w0" : "=q"(gs) /*output*/); 450d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughes result->entry_number = (gs & 0xffff) >> 3; 460d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughes } 471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 480d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughes result->base_addr = (uintptr_t) base_addr; 491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 500d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughes result->limit = PAGE_SIZE; 511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 520d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughes result->seg_32bit = 1; 530d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughes result->contents = MODIFY_LDT_CONTENTS_DATA; 540d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughes result->read_exec_only = 0; 550d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughes result->limit_in_pages = 1; 560d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughes result->seg_not_present = 0; 570d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughes result->useable = 1; 581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 60a75869f0b2528079503d2e4dd2174142ab1df904Elliott Hughes__LIBC_HIDDEN__ int __set_tls(void* ptr) { 610d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughes struct user_desc tls_descriptor; 620d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughes __init_user_desc(&tls_descriptor, true, ptr); 631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 640d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughes int rc = __set_thread_area(&tls_descriptor); 650d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughes if (rc != -1) { 660d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughes // Change %gs to be new GDT entry. 670d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughes uint16_t table_indicator = 0; // GDT 680d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughes uint16_t rpl = 3; // Requested privilege level 690d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughes uint16_t selector = (tls_descriptor.entry_number << 3) | table_indicator | rpl; 700d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughes __asm__ __volatile__("movw %w0, %%gs" : /*output*/ : "q"(selector) /*input*/ : /*clobber*/); 710d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughes } 721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 730d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughes return rc; 740d236aa3f1e6d31b0c729448ae9d3ed1cad23fb4Elliott Hughes} 75