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 18class TLSBlock { 19public: 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 + TLS_DTV_OFFSET + offset); } 31 32private: 33 void* fPointer; 34}; 35 36class Generation { 37public: 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 46private: 47 unsigned fCounter; 48 unsigned fSize; 49}; 50 51class DynamicThreadVector { 52public: 53 inline DynamicThreadVector(); 54 55 void DestroyAll(); 56 57 inline TLSBlock& operator[](unsigned dso); 58 59private: 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 75TLSBlockTemplates* TLSBlockTemplates::fInstance; 76 77 78void 79TLSBlockTemplate::SetBaseAddress(addr_t baseAddress) 80{ 81 fAddress = (void*)((addr_t)fAddress + baseAddress); 82} 83 84 85TLSBlock 86TLSBlockTemplate::CreateBlock() 87{ 88 void* pointer = malloc(fMemorySize + TLS_DTV_OFFSET); 89 if (pointer == NULL) 90 return TLSBlock(); 91 memset(pointer, 0, TLS_DTV_OFFSET); 92 memcpy((char*)pointer + TLS_DTV_OFFSET, fAddress, fFileSize); 93 if (fMemorySize > fFileSize) 94 memset((char*)pointer + TLS_DTV_OFFSET + fFileSize, 0, fMemorySize - fFileSize); 95 return TLSBlock(pointer); 96} 97 98 99TLSBlockTemplates& 100TLSBlockTemplates::Get() 101{ 102 if (fInstance == NULL) 103 fInstance = new TLSBlockTemplates; 104 return *fInstance; 105} 106 107 108unsigned 109TLSBlockTemplates::Register(const TLSBlockTemplate& block) 110{ 111 unsigned dso; 112 113 if (!fFreeDSOs.empty()) { 114 dso = fFreeDSOs.back(); 115 fFreeDSOs.pop_back(); 116 fTemplates[dso] = block; 117 } else { 118 dso = fTemplates.size(); 119 fTemplates.push_back(block); 120 } 121 122 fTemplates[dso].SetGeneration(fGeneration); 123 return dso; 124} 125 126 127void 128TLSBlockTemplates::Unregister(unsigned dso) 129{ 130 if (dso == unsigned(-1)) 131 return; 132 133 fGeneration++; 134 fFreeDSOs.push_back(dso); 135} 136 137 138void 139TLSBlockTemplates::SetBaseAddress(unsigned dso, addr_t baseAddress) 140{ 141 if (dso != unsigned(-1)) 142 fTemplates[dso].SetBaseAddress(baseAddress); 143} 144 145 146unsigned 147TLSBlockTemplates::GetGeneration(unsigned dso) const 148{ 149 if (dso == unsigned(-1)) 150 return fGeneration; 151 return fTemplates[dso].Generation(); 152} 153 154 155TLSBlock 156TLSBlockTemplates::CreateBlock(unsigned dso) 157{ 158 return fTemplates[dso].CreateBlock(); 159} 160 161 162TLSBlockTemplates::TLSBlockTemplates() 163 : 164 fGeneration(0) 165{ 166} 167 168 169TLSBlock::TLSBlock() 170 : 171 fPointer(NULL) 172{ 173} 174 175 176TLSBlock::TLSBlock(void* pointer) 177 : 178 fPointer(pointer) 179{ 180} 181 182 183status_t 184TLSBlock::Initialize(unsigned dso) 185{ 186 fPointer = TLSBlockTemplates::Get().CreateBlock(dso).fPointer; 187 return fPointer != NULL ? B_OK : B_NO_MEMORY; 188} 189 190 191void 192TLSBlock::Destroy() 193{ 194 free(fPointer); 195 fPointer = NULL; 196} 197 198 199Generation::Generation() 200 : 201 fCounter(0), 202 fSize(0) 203{ 204} 205 206 207DynamicThreadVector::DynamicThreadVector() 208 : 209 fVector((TLSBlock**)tls_address(TLS_DYNAMIC_THREAD_VECTOR)), 210 fGeneration(NULL) 211{ 212 if (*fVector != NULL) 213 fGeneration = (Generation*)*(void**)*fVector; 214} 215 216 217void 218DynamicThreadVector::DestroyAll() 219{ 220 for (unsigned i = 0; i < _Size(); i++) { 221 TLSBlock& block = (*fVector)[i + 1]; 222 if (!block.IsInvalid()) 223 block.Destroy(); 224 } 225 226 free(*fVector); 227 *fVector = NULL; 228 229 delete fGeneration; 230} 231 232 233TLSBlock& 234DynamicThreadVector::operator[](unsigned dso) 235{ 236 unsigned generation = TLSBlockTemplates::Get().GetGeneration(-1); 237 if (_Generation() < generation) { 238 // We need to destroy any blocks whose DSO generation has changed 239 // to be greater than our own generation. 240 for (unsigned dsoIndex = 0; dsoIndex < _Size(); dsoIndex++) { 241 TLSBlock& block = (*fVector)[dsoIndex + 1]; 242 unsigned dsoGeneration 243 = TLSBlockTemplates::Get().GetGeneration(dsoIndex); 244 if (dsoGeneration > _Generation() && dsoGeneration <= generation) 245 block.Destroy(); 246 } 247 248 fGeneration->SetCounter(generation); 249 } 250 251 if (_Size() <= dso) { 252 status_t result = _ResizeVector(dso + 1); 253 if (result != B_OK) 254 return fNullBlock; 255 } 256 257 TLSBlock& block = (*fVector)[dso + 1]; 258 if (block.IsInvalid()) { 259 status_t result = block.Initialize(dso); 260 if (result != B_OK) 261 return fNullBlock; 262 } 263 264 return block; 265} 266 267 268unsigned 269DynamicThreadVector::_Generation() const 270{ 271 if (fGeneration != NULL) 272 return fGeneration->Counter(); 273 return unsigned(-1); 274} 275 276 277status_t 278DynamicThreadVector::_ResizeVector(unsigned minimumSize) 279{ 280 static const unsigned kInitialSize = 4; 281 unsigned size = std::max(minimumSize, kInitialSize); 282 unsigned oldSize = _Size(); 283 if (size <= oldSize) 284 return B_OK; 285 286 void* newVector = realloc(*fVector, (size + 1) * sizeof(TLSBlock)); 287 if (newVector == NULL) 288 return B_NO_MEMORY; 289 290 *fVector = (TLSBlock*)newVector; 291 memset(*fVector + oldSize + 1, 0, (size - oldSize) * sizeof(TLSBlock)); 292 if (fGeneration == NULL) { 293 fGeneration = new Generation; 294 if (fGeneration == NULL) 295 return B_NO_MEMORY; 296 } 297 298 *(Generation**)*fVector = fGeneration; 299 fGeneration->SetSize(size); 300 301 return B_OK; 302} 303 304 305void* 306get_tls_address(unsigned dso, addr_t offset) 307{ 308 DynamicThreadVector dynamicThreadVector; 309 TLSBlock& block = dynamicThreadVector[dso]; 310 if (block.IsInvalid()) 311 return NULL; 312 return block + offset; 313} 314 315 316void 317destroy_thread_tls() 318{ 319 DynamicThreadVector().DestroyAll(); 320} 321 322