1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     os_ThreadLocalStorage.cpp
4 
5   Copyright (C)2009 Nintendo Co., Ltd.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law. They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Rev: 34323 $
14  *---------------------------------------------------------------------------*/
15 
16 #include <nn/os/os_ThreadLocalStorage.h>
17 #include <nn/os/os_Result.h>
18 #include <nn/os/os_Private.h>
19 #include <nn/assert.h>
20 #include <nn/hw/ARM/reg_access.h>
21 //---------------------------------------------------------------------------
22 
23 using namespace nn;
24 using nn::Result;
25 
26 namespace nn{ namespace os{
27 
28 #if defined(NN_PROCESSOR_ARM_V6)
29 
30     NN_STATIC_ASSERT(TLS_NUM == 16);
31 
32     typedef ThreadLocalRegion ThreadLocalBuffer;
33 
GetThreadLocalBuffer()34     inline ThreadLocalBuffer* GetThreadLocalBuffer()
35     {
36         return GetThreadLocalRegion();
37     }
38 
39 #elif defined(NN_PROCESSOR_ARM_V5)
40 
41     struct ThreadLocalBuffer
42     {
43         uptr tls[TLS_NUM];
44     };
45 
46     ThreadLocalBuffer s_ThreadLocalBuffers[nn::os::CTR::ARM946ES::NUM_THREAD_INDEX];
47 
48     inline ThreadLocalBuffer* GetThreadLocalBuffer()
49     {
50         return s_ThreadLocalBuffers + nn::os::CTR::ARM946ES::GetThreadIndex();
51     }
52 
53 #endif
54 
55 namespace {
56 
57 u16 sTLSMap = 0;   // Manage TLS allocation state with bits 0 - 15
58 
59 /* Please see man pages for details
60 
61 
62 
63 */
IsMappedIndex(s32 index)64 inline bool IsMappedIndex(s32 index)
65 {
66     return ((sTLSMap >> index) & 1) == 1;
67 }
68 
69 /* Please see man pages for details
70 
71 
72 
73 */
SearchFreeTLSIndex()74 s32 SearchFreeTLSIndex()
75 {
76 
77     for(int i = 0; i < TLS_NUM; ++i)
78     {
79         if(!IsMappedIndex(i))
80         {
81             return i;
82         }
83     }
84     return -1;
85 }
86 
87 /* Please see man pages for details
88 
89 
90 
91 */
AllocateTLSIndex()92 s32 AllocateTLSIndex()
93 {
94     s32 index = SearchFreeTLSIndex();
95     if(index >= 0 && index < TLS_NUM)
96     {
97         sTLSMap |= (1 << index);
98     }
99     return index;
100 }
101 
102 /* Please see man pages for details
103 
104 
105 
106 */
FreeTLSIndex(int index)107 s32 FreeTLSIndex(int index)
108 {
109     if(!IsMappedIndex(index))
110     {
111         return -1;
112     }
113     return sTLSMap &= ~(1 << index);
114 }
115 
116 
117 } // Namespace
118 
ThreadLocalStorage()119 ThreadLocalStorage::ThreadLocalStorage()
120 {
121     this->m_Index = AllocateTLSIndex();
122     NN_TASSERTMSG_(m_Index >= 0, "Out of Thread Local Storage Slot.");
123 }
124 
~ThreadLocalStorage()125 ThreadLocalStorage::~ThreadLocalStorage()
126 {
127     NN_TASSERT_(m_Index >= 0 && m_Index < TLS_NUM);
128     NN_TASSERT_(IsMappedIndex(m_Index));
129     FreeTLSIndex(m_Index);
130 }
131 
GetValue() const132 uptr ThreadLocalStorage::GetValue() const
133 {
134     NN_TASSERT_(m_Index >= 0 && m_Index < TLS_NUM);
135     NN_TASSERT_(IsMappedIndex(m_Index));
136     return GetThreadLocalBuffer()->tls[m_Index];
137 }
138 
SetValue(uptr value)139 void ThreadLocalStorage::SetValue(uptr value)
140 {
141     NN_TASSERT_(m_Index >= 0 && m_Index < TLS_NUM);
142     NN_TASSERT_(IsMappedIndex(m_Index));
143     GetThreadLocalBuffer()->tls[m_Index] = value;
144 }
145 
ClearAllSlots()146 void ThreadLocalStorage::ClearAllSlots()
147 {
148     ThreadLocalBuffer& tlr = *GetThreadLocalBuffer();
149 
150     for( int i = 0; i < TLS_NUM; ++i )
151     {
152         tlr.tls[i] = 0;
153     }
154 }
155 
156 }} // namespace nn::os
157 
158