1 /* 2 * Copyright 2014, Paweł Dziepak, pdziepak@quarnos.org. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include "elf_tls.h" 7 8 #include <stdlib.h> 9 #include <string.h> 10 11 #include <support/TLS.h> 12 13 #include <tls.h> 14 15 #include <util/kernel_cpp.h> 16 17 18 class TLSBlock { 19 public: 20 inline TLSBlock(); 21 inline TLSBlock(void* pointer); 22 23 inline status_t Initialize(unsigned dso); 24 25 void Destroy(); 26 27 bool IsInvalid() const { return fPointer == NULL; } 28 29 void* operator+(addr_t offset) const 30 { return (void*)((addr_t)fPointer + offset); } 31 32 private: 33 void* fPointer; 34 }; 35 36 class Generation { 37 public: 38 inline Generation(); 39 40 unsigned Counter() const { return fCounter; } 41 unsigned Size() const { return fSize; } 42 43 void SetCounter(unsigned counter) { fCounter = counter; } 44 void SetSize(unsigned size) { fSize = size; } 45 46 private: 47 unsigned fCounter; 48 unsigned fSize; 49 }; 50 51 class DynamicThreadVector { 52 public: 53 inline DynamicThreadVector(); 54 55 void DestroyAll(); 56 57 inline TLSBlock& operator[](unsigned dso); 58 59 private: 60 bool _DoesExist() const { return *fVector != NULL; } 61 unsigned _Size() const 62 { return _DoesExist() 63 ? fGeneration->Size() : 0; } 64 65 unsigned _Generation() const; 66 67 status_t _ResizeVector(unsigned minimumSize); 68 69 TLSBlock** fVector; 70 Generation* fGeneration; 71 TLSBlock fNullBlock; 72 }; 73 74 75 TLSBlockTemplates* TLSBlockTemplates::fInstance; 76 77 78 void 79 TLSBlockTemplate::SetBaseAddress(addr_t baseAddress) 80 { 81 fAddress = (void*)((addr_t)fAddress + baseAddress); 82 } 83 84 85 TLSBlock 86 TLSBlockTemplate::CreateBlock() 87 { 88 void* pointer = malloc(fMemorySize); 89 if (pointer == NULL) 90 return TLSBlock(); 91 memcpy(pointer, fAddress, fFileSize); 92 if (fMemorySize > fFileSize) 93 memset((char*)pointer + fFileSize, 0, fMemorySize - fFileSize); 94 return TLSBlock(pointer); 95 } 96 97 98 TLSBlockTemplates& 99 TLSBlockTemplates::Get() 100 { 101 if (fInstance == NULL) 102 fInstance = new TLSBlockTemplates; 103 return *fInstance; 104 } 105 106 107 unsigned 108 TLSBlockTemplates::Register(const TLSBlockTemplate& block) 109 { 110 unsigned dso; 111 112 if (!fFreeDSOs.empty()) { 113 dso = fFreeDSOs.back(); 114 fFreeDSOs.pop_back(); 115 fTemplates[dso] = block; 116 } else { 117 dso = fTemplates.size(); 118 fTemplates.push_back(block); 119 } 120 121 fTemplates[dso].SetGeneration(fGeneration); 122 return dso; 123 } 124 125 126 void 127 TLSBlockTemplates::Unregister(unsigned dso) 128 { 129 if (dso == unsigned(-1)) 130 return; 131 132 fGeneration++; 133 fFreeDSOs.push_back(dso); 134 } 135 136 137 void 138 TLSBlockTemplates::SetBaseAddress(unsigned dso, addr_t baseAddress) 139 { 140 if (dso != unsigned(-1)) 141 fTemplates[dso].SetBaseAddress(baseAddress); 142 } 143 144 145 unsigned 146 TLSBlockTemplates::GetGeneration(unsigned dso) const 147 { 148 if (dso == unsigned(-1)) 149 return fGeneration; 150 return fTemplates[dso].Generation(); 151 } 152 153 154 TLSBlock 155 TLSBlockTemplates::CreateBlock(unsigned dso) 156 { 157 return fTemplates[dso].CreateBlock(); 158 } 159 160 161 TLSBlockTemplates::TLSBlockTemplates() 162 : 163 fGeneration(0) 164 { 165 } 166 167 168 TLSBlock::TLSBlock() 169 : 170 fPointer(NULL) 171 { 172 } 173 174 175 TLSBlock::TLSBlock(void* pointer) 176 : 177 fPointer(pointer) 178 { 179 } 180 181 182 status_t 183 TLSBlock::Initialize(unsigned dso) 184 { 185 fPointer = TLSBlockTemplates::Get().CreateBlock(dso).fPointer; 186 return fPointer != NULL ? B_OK : B_NO_MEMORY; 187 } 188 189 190 void 191 TLSBlock::Destroy() 192 { 193 free(fPointer); 194 fPointer = NULL; 195 } 196 197 198 Generation::Generation() 199 : 200 fCounter(0), 201 fSize(0) 202 { 203 } 204 205 206 DynamicThreadVector::DynamicThreadVector() 207 : 208 fVector((TLSBlock**)tls_address(TLS_DYNAMIC_THREAD_VECTOR)), 209 fGeneration(NULL) 210 { 211 if (*fVector != NULL) 212 fGeneration = (Generation*)*(void**)*fVector; 213 } 214 215 216 void 217 DynamicThreadVector::DestroyAll() 218 { 219 for (unsigned i = 0; i < _Size(); i++) { 220 TLSBlock& block = (*fVector)[i + 1]; 221 if (!block.IsInvalid()) 222 block.Destroy(); 223 } 224 225 free(*fVector); 226 *fVector = NULL; 227 228 delete fGeneration; 229 } 230 231 232 TLSBlock& 233 DynamicThreadVector::operator[](unsigned dso) 234 { 235 unsigned generation = TLSBlockTemplates::Get().GetGeneration(-1); 236 if (_Generation() < generation) { 237 for (unsigned i = 0; i < _Size(); i++) { 238 TLSBlock& block = (*fVector)[i + 1]; 239 unsigned dsoGeneration 240 = TLSBlockTemplates::Get().GetGeneration(dso); 241 if (_Generation() < dsoGeneration && dsoGeneration <= generation) 242 block.Destroy(); 243 } 244 245 fGeneration->SetCounter(generation); 246 } 247 248 if (_Size() <= dso) { 249 status_t result = _ResizeVector(dso + 1); 250 if (result != B_OK) 251 return fNullBlock; 252 } 253 254 TLSBlock& block = (*fVector)[dso + 1]; 255 if (block.IsInvalid()) { 256 status_t result = block.Initialize(dso); 257 if (result != B_OK) 258 return fNullBlock; 259 }; 260 261 return block; 262 } 263 264 265 unsigned 266 DynamicThreadVector::_Generation() const 267 { 268 if (fGeneration != NULL) 269 return fGeneration->Counter(); 270 return unsigned(-1); 271 } 272 273 274 status_t 275 DynamicThreadVector::_ResizeVector(unsigned minimumSize) 276 { 277 static const unsigned kInitialSize = 4; 278 unsigned size = std::max(minimumSize, kInitialSize); 279 unsigned oldSize = _Size(); 280 if (size <= oldSize) 281 return B_OK; 282 283 void* newVector = realloc(*fVector, (size + 1) * sizeof(TLSBlock)); 284 if (newVector == NULL) 285 return B_NO_MEMORY; 286 287 *fVector = (TLSBlock*)newVector; 288 memset(*fVector + oldSize + 1, 0, (size - oldSize) * sizeof(TLSBlock)); 289 if (fGeneration == NULL) { 290 fGeneration = new Generation; 291 if (fGeneration == NULL) 292 return B_NO_MEMORY; 293 } 294 295 *(Generation**)*fVector = fGeneration; 296 fGeneration->SetSize(size); 297 298 return B_OK; 299 } 300 301 302 void* 303 get_tls_address(unsigned dso, addr_t offset) 304 { 305 DynamicThreadVector dynamicThreadVector; 306 TLSBlock& block = dynamicThreadVector[dso]; 307 if (block.IsInvalid()) 308 return NULL; 309 return block + offset; 310 } 311 312 313 void 314 destroy_thread_tls() 315 { 316 DynamicThreadVector().DestroyAll(); 317 } 318 319