thread_x86.cc revision 578bbdc684db8ed68e9fedbc678669d27fa68b6e
1// Copyright 2011 Google Inc. All Rights Reserved.
2
3#include "thread.h"
4
5#include <asm/ldt.h>
6#include <sys/syscall.h>
7#include <sys/types.h>
8
9#include "macros.h"
10
11namespace art {
12
13void Thread::InitCpu() {
14  // Read LDT
15  CHECK_EQ((size_t)LDT_ENTRY_SIZE, sizeof(uint64_t));
16  uint64_t ldt_[LDT_ENTRIES];
17  syscall(SYS_modify_ldt, 0, ldt_, sizeof(ldt_));
18  // Create empty slot to point at current Thread*
19  struct user_desc ldt_entry;
20  ldt_entry.entry_number = -1;
21  ldt_entry.base_addr = (unsigned int)this;
22  ldt_entry.limit = 4096;
23  ldt_entry.seg_32bit = 1;
24  ldt_entry.contents = MODIFY_LDT_CONTENTS_DATA;
25  ldt_entry.read_exec_only = 0;
26  ldt_entry.limit_in_pages = 0;
27  ldt_entry.seg_not_present = 0;
28  ldt_entry.useable = 1;
29  for (int i = 0; i < LDT_ENTRIES; i++) {
30    if (ldt_[i] == 0) {
31      ldt_entry.entry_number = i;
32      break;
33    }
34  }
35  if (ldt_entry.entry_number >= LDT_ENTRIES) {
36    LOG(FATAL) << "Failed to find available LDT slot";
37  }
38  // Update LDT
39  CHECK_EQ(0, syscall(SYS_modify_ldt, 1, &ldt_entry, sizeof(ldt_entry)));
40  // Change FS to be new LDT entry
41  uint16_t table_indicator = 1 << 2;  // LDT
42  uint16_t rpl = 3;  // Requested privilege level
43  uint16_t selector = (ldt_entry.entry_number << 3) | table_indicator | rpl;
44  // TODO: use our assembler to generate code
45  asm("movw %w0, %%fs"
46      :    // output
47      : "q"(selector)  // input
48      :);  // clobber
49  // Allow easy indirection back to Thread*
50  self_ = this;
51  // Sanity check reads from FS goes to this Thread*
52  Thread* self_check;
53  // TODO: use our assembler to generate code
54  asm("movl %%fs:(%1), %0"
55      : "=r"(self_check)  // output
56      : "r"(OFFSETOF_MEMBER(Thread, self_))  // input
57      :);  // clobber
58  CHECK_EQ(self_check, this);
59}
60
61}  // namespace art
62