summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJaymes Wilks <mjwilks@us.ibm.com>2019-02-04 14:06:56 -0600
committerDaniel M. Crowell <dcrowell@us.ibm.com>2019-03-11 17:07:52 -0500
commitf5475890894b4d542f622cee27604de15b41bb4b (patch)
treec7462a5d51689fab8dfbe66dd87c6263e8e44959 /src
parent676c584aaa7046d45d0c9ac3851699566d905bac (diff)
downloadtalos-hostboot-f5475890894b4d542f622cee27604de15b41bb4b.tar.gz
talos-hostboot-f5475890894b4d542f622cee27604de15b41bb4b.zip
Support thread local storage
Generally adds support to declare variables as thread_local - Add support in HBRT start assembly to skip adjusting TLS relocations - Add support in linker to generate tagged TLS entries - Update linker to process TLS relocations correctly - Update TLS code to ignore top half of module ID - Update module images to hold a "module ID" - Update custome linker to update module ID during binary link - Update TLS code to track TLS sections via module ID Change-Id: I1589550d7787beb08827ca24a728397dedf0373b RTC: 147599 Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/71709 Reviewed-by: Ilya Smirnov <ismirno@us.ibm.com> Reviewed-by: Michael Baiocchi <mbaiocch@us.ibm.com> Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com> Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com> Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src')
-rw-r--r--src/build/linker/linker.C123
-rw-r--r--src/include/util/nolockfree/stack.H115
-rw-r--r--src/lib/makefile3
-rw-r--r--src/lib/tls.C123
-rw-r--r--src/lib/tlsrt.C31
-rw-r--r--src/makefile5
-rw-r--r--src/runtime/rt_start.S35
-rw-r--r--src/usr/module_init.C18
-rw-r--r--src/usr/testcore/rtloader/loader.H2
9 files changed, 400 insertions, 55 deletions
diff --git a/src/build/linker/linker.C b/src/build/linker/linker.C
index fe5f651ea..9e4751e41 100644
--- a/src/build/linker/linker.C
+++ b/src/build/linker/linker.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2018 */
+/* Contributors Listed Below - COPYRIGHT 2011,2019 */
/* [+] International Business Machines Corp. */
/* [+] Jan Hlavac */
/* */
@@ -132,6 +132,10 @@ struct Object
FILE * iv_output; //!< output file handle
ssize_t tls_module; //!< module id of this module's
// thread local storage.
+ map<uint64_t,string> tls_vars; //!< keep track of TLS variables in
+ // this module by mapping offsets
+ // to names for use with identifying
+ // unnamed DTPRELs
/**
* Read the object from it's file and extract bfd, text, & data image
* @param[in] i_file : file path
@@ -219,7 +223,7 @@ inline bool Object::isELF()
}
/**
- * Infomraiton needed to build the Module table in each output image
+ * Information needed to build the Module table in each output image
*/
class ModuleTable
{
@@ -289,11 +293,24 @@ vector<ModuleTable> module_tables;
map<string,size_t> weak_symbols;
set<string> all_symbols;
set<string> weak_symbols_to_check;
+
+// map TLS symbol names to TLS module IDs
+map<string, uint64_t> tls_modules;
+
+// map TLS symbol names to TLS offsets
+map<string, uint64_t> tls_offsets;
+
bool includes_extended_image = false;
bool relocation = true;
size_t next_tls_id = 0;
+/**
+ * @brief Marker (ASCII 'TLS' + 0x00) or'd into bit 0 position of a TLS module
+ * relocation to flag it as such for runtime relocation processing
+ */
+const uint64_t TLS_MARKER = 0x544C530000000000ULL;
+
//-----------------------------------------------------------------------------
// MAIN
//-----------------------------------------------------------------------------
@@ -612,6 +629,38 @@ bool Object::write_object()
cout << strerror(error) << endl;
}
+ // Look for the "TLS_MODULE_ID" symbol in the module. If found, seek to
+ // its location in the final binary and update it with the TLS module ID
+ // for this module.
+ if (symbols.find(VFS_TOSTRING(TLS_MODULE_ID)) != symbols.end())
+ {
+ fseek(iv_output, symbols[VFS_TOSTRING(TLS_MODULE_ID)].address
+ + offset + data.vma_offset, SEEK_SET);
+ size_t tlsModuleId = 0;
+ bfd_putb64(get_tls_module(),&tlsModuleId);
+ if (sizeof(tlsModuleId) != fwrite(&tlsModuleId, sizeof(uint8_t),
+ sizeof(tlsModuleId), iv_output))
+ {
+ const int error = errno;
+ cout << "Error writing TLS_MODULE_ID to output: " << endl;
+ cout << strerror(error) << endl;
+ }
+ else
+ {
+ cout << "Setting module ID to " << get_tls_module() << " for "
+ << name << " addr = "
+ << symbols[VFS_TOSTRING(TLS_MODULE_ID)].address
+ << " + " << offset + data.vma_offset << endl;
+ }
+
+ // Seek back to where the cursor would have been, had the module
+ // ID not been updated
+ fseek(iv_output, offset + data.vma_offset + data.size, SEEK_SET);
+ }
+ else
+ {
+ cout << " module ID not found for " << name << endl;
+ }
}
else // binary blob
{
@@ -690,11 +739,27 @@ bool Object::read_relocation()
cout << "\tSymbol: " << syms[i]->name << endl;
cout << "\t\tAddress: " << std::hex << syms[i]->value << endl;
+ bool is_tls = false;
+
// Determine symbol types.
+ if (syms[i]->flags & BSF_THREAD_LOCAL)
+ {
+ cout << "\t\tTLS_VARIABLE" << endl;
+ is_tls = true;
+ }
+
if (syms[i]->flags & BSF_GLOBAL)
{
s.type |= Symbol::GLOBAL;
- cout << "\t\tGLOBAL" << endl;
+ cout << "\t\tGLOBAL";
+ if (is_tls)
+ {
+ cout << " TLS offset: " << bfd_asymbol_value(syms[i]);
+
+ // store the name in a map of offsets to TLS variable names
+ tls_vars[bfd_asymbol_value(syms[i])] = s.name;
+ }
+ cout << endl;
}
else if (syms[i]->flags & (BSF_LOCAL | BSF_WEAK | BSF_GNU_UNIQUE))
{
@@ -827,10 +892,19 @@ bool Object::perform_local_relocations()
bool needs_relocation = true;
+ bool is_weak = false;
+
fseek(iv_output, offset + i->address, SEEK_SET);
fread(data, sizeof(uint64_t), 1, iv_output);
+ if (weak_symbols.find(i->name) != weak_symbols.end())
+ {
+ cout << "\t\tWEAK" << endl;
+ is_weak = true;
+ }
+
address = bfd_getb64(data);
+
if ((address != i->addend) && (address != 0))
{
ostringstream oss;
@@ -855,13 +929,25 @@ bool Object::perform_local_relocations()
address = get_tls_module();
needs_relocation = false;
relocation = address;
+
+ cout << "\t\tTLS_MODULE" << endl;
}
else if (i->type & Symbol::TLS_OFFSET)
{
// Set value to TLS offset.
- address = i->addend - VFS_PPC64_DTPREL_OFFSET;
+ cout << "\t\tTLS_OFFSET" << endl;
+ address = relocation = i->addend - VFS_PPC64_DTPREL_OFFSET;
needs_relocation = false;
- relocation = address;
+
+ // look up the offset in tls_vars find the name and use that
+ // to map the name to the correct TLS offset
+ tls_offsets[tls_vars[i->addend]] = relocation;
+ tls_modules[tls_vars[i->addend]] = get_tls_module();
+ }
+ else if (is_weak && address == 0)
+ {
+ cout << "\tWEAK NULL" << endl;
+ relocation = 0;
}
else // Perform relocation.
{
@@ -956,6 +1042,12 @@ bool Object::perform_global_relocations()
}
else
{
+ bool is_tls = false;
+ if (tls_modules.find(i->name) != tls_modules.end())
+ {
+ is_tls = true;
+ }
+
if (s.type & Symbol::FUNCTION)
{
cout << "\tTOC link for function: " << s.name
@@ -966,7 +1058,28 @@ bool Object::perform_global_relocations()
cout << "\tOffset to " << i->addend << endl;
symbol_addr += i->addend;
}
+
symbol_addr += j->base_addr;
+
+ if (is_tls)
+ {
+ if (i->type & Symbol::TLS_MODULE)
+ {
+ symbol_addr = tls_modules[i->name];
+
+ // Bitwise OR the TLS marker into the relocation
+ // to flag it as a TLS module entry for
+ // relocation processing code. This is safe
+ // since it would take 4 giga-modules to over
+ // flow into that space.
+ symbol_addr |= TLS_MARKER;
+ }
+ else if (i->type & Symbol::TLS_OFFSET)
+ {
+ symbol_addr = tls_offsets[i->name];
+ }
+ }
+
bfd_putb64(symbol_addr, data);
fseek(iv_output, offset + i->address, SEEK_SET);
fwrite(data, sizeof(uint64_t), 1, iv_output);
diff --git a/src/include/util/nolockfree/stack.H b/src/include/util/nolockfree/stack.H
new file mode 100644
index 000000000..bc2bb5fbb
--- /dev/null
+++ b/src/include/util/nolockfree/stack.H
@@ -0,0 +1,115 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/include/util/nolockfree/stack.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2010,2019 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+#ifndef __UTIL_NOLOCKFREE_STACK_H
+#define __UTIL_NOLOCKFREE_STACK_H
+
+#include <stddef.h>
+#include <assert.h>
+
+namespace Util
+{
+ namespace NoLockFree
+ {
+
+ /**
+ * @brief Non-lockfree stack implementation
+ *
+ * This is an intrusive container design, meaning elements being
+ * added to the stack must have a 'next' member of _T* type. This
+ * container is not threadsafe.
+ *
+ * @note: For a lockfree stack implementation, see Util::LockFree::Stack
+ */
+ template <typename _T>
+ class Stack
+ {
+ public:
+
+ /**
+ * @brief Constructor
+ */
+ Stack()
+ : head(nullptr)
+ {
+ }
+
+ /**
+ * @brief Pop an element from the stack.
+ *
+ * @return _T* The pointer to the element popped from the stack
+ */
+ _T* pop();
+
+ /**
+ * @brief Push an element to the stack.
+ *
+ * @param[in] p Pointer to the element to add to the stack.
+ */
+ void push(_T* p);
+
+ /**
+ * @brief Get a pointer to the first element in the stack
+ *
+ * @return _T* The pointer to the first element
+ * @Note: SMP safety of this pointer is not guaranteed.
+ */
+ _T* first();
+
+ private:
+ _T* head;
+ };
+
+ template <typename _T>
+ _T* Stack<_T>::first()
+ {
+ return head;
+ }
+
+ template <typename _T>
+ _T* Stack<_T>::pop()
+ {
+ auto original = head;
+ if (unlikely(nullptr == original))
+ {
+ return nullptr;
+ }
+ head = original->next;
+ return original;
+ }
+
+ template <typename _T>
+ void Stack<_T>::push(_T* p)
+ {
+ p->next = head;
+ head = p;
+ }
+
+ } // End NoLockFree namespace
+
+} // End Util namespace
+
+#endif // __UTIL_NOLOCKFREE_STACK_H
+
diff --git a/src/lib/makefile b/src/lib/makefile
index 5e64025d1..406d5ead8 100644
--- a/src/lib/makefile
+++ b/src/lib/makefile
@@ -5,7 +5,7 @@
#
# OpenPOWER HostBoot Project
#
-# Contributors Listed Below - COPYRIGHT 2010,2017
+# Contributors Listed Below - COPYRIGHT 2010,2019
# [+] International Business Machines Corp.
#
#
@@ -50,6 +50,7 @@ OBJS += utilmisc.o
OBJS += tls.o
OBJS += errno.o
+OBJS += tlsrt.o
ifdef HOSTBOOT_MEMORY_LEAKS
COMMONFLAGS += -DHOSTBOOT_MEMORY_LEAKS=1
diff --git a/src/lib/tls.C b/src/lib/tls.C
index 4fcafb23b..3e2294251 100644
--- a/src/lib/tls.C
+++ b/src/lib/tls.C
@@ -31,9 +31,21 @@
#include <algorithm>
#include <stdlib.h>
#include <string.h>
+#ifndef __HOSTBOOT_RUNTIME
#include <util/lockfree/stack.H>
+#else
+#include <util/nolockfree/stack.H>
+#endif
#include <sys/vfs.h>
+/**
+ * @brief Mask which suppresses ignored portions of a TLS module ID. When
+ * The linker creates a module ID, it prefixes it with "TLS" + 0x00
+ * as the first 32 bits. This mask slices that off to leave just the
+ * normalized module ID
+ */
+const size_t TLS_MODULE_MASK = 0x00000000FFFFFFFFULL;
+
/** Thread Local Storage - How it works.
*
* For background:
@@ -86,8 +98,36 @@ struct __tls_linker_tuple
/** Info about the .tdata section for each module. */
struct __tls_module
{
- void* sect_addr;
- size_t size;
+ void* sect_addr; //< Starting address of module
+ size_t size; //< Size of module
+ size_t module; //< Module ID of this module
+ //< (set by custom linker)
+
+ /**
+ * @brief Default constructor
+ */
+ __tls_module()
+ : sect_addr(0),
+ size(0),
+ module(0)
+ {
+ }
+
+ /**
+ * @brief Specialized contstructor
+ *
+ * @param[in] i_start Module starting address. Must not be nullptr.
+ * @param[in] i_size Module size in bytes
+ * @param[in] i_module Modue ID of the module
+ */
+ __tls_module(void* const i_start,
+ const size_t i_size,
+ const size_t i_module)
+ : sect_addr(i_start),
+ size(i_size),
+ module(i_module)
+ {
+ }
};
/** TLS destructor data. */
@@ -103,7 +143,11 @@ struct __tls_dtor
struct __tls_thread_info
{
size_t count;
+#ifndef __HOSTBOOT_RUNTIME
Util::Lockfree::Stack<__tls_dtor> dtors;
+#else
+ Util::NoLockFree::Stack<__tls_dtor> dtors;
+#endif
void* blobs[0];
};
@@ -114,51 +158,47 @@ std::vector<__tls_module> __tls_pending_modules;
/** Get the previously registered __tls_module data for a TLS variable */
const __tls_module* __tls_get_module(const __tls_linker_tuple* tuple)
{
+ size_t tuple_module = tuple->module & TLS_MODULE_MASK;
+
// Look the module up in the __tls_modules first, in case we've seen
// this module before in another thread.
- if ((__tls_modules.size() > tuple->module) &&
- (__tls_modules[tuple->module].sect_addr != nullptr))
+ if ((__tls_modules.size() > tuple_module) &&
+ (__tls_modules[tuple_module].sect_addr != nullptr))
{
- return &__tls_modules[tuple->module];
+ return &__tls_modules[tuple_module];
}
// We plan to insert a new module, so make sure we can contain it.
- if (__tls_modules.size() <= tuple->module)
+ if (__tls_modules.size() <= tuple_module)
{
- __tls_modules.resize(tuple->module+1);
+ __tls_modules.resize(tuple_module+1);
}
// This is the first time we've seen this module. Need to look up in
// pending.
- // The TLS sections are at the beginning of the .rodata section and the
- // linker tuples are somewhere in .data. Therefore sect_addr < tuple.
- // Search __tls_pending_modules for the highest address section that is
- // less than the tuple address.
- auto best = __tls_pending_modules.begin();
- auto curr = best;
- while(curr != __tls_pending_modules.end())
- {
- if ((curr->sect_addr > best->sect_addr) &&
- (curr->sect_addr < tuple))
+ // The module should have pre-registered its module ID in association
+ // with its starting address and size; look for a module ID match.
+ auto moduleItr = std::find_if(
+ __tls_pending_modules.begin(),
+ __tls_pending_modules.end(),
+ [&tuple_module](const __tls_module& i_module)
{
- best = curr;
- }
- ++curr;
- }
- assert(best != __tls_pending_modules.end());
+ return (tuple_module == i_module.module);
+ });
+ assert(moduleItr != __tls_pending_modules.end());
// Copy it into the __tls_modules and remove it from the pending list.
- __tls_modules[tuple->module] = *best;
- __tls_pending_modules.erase(best);
+ __tls_modules[tuple_module] = *moduleItr;
+ __tls_pending_modules.erase(moduleItr);
- return &__tls_modules[tuple->module];
+ return &__tls_modules[tuple_module];
}
/* Since Hostboot runtime only has a single thread, we'll just create a
* single global TLS area. */
#ifdef __HOSTBOOT_RUNTIME
-task_t __tls_task_struct;
+task_t tls_task_struct;
#endif
/** Get a TLS variable address
@@ -168,6 +208,8 @@ task_t __tls_task_struct;
extern "C"
void* __tls_get_addr(const __tls_linker_tuple* tuple)
{
+ size_t tuple_module = tuple->module & TLS_MODULE_MASK;
+
task_t* task = nullptr;
#ifdef __HOSTBOOT_RUNTIME
task = &tls_task_struct;
@@ -184,36 +226,36 @@ void* __tls_get_addr(const __tls_linker_tuple* tuple)
// - tls[module] is nullptr
// Then: module blob needs to be allocated.
if ((tls_info == nullptr) ||
- (tls_info->count <= tuple->module) ||
- (tls_info->blobs[tuple->module] == nullptr))
+ (tls_info->count <= tuple_module) ||
+ (tls_info->blobs[tuple_module] == nullptr))
{
// If there isn't room for the module's blob, we need to allocate it.
- if ((tls_info == nullptr) || (tls_info->count <= tuple->module))
+ if ((tls_info == nullptr) || (tls_info->count <= tuple_module))
{
- decltype(__tls_thread_info::count) old_size = 0;
+ decltype(__tls_thread_info::count) old_count = 0;
auto new_size = sizeof(__tls_thread_info) +
- sizeof(void*)*(tuple->module+1);
+ sizeof(void*)*(tuple_module+1);
// Allocate or reallocate the tls info.
if (tls_info == nullptr)
{
- old_size = 0;
+ old_count = 0;
tls_info = reinterpret_cast<decltype(tls_info)>(
malloc(new_size));
memset(&tls_info->dtors, '\0', sizeof(tls_info->dtors));
}
else
{
- old_size = tls_info->count;
+ old_count = tls_info->count;
tls_info = reinterpret_cast<decltype(tls_info)>(
realloc(tls_info, new_size));
}
// Clear the newly allocated area and update the count.
- memset(&tls_info->blobs[old_size], '\0', new_size -
- (sizeof(__tls_thread_info) + sizeof(void*)*old_size));
- tls_info->count = tuple->module+1;
+ memset(&tls_info->blobs[old_count], '\0', new_size -
+ (sizeof(__tls_thread_info) + sizeof(void*)*old_count));
+ tls_info->count = tuple_module+1;
// save into task struct.
task->tls_context = tls_info;
@@ -224,7 +266,7 @@ void* __tls_get_addr(const __tls_linker_tuple* tuple)
mutex_lock(&__tls_mutex);
{
auto module = __tls_get_module(tuple);
- auto blob = tls_info->blobs[tuple->module] = malloc(module->size);
+ auto blob = tls_info->blobs[tuple_module] = malloc(module->size);
memcpy(blob, module->sect_addr, module->size);
}
mutex_unlock(&__tls_mutex);
@@ -232,7 +274,7 @@ void* __tls_get_addr(const __tls_linker_tuple* tuple)
}
// Return the offset of the TLS variable from this module's blob.
- return &reinterpret_cast<uint8_t*>(tls_info->blobs[tuple->module])
+ return &reinterpret_cast<uint8_t*>(tls_info->blobs[tuple_module])
[tuple->offset+VFS_PPC64_DTPREL_OFFSET];
}
@@ -240,13 +282,12 @@ void* __tls_get_addr(const __tls_linker_tuple* tuple)
*
* Called by init() in module_init.
*/
-void __tls_register(void* s, void* e)
+void __tls_register(void* s, void* e, const size_t i_module)
{
if (s == e)
return;
- __tls_module m = { s, ((size_t)e) - ((size_t)s) };
-
+ __tls_module m(s, ((size_t)e) - ((size_t)s), i_module );
mutex_lock(&__tls_mutex);
{
__tls_pending_modules.push_back(m);
diff --git a/src/lib/tlsrt.C b/src/lib/tlsrt.C
new file mode 100644
index 000000000..100299d16
--- /dev/null
+++ b/src/lib/tlsrt.C
@@ -0,0 +1,31 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/lib/tlsrt.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015,2019 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+// There are no good ways to apply the runtime condition to a non-module
+// object, so this facilitates creating two different verisions of the
+// same object
+#define __HOSTBOOT_RUNTIME 1
+#include "tls.C"
+
diff --git a/src/makefile b/src/makefile
index 6b562d166..a9c918dd0 100644
--- a/src/makefile
+++ b/src/makefile
@@ -58,7 +58,6 @@ BASE_OBJECTS += cxxtest_data.o
BASE_OBJECTS += sprintf.o
BASE_OBJECTS += crc32.o
BASE_OBJECTS += utilmisc.o
-BASE_OBJECTS += tls.o
ifdef HOSTBOOT_PROFILE
BASE_OBJECTS += gcov.o
@@ -340,7 +339,7 @@ hbibl_OBJECTS += ${BOOTLDR_OBJECTS}
hbibl_LDFILE = bootloader.ld
hbibl_NO_RELOCATION = 1
-hbicore_OBJECTS += ${BASE_OBJECTS}
+hbicore_OBJECTS += ${BASE_OBJECTS} tls.o
hbicore_OBJECTS += ${DIRECT_BOOT_OBJECTS}
hbicore_MODULES += ${BASE_MODULES}
hbicore_EXTENDED_MODULES += ${EXTENDED_MODULES}
@@ -369,7 +368,7 @@ endif
hbicore_test_LDFILE = kernel.ld
hbirt_OBJECTS += ${RUNTIME_OBJECTS}
-hbirt_OBJECTS += ${BASE_OBJECTS}
+hbirt_OBJECTS += ${BASE_OBJECTS} tlsrt.o
hbirt_MODULES += ${RUNTIME_MODULES}
hbirt_DATA_MODULES += ${RUNTIME_DATA_MODULES}
hbirt_DATA_MODULES += $(if $(CONFIG_HBRT_PRD),$(prd_rule_prf_targets))
diff --git a/src/runtime/rt_start.S b/src/runtime/rt_start.S
index ba1a975d7..aaf4ee59e 100644
--- a/src/runtime/rt_start.S
+++ b/src/runtime/rt_start.S
@@ -5,7 +5,7 @@
#
# OpenPOWER HostBoot Project
#
-# Contributors Listed Below - COPYRIGHT 2013,2017
+# Contributors Listed Below - COPYRIGHT 2013,2019
# [+] International Business Machines Corp.
# [+] Joel Stanley
#
@@ -52,13 +52,46 @@ _init:
cmpwi cr0, r8, 0 # Perform relocations (if any).
beq 2f
+
+ # TLS workaround
+ # Load ASCII 'T','L','S' + 0x00 into bits 32:63 of r6, which will be used
+ # to compare against bits 0-31 of each relocation entry. A match signifies
+ # that this and the next relocation entry are the TLS module and offset
+ # relocations respectively. Skip both relocations before continuing the
+ # processing. These first two directives create the reference pattern to
+ # compare against. Also skip a relocation entry if its value is 0.
+ rldicl r6,r6,0,63 # Clear r6 to zero
+ addis r6, 0, 0x544C # Load ASCII "TL" into bits 32:47 of r6
+ ori r6, r6, 0x5300 # Load ASCII "S" + 0x00 into bits 48:63 of r6
+
mtctr r8
1:
ldu r8, 8(r10) # Get relocation destination
add r8, r8, r4
ld r7, 0(r8) # Get relocation address
+
+
+ # TLS workaround (continued for next 8 instructions)
+ rldicl r5,r5,0,63 # Clear r5 to zero
+ cmp cr0, 0, r5, r7 # Compare the relocation address (r7) to zero (r5)
+ beq cr0, 3f # If the relocation address is zero, do
+ # not adjust it and instead jump to the loop
+ # decrement/branch instruction
+
+ rldicl r5,r7,32,32 # Rotate bits 0-31 of the relocation address
+ # into 32-63 and clear bits 0-31, saving result
+ # to r5, to set up the next comparison
+ cmp cr0, 0, r6, r5 # Compare bits 32-63, which should both contain
+ # ASCII TLS+0x00 if this is a TLS module
+ bne cr0, 4f # If not a TLS module relocation, keep going;
+ ldu r8, 8(r10) # otherwise, skip the TLS module relocation
+ bdnz 3f # and decrement the loop counter to match. Jump
+ # to a 2nd skip/decrement pair to effectively skip
+ # the next TLS module relocation as well
+4:
add r7, r7, r4
std r7, 0(r8) # Update relocation address.
+3:
bdnz 1b # Decrement CTR and continue loop.
2:
addi r10, r4, 0x2008 # Find pointer to main TOC.
diff --git a/src/usr/module_init.C b/src/usr/module_init.C
index 3e9a25e58..91df9a952 100644
--- a/src/usr/module_init.C
+++ b/src/usr/module_init.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2015 */
+/* Contributors Listed Below - COPYRIGHT 2011,2019 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -22,20 +22,32 @@
/* permissions and limitations under the License. */
/* */
/* IBM_PROLOG_END_TAG */
+
+#include <stdint.h>
+
void call_dtors(void * i_dso_handle);
-void __tls_register(void * tls_start, void * tls_end);
+
+/**
+ * @note: See documentation in src/lib/tls.C
+ */
+void __tls_register(void * tls_start, void * tls_end,const size_t i_module);
+
void __tls_unregister(void * tls_start, void * tls_end);
// This identifies the module
void* __dso_handle = (void*) &__dso_handle;
+// TLS Module ID to be updated by custom linker during final binary creation.
+// Set to max ID so that if it's not replaced, it will lead to obvious crashes.
+size_t TLS_MODULE_ID = 0xFFFFFFFFFFFFFFFFULL;
+
extern "C"
void _init(void*)
{
// Register thread-local storage.
extern void* tls_start_address;
extern void* tls_end_address;
- __tls_register(&tls_start_address, &tls_end_address);
+ __tls_register(&tls_start_address, &tls_end_address, TLS_MODULE_ID);
// Call default constructors for any static objects.
extern void (*ctor_start_address)();
diff --git a/src/usr/testcore/rtloader/loader.H b/src/usr/testcore/rtloader/loader.H
index 1c4423484..64db72dc4 100644
--- a/src/usr/testcore/rtloader/loader.H
+++ b/src/usr/testcore/rtloader/loader.H
@@ -228,7 +228,7 @@ class RuntimeLoaderTest : public CxxTest::TestSuite
"std 2, 40(1); bctrl; ld 2, 40(1); "
"mr %0, 3" :
"=r" (result) : "r" (entry), "r" (param0), "r" (param1) :
- "lr","ctr","r0","r3","r4","r5","r6","r7","r8","r9",
+ "lr","ctr","cr0","r0","r3","r4","r5","r6","r7","r8","r9",
"r10","r11"); // TODO: Need to double check the ABI here.
return result;
OpenPOWER on IntegriCloud