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