12faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes/* 22faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * Copyright (C) 2011 The Android Open Source Project 32faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * 42faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * Licensed under the Apache License, Version 2.0 (the "License"); 52faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * you may not use this file except in compliance with the License. 62faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * You may obtain a copy of the License at 72faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * 82faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * http://www.apache.org/licenses/LICENSE-2.0 92faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * 102faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * Unless required by applicable law or agreed to in writing, software 112faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * distributed under the License is distributed on an "AS IS" BASIS, 122faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * See the License for the specific language governing permissions and 142faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * limitations under the License. 152faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes */ 16b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers 17578bbdc684db8ed68e9fedbc678669d27fa68b6eBrian Carlstrom#include "thread.h" 18578bbdc684db8ed68e9fedbc678669d27fa68b6eBrian Carlstrom 19b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers#include <sys/syscall.h> 20b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers#include <sys/types.h> 21578bbdc684db8ed68e9fedbc678669d27fa68b6eBrian Carlstrom 227655f29fabc0a12765de828914a18314382e5a35Ian Rogers#include "asm_support_x86.h" 23761600567d73b23324ae0251e871c15d6849ffd8Elliott Hughes#include "base/macros.h" 2450b35e2fd1a68cd1240e4a9d9f363e11764957d1Ian Rogers#include "thread.h" 25891f4a94ded25b92b920c6f1ba908b1411138b60Ian Rogers#include "thread_list.h" 26b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers 27ad6c9c3dbf7541340f22ccbb333f08556ad7e000Elliott Hughes#if defined(__APPLE__) 28ad6c9c3dbf7541340f22ccbb333f08556ad7e000Elliott Hughes#include <architecture/i386/table.h> 29ad6c9c3dbf7541340f22ccbb333f08556ad7e000Elliott Hughes#include <i386/user_ldt.h> 3042f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughesstruct descriptor_table_entry_t { 3142f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes uint16_t limit0; 3242f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes uint16_t base0; 3342f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes unsigned base1: 8, type: 4, s: 1, dpl: 2, p: 1; 3442f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes unsigned limit: 4, avl: 1, l: 1, d: 1, g: 1, base2: 8; 3542f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes} __attribute__((packed)); 3642f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes#define MODIFY_LDT_CONTENTS_DATA 0 37ad6c9c3dbf7541340f22ccbb333f08556ad7e000Elliott Hughes#else 38ad6c9c3dbf7541340f22ccbb333f08556ad7e000Elliott Hughes#include <asm/ldt.h> 39ad6c9c3dbf7541340f22ccbb333f08556ad7e000Elliott Hughes#endif 40ad6c9c3dbf7541340f22ccbb333f08556ad7e000Elliott Hughes 41b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogersnamespace art { 42b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers 43b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogersvoid Thread::InitCpu() { 448323972b16642b8a3accf6fcbb6677b65a7a20fbElliott Hughes static Mutex modify_ldt_lock("modify_ldt lock"); 4550b35e2fd1a68cd1240e4a9d9f363e11764957d1Ian Rogers MutexLock mu(Thread::Current(), modify_ldt_lock); 46891f4a94ded25b92b920c6f1ba908b1411138b60Ian Rogers 4742f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes const uintptr_t base = reinterpret_cast<uintptr_t>(this); 4842f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes const size_t limit = kPageSize; 4942f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes 5042f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes const int contents = MODIFY_LDT_CONTENTS_DATA; 5142f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes const int seg_32bit = 1; 5242f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes const int read_exec_only = 0; 5342f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes const int limit_in_pages = 0; 5442f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes const int seg_not_present = 0; 5542f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes const int useable = 1; 5642f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes 5742f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes int entry_number = -1; 5842f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes 5942f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes#if defined(__APPLE__) 6042f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes descriptor_table_entry_t entry; 6142f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes memset(&entry, 0, sizeof(entry)); 6242f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes entry.limit0 = (limit & 0x0ffff); 6342f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes entry.limit = (limit & 0xf0000) >> 16; 6442f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes entry.base0 = (base & 0x0000ffff); 6542f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes entry.base1 = (base & 0x00ff0000) >> 16; 6642f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes entry.base2 = (base & 0xff000000) >> 24; 6742f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes entry.type = ((read_exec_only ^ 1) << 1) | (contents << 2); 6842f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes entry.s = 1; 6942f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes entry.dpl = 0x3; 7042f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes entry.p = seg_not_present ^ 1; 7142f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes entry.avl = useable; 7242f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes entry.l = 0; 7342f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes entry.d = seg_32bit; 7442f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes entry.g = limit_in_pages; 7542f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes 762d88862f0752a7a0e65145b088f49dabd49d4284Brian Carlstrom entry_number = i386_set_ldt(LDT_AUTO_ALLOC, reinterpret_cast<ldt_entry*>(&entry), 1); 7742f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes if (entry_number == -1) { 7842f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes PLOG(FATAL) << "i386_set_ldt failed"; 7942f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes } 8042f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes#else 8142f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes // Read current LDT entries. 82b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers CHECK_EQ((size_t)LDT_ENTRY_SIZE, sizeof(uint64_t)); 833b6baaa203fa63f1522b2172a1645f90412afdaeElliott Hughes std::vector<uint64_t> ldt(LDT_ENTRIES); 843b6baaa203fa63f1522b2172a1645f90412afdaeElliott Hughes size_t ldt_size(sizeof(uint64_t) * ldt.size()); 853b6baaa203fa63f1522b2172a1645f90412afdaeElliott Hughes memset(&ldt[0], 0, ldt_size); 8642f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes // TODO: why doesn't this return LDT_ENTRY_SIZE * LDT_ENTRIES for the main thread? 87942df41c03ddb9f7b47a34fcfc4414d8b8ca8ce1Elliott Hughes syscall(__NR_modify_ldt, 0, &ldt[0], ldt_size); 8842f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes 8942f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes // Find the first empty slot. 9042f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes for (entry_number = 0; entry_number < LDT_ENTRIES && ldt[entry_number] != 0; ++entry_number) { 91b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers } 9242f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes if (entry_number >= LDT_ENTRIES) { 9342f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes LOG(FATAL) << "Failed to find a free LDT slot"; 94b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers } 9542f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes 9642f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes // Update LDT entry. 9742f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes user_desc ldt_entry; 9842f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes memset(&ldt_entry, 0, sizeof(ldt_entry)); 9942f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes ldt_entry.entry_number = entry_number; 10042f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes ldt_entry.base_addr = base; 10142f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes ldt_entry.limit = limit; 10242f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes ldt_entry.seg_32bit = seg_32bit; 10342f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes ldt_entry.contents = contents; 10442f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes ldt_entry.read_exec_only = read_exec_only; 10542f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes ldt_entry.limit_in_pages = limit_in_pages; 10642f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes ldt_entry.seg_not_present = seg_not_present; 10742f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes ldt_entry.useable = useable; 108942df41c03ddb9f7b47a34fcfc4414d8b8ca8ce1Elliott Hughes CHECK_EQ(0, syscall(__NR_modify_ldt, 1, &ldt_entry, sizeof(ldt_entry))); 10942f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes entry_number = ldt_entry.entry_number; 11042f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes#endif 11142f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes 11242f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes // Change %fs to be new LDT entry. 113b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers uint16_t table_indicator = 1 << 2; // LDT 114b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers uint16_t rpl = 3; // Requested privilege level 11542f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes uint16_t selector = (entry_number << 3) | table_indicator | rpl; 116b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers // TODO: use our assembler to generate code 1177834cbd5d8a0e61db14339910d2223a3e59d7efcElliott Hughes __asm__ __volatile__("movw %w0, %%fs" 118b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers : // output 119b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers : "q"(selector) // input 120b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers :); // clobber 12142f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes 12242f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes // Allow easy indirection back to Thread*. 123b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers self_ = this; 12442f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes 12542f54adfec08082c6d661078b923c8cc75e16b7cElliott Hughes // Sanity check that reads from %fs point to this Thread*. 126b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers Thread* self_check; 127b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers // TODO: use our assembler to generate code 1289651f425f7413772a7b5352da2b04eb7de7d416fIan Rogers CHECK_EQ(THREAD_SELF_OFFSET, OFFSETOF_MEMBER(Thread, self_)); 1297834cbd5d8a0e61db14339910d2223a3e59d7efcElliott Hughes __asm__ __volatile__("movl %%fs:(%1), %0" 130b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers : "=r"(self_check) // output 1319651f425f7413772a7b5352da2b04eb7de7d416fIan Rogers : "r"(THREAD_SELF_OFFSET) // input 132b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers :); // clobber 133b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers CHECK_EQ(self_check, this); 1340399dde18753aa9bd2bd0d7cf60beef154d164a4Ian Rogers 1350399dde18753aa9bd2bd0d7cf60beef154d164a4Ian Rogers // Sanity check other offsets. 1360399dde18753aa9bd2bd0d7cf60beef154d164a4Ian Rogers CHECK_EQ(THREAD_EXCEPTION_OFFSET, OFFSETOF_MEMBER(Thread, exception_)); 137b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers} 138b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers 139b033c75ebda80ac75f936366fe78d1edf5cec937Ian Rogers} // namespace art 140