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