1b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines/*
2b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines * Copyright 2011, The Android Open Source Project
3b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines *
4b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines * Licensed under the Apache License, Version 2.0 (the "License");
5b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines * you may not use this file except in compliance with the License.
6b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines * You may obtain a copy of the License at
7b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines *
8b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines *     http://www.apache.org/licenses/LICENSE-2.0
9b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines *
10b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines * Unless required by applicable law or agreed to in writing, software
11b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines * distributed under the License is distributed on an "AS IS" BASIS,
12b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines * See the License for the specific language governing permissions and
14b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines * limitations under the License.
15b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines */
16b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines
17b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines#include "StubLayout.h"
18b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines
19b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines#include "utils/flush_cpu_cache.h"
20b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines#include "utils/raw_ostream.h"
21b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines#include "utils/rsl_assert.h"
22b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines
23b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines#include <stdint.h>
24b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines#include <stdlib.h>
25b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines#include <sys/mman.h>
26b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines
27b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen HinesStubLayout::StubLayout() : table(NULL), count(0) {
28b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines}
29b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines
30b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hinesvoid StubLayout::initStubTable(unsigned char *table_, size_t count_) {
31b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  table = table_;
32b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  count = count_;
33b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines}
34b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines
35b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hinesvoid *StubLayout::allocateStub(void *addr) {
36b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  // Check if we have created this stub or not.
37b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  std::map<void *, void *>::iterator index_iter = stub_index.find(addr);
38b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines
39b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  if (index_iter != stub_index.end()) {
40b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines    return index_iter->second;
41b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  }
42b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines
43b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  // We have to create a new stub
44b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  if (count == 0) {
45b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines    // No free stub slot is available
46b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines    return NULL;
47b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  }
48b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines
49b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  // Initialize the stub
50b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  unsigned char *stub = table;
51b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  setStubAddress(stub, addr);
52b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  stub_index.insert(std::make_pair(addr, stub));
53b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines
54b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  // Increase the free stub slot pointer
55b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  table += getUnitStubSize();
56b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  count--;
57b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines
58b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  return stub;
59b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines}
60b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines
61b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hinessize_t StubLayout::calcStubTableSize(size_t count) const {
62b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  return count * getUnitStubSize();
63b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines}
64b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines
65b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hinessize_t StubLayoutARM::getUnitStubSize() const {
66b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  return 8;
67b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines}
68b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines
69b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hinesvoid StubLayoutARM::setStubAddress(void *stub_, void *addr) {
70b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  uint8_t *stub = (uint8_t *)stub_;
71b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  stub[0] = 0x04; // ldr pc, [pc, #-4]
72b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  stub[1] = 0xf0; // ldr pc, [pc, #-4]
73b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  stub[2] = 0x1f; // ldr pc, [pc, #-4]
74b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  stub[3] = 0xe5; // ldr pc, [pc, #-4]
75b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines
76b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  void **target = (void **)(stub + 4);
77b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  *target = addr;
78b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines}
79b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines
80b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hinessize_t StubLayoutMIPS::getUnitStubSize() const {
81b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  return 16;
82b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines}
83b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines
84b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hinesvoid StubLayoutMIPS::setStubAddress(void *stub_, void *addr) {
85b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  uint32_t addr32 = (uint32_t)(uintptr_t)addr;
86b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  uint16_t addr_hi16 = (addr32 >> 16) &  0xffff;
87b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  uint16_t addr_lo16 = addr32 & 0xffff;
88b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines
89b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  uint32_t *stub = (uint32_t *)stub_;
90b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  stub[0] = 0x3c190000ul | addr_hi16; // lui
91b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  stub[1] = 0x37390000ul | addr_lo16; // ori
92b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  stub[2] = 0x03200008ul; // jr (jump register)
93b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines  stub[3] = 0x00000000ul; // nop
94b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines}
95