source: rtems/cpukit/score/src/smp.c @ 97d0b9b

4.115
Last change on this file since 97d0b9b was d134adeb, checked in by Sebastian Huber <sebastian.huber@…>, on 05/23/14 at 13:32:32

score: Fix race condition in SMP startup

Do not use the Per_CPU_Control::started in
_SMP_Start_multitasking_on_secondary_processor() since this field may be
not up to date when a secondary processor reads it. Use the read-only
scheduler assignment instead.

Add a new fatal error SMP_FATAL_MULTITASKING_START_ON_INVALID_PROCESSOR.
This prevents out-of-bounds access.

It is currently not possible to test these fatal errors. One option
would be to fake values of the _CPU_SMP_Get_current_processor(), but
unfortunately this function is inline on some architectures.

  • Property mode set to 100644
File size: 4.9 KB
Line 
1/**
2 *  @file
3 *
4 *  @brief SMP Support
5 *  @ingroup Score
6 */
7
8/*
9 *  COPYRIGHT (c) 1989-2011.
10 *  On-Line Applications Research Corporation (OAR).
11 *
12 *  The license and distribution terms for this file may be
13 *  found in the file LICENSE in this distribution or at
14 *  http://www.rtems.org/license/LICENSE.
15 */
16
17#if HAVE_CONFIG_H
18#include "config.h"
19#endif
20
21#include <rtems/score/smpimpl.h>
22#include <rtems/score/assert.h>
23#include <rtems/score/schedulerimpl.h>
24#include <rtems/score/threaddispatch.h>
25#include <rtems/score/threadimpl.h>
26#include <rtems/config.h>
27
28static void _SMP_Start_processors( uint32_t cpu_count )
29{
30  uint32_t cpu_index_self = _SMP_Get_current_processor();
31  uint32_t cpu_index;
32
33
34  for ( cpu_index = 0 ; cpu_index < cpu_count; ++cpu_index ) {
35    const Scheduler_Assignment *assignment =
36      _Scheduler_Get_assignment( cpu_index );
37    Per_CPU_Control *cpu = _Per_CPU_Get_by_index( cpu_index );
38    bool started;
39
40    if ( cpu_index != cpu_index_self ) {
41      if ( _Scheduler_Should_start_processor( assignment ) ) {
42        started = _CPU_SMP_Start_processor( cpu_index );
43
44        if ( !started && _Scheduler_Is_mandatory_processor( assignment ) ) {
45          _SMP_Fatal( SMP_FATAL_START_OF_MANDATORY_PROCESSOR_FAILED );
46        }
47      } else {
48        started = false;
49      }
50    } else {
51      started = true;
52
53      if ( !_Scheduler_Should_start_processor( assignment ) ) {
54        _SMP_Fatal( SMP_FATAL_BOOT_PROCESSOR_NOT_ASSIGNED_TO_SCHEDULER );
55      }
56    }
57
58    cpu->started = started;
59
60    if ( started ) {
61      Scheduler_Context *context =
62        _Scheduler_Get_context( assignment->scheduler );
63
64      ++context->processor_count;
65      cpu->scheduler_context = context;
66    }
67  }
68}
69
70void _SMP_Handler_initialize( void )
71{
72  uint32_t cpu_max = rtems_configuration_get_maximum_processors();
73  uint32_t cpu_count;
74  uint32_t cpu_index;
75
76  for ( cpu_index = 0 ; cpu_index < cpu_max; ++cpu_index ) {
77    Per_CPU_Control *cpu = _Per_CPU_Get_by_index( cpu_index );
78
79    _SMP_ticket_lock_Initialize( &cpu->Lock, "per-CPU" );
80  }
81
82  /*
83   * Discover and initialize the secondary cores in an SMP system.
84   */
85
86  cpu_count = _CPU_SMP_Initialize();
87  cpu_count = cpu_count < cpu_max ? cpu_count : cpu_max;
88  _SMP_Processor_count = cpu_count;
89
90  for ( cpu_index = cpu_count ; cpu_index < cpu_max; ++cpu_index ) {
91    const Scheduler_Assignment *assignment =
92      _Scheduler_Get_assignment( cpu_index );
93
94    if ( _Scheduler_Is_mandatory_processor( assignment ) ) {
95      _SMP_Fatal( SMP_FATAL_MANDATORY_PROCESSOR_NOT_PRESENT );
96    }
97  }
98
99  _SMP_Start_processors( cpu_count );
100
101  _CPU_SMP_Finalize_initialization( cpu_count );
102}
103
104void _SMP_Request_start_multitasking( void )
105{
106  Per_CPU_Control *self_cpu = _Per_CPU_Get();
107  uint32_t cpu_count = _SMP_Get_processor_count();
108  uint32_t cpu_index;
109
110  _Per_CPU_State_change( self_cpu, PER_CPU_STATE_READY_TO_START_MULTITASKING );
111
112  for ( cpu_index = 0 ; cpu_index < cpu_count ; ++cpu_index ) {
113    Per_CPU_Control *cpu = _Per_CPU_Get_by_index( cpu_index );
114
115    if ( _Per_CPU_Is_processor_started( cpu ) ) {
116      _Per_CPU_State_change( cpu, PER_CPU_STATE_REQUEST_START_MULTITASKING );
117    }
118  }
119}
120
121void _SMP_Start_multitasking_on_secondary_processor( void )
122{
123  Per_CPU_Control *self_cpu = _Per_CPU_Get();
124  uint32_t cpu_index_self = _Per_CPU_Get_index( self_cpu );
125  const Scheduler_Assignment *assignment =
126    _Scheduler_Get_assignment( cpu_index_self );
127
128  if ( cpu_index_self >= rtems_configuration_get_maximum_processors() ) {
129    _SMP_Fatal( SMP_FATAL_MULTITASKING_START_ON_INVALID_PROCESSOR );
130  }
131
132  if ( !_Scheduler_Should_start_processor( assignment ) ) {
133    _SMP_Fatal( SMP_FATAL_MULTITASKING_START_ON_UNASSIGNED_PROCESSOR );
134  }
135
136  _Per_CPU_State_change( self_cpu, PER_CPU_STATE_READY_TO_START_MULTITASKING );
137
138  _Thread_Start_multitasking();
139}
140
141void _SMP_Request_shutdown( void )
142{
143  Per_CPU_Control *self_cpu = _Per_CPU_Get();
144
145  _Per_CPU_State_change( self_cpu, PER_CPU_STATE_SHUTDOWN );
146
147  /*
148   * We have to drop the Giant lock here in order to give other processors the
149   * opportunity to receive the inter-processor interrupts issued previously.
150   * In case the executing thread still holds SMP locks, then other processors
151   * already waiting for this SMP lock will spin forever.
152   */
153  _Giant_Drop( self_cpu );
154}
155
156void _SMP_Send_message( uint32_t cpu_index, unsigned long message )
157{
158  Per_CPU_Control *cpu = _Per_CPU_Get_by_index( cpu_index );
159
160  _Atomic_Fetch_or_ulong( &cpu->message, message, ATOMIC_ORDER_RELAXED );
161
162  _CPU_SMP_Send_interrupt( cpu_index );
163}
164
165void _SMP_Broadcast_message( uint32_t message )
166{
167  uint32_t cpu_count = _SMP_Get_processor_count();
168  uint32_t cpu_index_self = _SMP_Get_current_processor();
169  uint32_t cpu_index;
170
171  _Assert( _Debug_Is_thread_dispatching_allowed() );
172
173  for ( cpu_index = 0 ; cpu_index < cpu_count ; ++cpu_index ) {
174    if ( cpu_index != cpu_index_self ) {
175      _SMP_Send_message( cpu_index, message );
176    }
177  }
178}
179
180SMP_Test_message_handler _SMP_Test_message_handler;
Note: See TracBrowser for help on using the repository browser.