Callisto4Bootloader: ARK/platform_startup.c Source File

Callisto4Bootloader

platform_startup.c
Go to the documentation of this file.
1 /*
2 * platform_startup.c
3 *
4 * Created on: 16 Jul 2020
5 * Author: Nick Pelling
6 */
7
8 #include <string.h> // for memcpy()
9 #include <stdio.h> // for printf()
10
11 #include "platform-api.h"
12 #include "platform-memory-map.h"
13
14 // ---------------------------------------------------------------------------
15 // ---------------------------------------------------------------------------
16
17 // Structure defining the addresses and sizes for a given plugin 'slot'
18 typedef struct
19 {
20 void * pvFlashLoc; uint32_t uiFlashSize;
21 void * pvConfigLoc; uint32_t pvConfigSize;
22 void * pvRamLoc; uint32_t uiRamSize;
23 } stPluginLocs_t;
24
25 // ---------------------------------------------------------------------------
26 // ---------------------------------------------------------------------------
27
28 // Array holding the addresses and sizes of all the plugin 'slots'
29 const stPluginLocs_t astPluginLocs[PLUGINS_MAX] =
30 {
31 {
32 (void *)QSPI_PLUGIN1x_BINARY, QSPI_PLUGIN_BINARY_SIZE,
33 (void *)QSPI_PLUGIN1x_CONFIG, QSPI_PLUGIN_CONFIG_SIZE,
34 (void *)RAM_PLUGIN1, RAM_PLUGIN_SIZE
35 },
36 {
37 (void *)QSPI_PLUGIN2x_BINARY, QSPI_PLUGIN_BINARY_SIZE,
38 (void *)QSPI_PLUGIN2x_CONFIG, QSPI_PLUGIN_CONFIG_SIZE,
39 (void *)RAM_PLUGIN2, RAM_PLUGIN_SIZE
40 },
41 {
42 (void *)QSPI_PLUGIN3x_BINARY, QSPI_PLUGIN_BINARY_SIZE,
43 (void *)QSPI_PLUGIN3x_CONFIG, QSPI_PLUGIN_CONFIG_SIZE,
44 (void *)RAM_PLUGIN3, RAM_PLUGIN_SIZE
45 },
46 {
47 (void *)QSPI_PLUGIN4x_BINARY, QSPI_PLUGIN_BINARY_SIZE,
48 (void *)QSPI_PLUGIN4x_CONFIG, QSPI_PLUGIN_CONFIG_SIZE,
49 (void *)RAM_PLUGIN4, RAM_PLUGIN_SIZE
50 },
51 {
52 (void *)QSPI_PLUGIN5x_BINARY, QSPI_PLUGIN_BINARY_SIZE,
53 (void *)QSPI_PLUGIN5x_CONFIG, QSPI_PLUGIN_CONFIG_SIZE,
54 (void *)RAM_PLUGIN5, RAM_PLUGIN_SIZE
55 }
56 };
57
58 // ---------------------------------------------------------------------------
59 // ---------------------------------------------------------------------------
60
61 // The currently active main platform
62 const stPlatformCalls_t * pstMainPlatform = NULL;
63
64 // Bridge across from the PlatformAPI macros to the currently active main platform
65 #define DO_CALL(FNPTR) (pstMainPlatform->FNPTR)
66
67 // Use the platform assert() function
68 #define assert(CONDITION) PLATFORM_ASSERT(CONDITION)
69
70 // Set to NULL if a given plugin is not active, else holds a pointer to its main header
71 static stPluginHeader_t * apstPluginHeader[PLUGINS_MAX];
72
73 // Points to mock API to use if a test plugin has taken control
74 static const stPlatformCallBlock_t * apstMockHeader[PLUGINS_MAX];
75
76 // Points to test plugin's copy of target plugin's plugin call block
77 static stPluginCallBlock_t * * appstTestPluginTargetPluginCallBlock[PLUGINS_MAX];
78
79 // ---------------------------------------------------------------------------
80 // ---------------------------------------------------------------------------
81
82 // Forward references
83 static ePLUGIN_Status_t sLaunchPlugin( uint32_t uiPluginIndex, uint32_t uiDeviceIndex );
84
85 // ---------------------------------------------------------------------------
86 // ---------------------------------------------------------------------------
87
96 static uint32_t checksum_calculate(const void *pvBase, uint32_t uiLength)
97 {
98 const uint32_t * pauiPtr = (const uint32_t *)pvBase;
99 uint32_t uiChecksum;
100 uint32_t i;
101
102 uiChecksum = 0U;
103 for (i = 0U; i < uiLength; i += sizeof(uint32_t))
104 {
105 uiChecksum += *pauiPtr++;
106 }
107
108 return uiChecksum;
109 }
110
120 static bool CheckThatPluginIsValid(uint32_t uiPluginSlotIndex, stPluginHeader_t ** ppstPluginHeader)
121 {
122 stPluginHeader_t * pstPluginHeader;
123 stPluginHeader_t * pstReturnPtr;
124 bool bResult;
125
126 assert(uiPluginSlotIndex < PLUGINS_MAX);
127
128 // Set default return values
129 pstReturnPtr = NULL;
130 bResult = false;
131
132 // Grab the address of the plugin image (on the QSPI)
133 pstPluginHeader = (stPluginHeader_t *) astPluginLocs[uiPluginSlotIndex].pvFlashLoc;
134
135 /*
136 * Ensure that the plugin header has a good magic number, isn't unexpectedly large
137 * and passes the checksum test.
138 */
139 if (pstPluginHeader->uiMagicNumber == 0xFFFFFFFFU)
140 {
141 printf("Plugin slot #%d: the flash memory seems to be erased but not programmed\r\n", (int)(uiPluginSlotIndex + 1U));
142 }
143 else if (pstPluginHeader->uiMagicNumber != PLUGIN_MAGIC_NUMBER)
144 {
145 printf("Plugin slot #%d: the plugin image has an invalid header\r\n", (int)(uiPluginSlotIndex + 1U));
146 }
147 else if (pstPluginHeader->pvFlashBase != (void *) pstPluginHeader)
148 {
149 printf("Plugin slot #%d: the plugin image was compiled for the wrong flash base address\r\n", (int)(uiPluginSlotIndex + 1U));
150 printf(" * Expected = 0x%p, Actual = 0x%p\r\n", pstPluginHeader, pstPluginHeader->pvFlashBase);
151 }
152 else if (pstPluginHeader->pvRamBase != astPluginLocs[uiPluginSlotIndex].pvRamLoc)
153 {
154 printf("Plugin slot #%d: the plugin image was compiled for the wrong RAM base address\r\n", (int)(uiPluginSlotIndex + 1U));
155 printf(" * Expected = 0x%p, Actual = 0x%p\r\n", astPluginLocs[uiPluginSlotIndex].pvRamLoc, pstPluginHeader->pvRamBase);
156 }
157 else if (pstPluginHeader->uiBinaryLength > QSPI_PLUGIN_BINARY_SIZE)
158 {
159 printf("Plugin slot #%d: the plugin flash image seems to be too large\r\n", (int)(uiPluginSlotIndex + 1U));
160 printf(" * Max expected = 0x%x, Actual = 0x%x\r\n", (int) pstPluginHeader->uiBinaryLength, (int) QSPI_PLUGIN_BINARY_SIZE);
161 }
162 else if (checksum_calculate((void *)pstPluginHeader, pstPluginHeader->uiBinaryLength) != 0U)
163 {
164 printf("Plugin slot #%d: has an incorrect checksum\r\n", (int)(uiPluginSlotIndex + 1U));
165 }
166 else
167 {
168 // FIXME: Ensure loaded plugin image is signed!?
169
170 // Everything checked out OK, so return pointer to the valid header
171 printf("Plugin slot #%d: plugin image \"%s\" is OK\r\n", (int)(uiPluginSlotIndex + 1U), pstPluginHeader->pachPluginName);
172
173 pstReturnPtr = pstPluginHeader;
174 bResult = true;
175 }
176
177 *ppstPluginHeader = pstReturnPtr;
178 return bResult;
179 }
180
181 // ---------------------------------------------------------------------------
182 // ---------------------------------------------------------------------------
183
194 static bool sTestCallback(uint32_t uiTargetPluginIndex,
195 const stPlatformCallBlock_t * pstMockAPI,
196 stPluginCallBlock_t **ppstTargetPluginCallBlock )
197 {
198 bool bRetVal = false;
199
200 if (uiTargetPluginIndex < PLUGINS_MAX)
201 {
202 // FIXME: if the platform doesn't want test plugins to run, it should return NULL here
203 // FIXME: how should a platform tell whether or not to run a test plugin?
204 // FIXME: should there be a test flag in the EEPROM that determines this?
205 // FIXME: if so, how can developers easily flip in and out of test mode?
206 // FIXME: also, how can build machines easily flip in and out of test mode?
207 // FIXME: or should we have something that blanks the first 64K of plugin slot #5?
208
209 if (apstPluginHeader[uiTargetPluginIndex] == NULL)
210 {
211 printf("Error: test plugin is expecting to find a plugin in slot #%d\r\n",
212 (int)(uiTargetPluginIndex + 1U));
213 }
214 else
215 {
216 // Keep a copy of the mock API the test API wants this
217 apstMockHeader[uiTargetPluginIndex] = pstMockAPI;
218
219 // Keep a copy of where the test plugin would like its target plugin call block written to
220 // Note: this only gets written to if the platform allows the test plugin to take over
221 // the target plugin.
222 appstTestPluginTargetPluginCallBlock[uiTargetPluginIndex] = ppstTargetPluginCallBlock;
223
224 bRetVal = true;
225 }
226 }
227
228 return bRetVal;
229 }
230
239 ePLATFORM_HasMask_t PLATFORM_STARTUP_PluginsRelocate(
240 uint16_t u16DeviceNumber)
241 {
242 uint32_t uiPluginIndex;
243 stPluginHeader_t * pstPluginHeader;
244 ePLATFORM_HasMask_t eHasMask;
245 ePLATFORM_HasMask_t eHasMask_Merged;
246
247 for (uiPluginIndex = 0U; uiPluginIndex < PLUGINS_MAX; uiPluginIndex++)
248 {
249 apstMockHeader[uiPluginIndex] = NULL;
250 }
251
252 // For all plugins: if plugin is valid, relocate its data & register any test plugin mocks
253 eHasMask_Merged = ePLATFORM_HasMask_NONE;
254 for (uiPluginIndex = 0U; uiPluginIndex < PLUGINS_MAX; uiPluginIndex++)
255 {
256 if ( CheckThatPluginIsValid(uiPluginIndex, &pstPluginHeader) == true )
257 {
258 // Call plugin's startup vector to copy its data across into RAM (etc)
259 // If this is a test plugin, supply it with a callback to register any mocks
260 eHasMask = (*pstPluginHeader->pfnDoStartup)(u16DeviceNumber, sTestCallback);
261 if (eHasMask != ePLATFORM_HasMask_NONE)
262 {
263 apstPluginHeader[uiPluginIndex] = pstPluginHeader;
264 eHasMask_Merged |= eHasMask;
265 }
266 }
267 }
268
269 return eHasMask_Merged;
270 }
271
280 bool PLATFORM_STARTUP_PluginsLateLink(
281 const stPlatformCalls_t * pstPlatformCalls,
282 uint16_t u16DeviceNumber)
283 {
284 uint32_t uiPluginIndex;
285 stPluginHeader_t * pstPluginHeader;
286
287 pstMainPlatform = pstPlatformCalls;
288
289 // For all valid plugins: late-link it either to the platform or to a test plugin mock
290 for (uiPluginIndex = 0U; uiPluginIndex < PLUGINS_MAX; uiPluginIndex++)
291 {
292 pstPluginHeader = apstPluginHeader[uiPluginIndex];
293 if (pstPluginHeader != NULL)
294 {
295 // Copy platform's vector table into the plugin's vector table
296 memcpy( pstPluginHeader->stPlatformCallBlock.pstPlatformCalls,
297 pstPlatformCalls,
298 pstPluginHeader->stPlatformCallBlock.uiPlatformCallsSize_Bytes );
299
300 // Override target plugin's platform vectors with non-NULL mock versions
301 if (apstMockHeader[uiPluginIndex] != NULL)
302 {
303 void * * papvMock = (void * *) apstMockHeader[uiPluginIndex]->pstPlatformCalls;
304 void * * papvDest = (void * *) pstPluginHeader->stPlatformCallBlock.pstPlatformCalls;
305 uint32_t uiSizeMock = apstMockHeader[uiPluginIndex]->uiPlatformCallsSize_Bytes;
306 uint32_t uiSizeDest = pstPluginHeader->stPlatformCallBlock.uiPlatformCallsSize_Bytes;
307 uint32_t uiRangeSize = (uiSizeMock < uiSizeDest) ? uiSizeMock : uiSizeDest;
308 uint32_t uiRangeSteps = uiRangeSize / sizeof(void*);
309 for (int i = 0; i < uiRangeSteps; i++ )
310 {
311 if (papvMock[i] != NULL)
312 {
313 papvDest[i] = papvMock[i];
314 }
315 }
316
317 // Pass a pointer to the target plugin's plugin call block back to the test plugin
318 if (appstTestPluginTargetPluginCallBlock[uiPluginIndex] != NULL)
319 {
320 *(appstTestPluginTargetPluginCallBlock[uiPluginIndex]) = &pstPluginHeader->stPluginCallBlock;
321 }
322 }
323 }
324 }
325 return true;
326 }
327
335 uint32_t PLATFORM_STARTUP_PluginsLaunch(uint16_t u16DeviceNumber)
336 {
337 uint32_t uiNumFailedPlugins;
338 uint32_t uiPluginIndex;
339 stPluginHeader_t * pstPluginHeader;
340 ePLUGIN_Status_t ePluginStatus;
341
342 uiNumFailedPlugins = 0U;
343 for ( uiPluginIndex = 0U; uiPluginIndex < PLUGINS_MAX; uiPluginIndex++)
344 {
345 pstPluginHeader = apstPluginHeader[uiPluginIndex];
346 if (pstPluginHeader != NULL)
347 {
348 // Call the plugin's proper launch code
349 ePluginStatus = sLaunchPlugin( uiPluginIndex, u16DeviceNumber );
350 if (ePluginStatus != ePLUGIN_Status_OK)
351 {
352 printf("Plugin #%d (%s): failed to launch, error code = %d\r\n",
353 (int)(uiPluginIndex + 1U),
354 pstPluginHeader->pachPluginName,
355 (int) ePluginStatus);
356 uiNumFailedPlugins++;
357 }
358 else
359 {
360 printf("Plugin #%d (%s): launched OK!\r\n",
361 (int)(uiPluginIndex + 1U),
362 pstPluginHeader->pachPluginName);
363 }
364 }
365 }
366
367 return uiNumFailedPlugins; // Return the number of plugins that had problems launching
368 }
369
370
371 // ---------------------------------------------------------------------------
372
373 #define PLUGINCALL_ISVALID(PLUGININDEX,FNPTR) \
374 ( FIELD_OFFSET(stPluginCalls_t,FNPTR) < \
375 apstPluginHeader[PLUGININDEX]->stPluginCallBlock.uiPluginCallsSize_Bytes )
376
377 #define DO_CALLPLUGIN(PLUGININDEX,FNPTR) \
378 (*apstPluginHeader[PLUGININDEX]->stPluginCallBlock.pstPluginCalls->FNPTR)
379
388 static ePLUGIN_Status_t sLaunchPlugin( uint32_t uiPluginSlotIndex, uint32_t uiDeviceIndex )
389 {
390 if (PLUGINCALL_ISVALID(uiPluginSlotIndex, pfn_Startup))
391 {
392 return DO_CALLPLUGIN(uiPluginSlotIndex, pfn_Startup)( uiPluginSlotIndex, uiDeviceIndex );
393 }
394 printf("Plugin #%d (%s): no valid launch vector\r\n",
395 (int)( uiPluginSlotIndex + 1U ),
396 apstPluginHeader[uiPluginSlotIndex]->pachPluginName);
397 return ePLUGIN_Status_NoLaunchVector;
398 }
399
400 // ---------------------------------------------------------------------------
401
NULL
#define NULL
Definition: bootloader_common.h:26
astPluginLocs
const stPluginLocs_t astPluginLocs[PLUGINS_MAX]
Definition: platform_startup.c:29
CheckThatPluginIsValid
static bool CheckThatPluginIsValid(uint32_t uiPluginSlotIndex, stPluginHeader_t **ppstPluginHeader)
Check that the plugin loaded in a given plugin slot is valid.
Definition: platform_startup.c:120
i
volatile int i
Definition: excep_test.c:17
stPluginLocs_t::pvRamLoc
void * pvRamLoc
Definition: platform_startup.c:22
apstMockHeader
static const stPlatformCallBlock_t * apstMockHeader[PLUGINS_MAX]
Definition: platform_startup.c:74
sLaunchPlugin
static ePLUGIN_Status_t sLaunchPlugin(uint32_t uiPluginIndex, uint32_t uiDeviceIndex)
Launch a given plugin.
Definition: platform_startup.c:388
stPluginLocs_t::pvConfigSize
uint32_t pvConfigSize
Definition: platform_startup.c:21
assert
#define assert(CONDITION)
Definition: platform_startup.c:68
pstMainPlatform
const stPlatformCalls_t * pstMainPlatform
Definition: platform_startup.c:62
PLATFORM_STARTUP_PluginsRelocate
ePLATFORM_HasMask_t PLATFORM_STARTUP_PluginsRelocate(uint16_t u16DeviceNumber)
Relocate the plugins (but don't actually start executing them)
Definition: platform_startup.c:239
DO_CALLPLUGIN
#define DO_CALLPLUGIN(PLUGININDEX, FNPTR)
Definition: platform_startup.c:377
stPluginLocs_t::uiRamSize
uint32_t uiRamSize
Definition: platform_startup.c:22
sTestCallback
static bool sTestCallback(uint32_t uiTargetPluginIndex, const stPlatformCallBlock_t *pstMockAPI, stPluginCallBlock_t **ppstTargetPluginCallBlock)
Definition: platform_startup.c:194
stPluginLocs_t
Definition: platform_startup.c:18
apstPluginHeader
static stPluginHeader_t * apstPluginHeader[PLUGINS_MAX]
Definition: platform_startup.c:71
checksum_calculate
static uint32_t checksum_calculate(const void *pvBase, uint32_t uiLength)
Calculate a 32-bit additive checksum.
Definition: platform_startup.c:96
PLATFORM_STARTUP_PluginsLaunch
uint32_t PLATFORM_STARTUP_PluginsLaunch(uint16_t u16DeviceNumber)
Launch all valid plugins.
Definition: platform_startup.c:335
PLATFORM_STARTUP_PluginsLateLink
bool PLATFORM_STARTUP_PluginsLateLink(const stPlatformCalls_t *pstPlatformCalls, uint16_t u16DeviceNumber)
Late-link the plugins.
Definition: platform_startup.c:280
PLUGINCALL_ISVALID
#define PLUGINCALL_ISVALID(PLUGININDEX, FNPTR)
Definition: platform_startup.c:373
appstTestPluginTargetPluginCallBlock
static stPluginCallBlock_t ** appstTestPluginTargetPluginCallBlock[PLUGINS_MAX]
Definition: platform_startup.c:77
stPluginLocs_t::uiFlashSize
uint32_t uiFlashSize
Definition: platform_startup.c:20