[f2f63d1] | 1 | /** |
---|
| 2 | * @file |
---|
[ac7d5ef0] | 3 | * |
---|
[f2f63d1] | 4 | * @brief Workspace Handler Support |
---|
[4c20da4b] | 5 | * @ingroup RTEMSScoreWorkspace |
---|
[f2f63d1] | 6 | */ |
---|
| 7 | |
---|
| 8 | /* |
---|
[e63b79d] | 9 | * COPYRIGHT (c) 1989-2009. |
---|
[ac7d5ef0] | 10 | * On-Line Applications Research Corporation (OAR). |
---|
| 11 | * |
---|
[98e4ebf5] | 12 | * The license and distribution terms for this file may be |
---|
| 13 | * found in the file LICENSE in this distribution or at |
---|
[c499856] | 14 | * http://www.rtems.org/license/LICENSE. |
---|
[ac7d5ef0] | 15 | */ |
---|
| 16 | |
---|
[a8eed23] | 17 | #if HAVE_CONFIG_H |
---|
[e6f7f81] | 18 | #include "config.h" |
---|
[a8eed23] | 19 | #endif |
---|
| 20 | |
---|
[5e9b32b] | 21 | #include <rtems/score/wkspace.h> |
---|
[cfc4231d] | 22 | #include <rtems/score/assert.h> |
---|
[e6f7f81] | 23 | #include <rtems/score/heapimpl.h> |
---|
[5e9b32b] | 24 | #include <rtems/score/interr.h> |
---|
[cfc4231d] | 25 | #include <rtems/score/percpudata.h> |
---|
[022851a] | 26 | #include <rtems/score/threadimpl.h> |
---|
| 27 | #include <rtems/score/tls.h> |
---|
[e97806a] | 28 | #include <rtems/posix/pthread.h> |
---|
[e6f7f81] | 29 | #include <rtems/config.h> |
---|
[976162a6] | 30 | |
---|
[cfc4231d] | 31 | #include <string.h> |
---|
[ac7d5ef0] | 32 | |
---|
[e63b79d] | 33 | /* #define DEBUG_WORKSPACE */ |
---|
| 34 | #if defined(DEBUG_WORKSPACE) |
---|
| 35 | #include <rtems/bspIo.h> |
---|
| 36 | #endif |
---|
| 37 | |
---|
[cfc4231d] | 38 | RTEMS_LINKER_RWSET( |
---|
| 39 | _Per_CPU_Data, |
---|
[9e4f21b9] | 40 | #if defined(RTEMS_SMP) |
---|
| 41 | /* |
---|
| 42 | * In SMP configurations, prevent false cache line sharing of per-processor |
---|
| 43 | * data with a proper alignment. |
---|
| 44 | */ |
---|
| 45 | RTEMS_ALIGNED( CPU_CACHE_LINE_BYTES ) |
---|
| 46 | #endif |
---|
| 47 | char |
---|
[cfc4231d] | 48 | ); |
---|
| 49 | |
---|
[358bd740] | 50 | Heap_Control _Workspace_Area; |
---|
| 51 | |
---|
[cfc4231d] | 52 | static uintptr_t _Workspace_Space_for_TLS( uintptr_t page_size ) |
---|
[8faca06] | 53 | { |
---|
[cfc4231d] | 54 | uintptr_t tls_size; |
---|
| 55 | uintptr_t space; |
---|
| 56 | |
---|
| 57 | tls_size = _TLS_Get_size(); |
---|
[47a3cd8] | 58 | |
---|
[884a6c59] | 59 | /* |
---|
| 60 | * In case we have a non-zero TLS size, then we need a TLS area for each |
---|
| 61 | * thread. These areas are allocated from the workspace. Ensure that the |
---|
| 62 | * workspace is large enough to fulfill all requests known at configuration |
---|
| 63 | * time (so excluding the unlimited option). It is not possible to estimate |
---|
| 64 | * the TLS size in the configuration at compile-time. The TLS size is |
---|
| 65 | * determined at application link-time. |
---|
| 66 | */ |
---|
[022851a] | 67 | if ( tls_size > 0 ) { |
---|
[6cf45cb] | 68 | uintptr_t tls_align = _TLS_Heap_align_up( (uintptr_t) _TLS_Alignment ); |
---|
| 69 | uintptr_t tls_alloc = _TLS_Get_allocation_size( tls_size, tls_align ); |
---|
| 70 | |
---|
| 71 | /* |
---|
| 72 | * Memory allocated with an alignment constraint is allocated from the end |
---|
| 73 | * of a free block. The last allocation may need one free block of minimum |
---|
| 74 | * size. |
---|
| 75 | */ |
---|
[cfc4231d] | 76 | space = _Heap_Min_block_size( page_size ); |
---|
[022851a] | 77 | |
---|
[21275b58] | 78 | space += _Thread_Initial_thread_count |
---|
[6cf45cb] | 79 | * _Heap_Size_with_overhead( page_size, tls_alloc, tls_align ); |
---|
[cfc4231d] | 80 | } else { |
---|
| 81 | space = 0; |
---|
| 82 | } |
---|
| 83 | |
---|
| 84 | return space; |
---|
| 85 | } |
---|
| 86 | |
---|
[7c19e50] | 87 | #ifdef RTEMS_SMP |
---|
| 88 | static void *_Workspace_Allocate_from_areas( |
---|
| 89 | Heap_Area *areas, |
---|
| 90 | size_t area_count, |
---|
| 91 | uintptr_t size, |
---|
| 92 | uintptr_t alignment |
---|
| 93 | ) |
---|
[cfc4231d] | 94 | { |
---|
[7c19e50] | 95 | size_t i; |
---|
[cfc4231d] | 96 | |
---|
[7c19e50] | 97 | for ( i = 0; i < area_count; ++i ) { |
---|
| 98 | Heap_Area *area; |
---|
| 99 | uintptr_t alloc_begin; |
---|
| 100 | uintptr_t alloc_size; |
---|
[cfc4231d] | 101 | |
---|
[7c19e50] | 102 | area = &areas[ i ]; |
---|
| 103 | alloc_begin = (uintptr_t) area->begin; |
---|
| 104 | alloc_begin = ( alloc_begin + alignment - 1 ) & ~( alignment - 1 ); |
---|
| 105 | alloc_size = size; |
---|
| 106 | alloc_size += alloc_begin - (uintptr_t) area->begin; |
---|
[cfc4231d] | 107 | |
---|
[7c19e50] | 108 | if ( area->size >= alloc_size ) { |
---|
| 109 | area->begin = (void *) ( alloc_begin + size ); |
---|
| 110 | area->size -= alloc_size; |
---|
[cfc4231d] | 111 | |
---|
[7c19e50] | 112 | return (void *) alloc_begin; |
---|
| 113 | } |
---|
[022851a] | 114 | } |
---|
[cfc4231d] | 115 | |
---|
[7c19e50] | 116 | return NULL; |
---|
[cfc4231d] | 117 | } |
---|
[7c19e50] | 118 | #endif |
---|
[cfc4231d] | 119 | |
---|
[7c19e50] | 120 | static void _Workspace_Allocate_per_CPU_data( |
---|
| 121 | Heap_Area *areas, |
---|
| 122 | size_t area_count |
---|
| 123 | ) |
---|
[cfc4231d] | 124 | { |
---|
| 125 | #ifdef RTEMS_SMP |
---|
[776464a] | 126 | uintptr_t size; |
---|
[cfc4231d] | 127 | |
---|
| 128 | size = RTEMS_LINKER_SET_SIZE( _Per_CPU_Data ); |
---|
| 129 | |
---|
[776464a] | 130 | if ( size > 0 ) { |
---|
| 131 | Per_CPU_Control *cpu; |
---|
| 132 | uint32_t cpu_index; |
---|
| 133 | uint32_t cpu_max; |
---|
| 134 | |
---|
| 135 | cpu = _Per_CPU_Get_by_index( 0 ); |
---|
| 136 | cpu->data = RTEMS_LINKER_SET_BEGIN( _Per_CPU_Data ); |
---|
| 137 | |
---|
| 138 | cpu_max = rtems_configuration_get_maximum_processors(); |
---|
| 139 | |
---|
| 140 | for ( cpu_index = 1 ; cpu_index < cpu_max ; ++cpu_index ) { |
---|
| 141 | cpu = _Per_CPU_Get_by_index( cpu_index ); |
---|
[7c19e50] | 142 | cpu->data = _Workspace_Allocate_from_areas( |
---|
| 143 | areas, |
---|
| 144 | area_count, |
---|
| 145 | size, |
---|
| 146 | CPU_CACHE_LINE_BYTES |
---|
| 147 | ); |
---|
| 148 | |
---|
| 149 | if( cpu->data == NULL ) { |
---|
| 150 | _Internal_error( INTERNAL_ERROR_NO_MEMORY_FOR_PER_CPU_DATA ); |
---|
| 151 | } |
---|
| 152 | |
---|
[776464a] | 153 | memcpy( cpu->data, RTEMS_LINKER_SET_BEGIN( _Per_CPU_Data ), size); |
---|
| 154 | } |
---|
[cfc4231d] | 155 | } |
---|
[7c19e50] | 156 | #else |
---|
| 157 | (void) areas; |
---|
| 158 | (void) area_count; |
---|
[cfc4231d] | 159 | #endif |
---|
| 160 | } |
---|
| 161 | |
---|
| 162 | void _Workspace_Handler_initialization( |
---|
| 163 | Heap_Area *areas, |
---|
| 164 | size_t area_count, |
---|
| 165 | Heap_Initialization_or_extend_handler extend |
---|
| 166 | ) |
---|
| 167 | { |
---|
| 168 | Heap_Initialization_or_extend_handler init_or_extend; |
---|
| 169 | uintptr_t remaining; |
---|
| 170 | bool do_zero; |
---|
| 171 | bool unified; |
---|
| 172 | uintptr_t page_size; |
---|
| 173 | uintptr_t overhead; |
---|
| 174 | size_t i; |
---|
| 175 | |
---|
[7c19e50] | 176 | _Workspace_Allocate_per_CPU_data( areas, area_count ); |
---|
| 177 | |
---|
[cfc4231d] | 178 | page_size = CPU_HEAP_ALIGNMENT; |
---|
| 179 | |
---|
| 180 | remaining = rtems_configuration_get_work_space_size(); |
---|
| 181 | remaining += _Workspace_Space_for_TLS( page_size ); |
---|
| 182 | |
---|
| 183 | init_or_extend = _Heap_Initialize; |
---|
| 184 | do_zero = rtems_configuration_get_do_zero_of_workspace(); |
---|
| 185 | unified = rtems_configuration_get_unified_work_area(); |
---|
| 186 | overhead = _Heap_Area_overhead( page_size ); |
---|
| 187 | |
---|
| 188 | for ( i = 0; i < area_count; ++i ) { |
---|
| 189 | Heap_Area *area; |
---|
[022851a] | 190 | |
---|
[cfc4231d] | 191 | area = &areas[ i ]; |
---|
[47a3cd8] | 192 | |
---|
| 193 | if ( do_zero ) { |
---|
| 194 | memset( area->begin, 0, area->size ); |
---|
| 195 | } |
---|
| 196 | |
---|
| 197 | if ( area->size > overhead ) { |
---|
| 198 | uintptr_t space_available; |
---|
| 199 | uintptr_t size; |
---|
| 200 | |
---|
| 201 | if ( unified ) { |
---|
| 202 | size = area->size; |
---|
| 203 | } else { |
---|
| 204 | if ( remaining > 0 ) { |
---|
| 205 | size = remaining < area->size - overhead ? |
---|
| 206 | remaining + overhead : area->size; |
---|
| 207 | } else { |
---|
| 208 | size = 0; |
---|
| 209 | } |
---|
| 210 | } |
---|
| 211 | |
---|
[cfc4231d] | 212 | space_available = ( *init_or_extend )( |
---|
[47a3cd8] | 213 | &_Workspace_Area, |
---|
| 214 | area->begin, |
---|
| 215 | size, |
---|
| 216 | page_size |
---|
| 217 | ); |
---|
| 218 | |
---|
| 219 | area->begin = (char *) area->begin + size; |
---|
| 220 | area->size -= size; |
---|
[05279b84] | 221 | |
---|
[47a3cd8] | 222 | if ( space_available < remaining ) { |
---|
| 223 | remaining -= space_available; |
---|
| 224 | } else { |
---|
| 225 | remaining = 0; |
---|
| 226 | } |
---|
[05279b84] | 227 | |
---|
[47a3cd8] | 228 | init_or_extend = extend; |
---|
| 229 | } |
---|
| 230 | } |
---|
[05279b84] | 231 | |
---|
[47a3cd8] | 232 | if ( remaining > 0 ) { |
---|
[3a659b04] | 233 | _Internal_error( INTERNAL_ERROR_TOO_LITTLE_WORKSPACE ); |
---|
[47a3cd8] | 234 | } |
---|
[2a713e3] | 235 | |
---|
| 236 | _Heap_Protection_set_delayed_free_fraction( &_Workspace_Area, 1 ); |
---|
[8faca06] | 237 | } |
---|
| 238 | |
---|
[5b33dc80] | 239 | void *_Workspace_Allocate( |
---|
[7ff6115] | 240 | size_t size |
---|
[5b33dc80] | 241 | ) |
---|
| 242 | { |
---|
[a2fa532d] | 243 | void *memory; |
---|
[e63b79d] | 244 | |
---|
[a2fa532d] | 245 | memory = _Heap_Allocate( &_Workspace_Area, size ); |
---|
[e63b79d] | 246 | #if defined(DEBUG_WORKSPACE) |
---|
| 247 | printk( |
---|
| 248 | "Workspace_Allocate(%d) from %p/%p -> %p\n", |
---|
| 249 | size, |
---|
| 250 | __builtin_return_address( 0 ), |
---|
| 251 | __builtin_return_address( 1 ), |
---|
[a2fa532d] | 252 | memory |
---|
[e63b79d] | 253 | ); |
---|
| 254 | #endif |
---|
[a2fa532d] | 255 | return memory; |
---|
[5b33dc80] | 256 | } |
---|
[ac7d5ef0] | 257 | |
---|
[a850d04] | 258 | void *_Workspace_Allocate_aligned( size_t size, size_t alignment ) |
---|
| 259 | { |
---|
| 260 | return _Heap_Allocate_aligned( &_Workspace_Area, size, alignment ); |
---|
| 261 | } |
---|
| 262 | |
---|
[5b33dc80] | 263 | /* |
---|
[9d4fa67] | 264 | * _Workspace_Free |
---|
[5b33dc80] | 265 | */ |
---|
[a0323a9f] | 266 | void _Workspace_Free( |
---|
[5b33dc80] | 267 | void *block |
---|
| 268 | ) |
---|
| 269 | { |
---|
[e63b79d] | 270 | #if defined(DEBUG_WORKSPACE) |
---|
| 271 | printk( |
---|
| 272 | "Workspace_Free(%p) from %p/%p\n", |
---|
| 273 | block, |
---|
| 274 | __builtin_return_address( 0 ), |
---|
| 275 | __builtin_return_address( 1 ) |
---|
| 276 | ); |
---|
| 277 | #endif |
---|
[8249054] | 278 | _Heap_Free( &_Workspace_Area, block ); |
---|
[5b33dc80] | 279 | } |
---|