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