1 /*
2  * Copyright (c) 2019-2022 Cypress Semiconductor Corporation (an Infineon
3  * company) or an affiliate of Cypress Semiconductor Corporation. All rights
4  * reserved.
5  * Copyright (c) 2021, Arm Limited. All rights reserved.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 #include <string.h>
20 
21 #include "driver_smpu.h"
22 
23 #include "internal_status_code.h"
24 #include "flash_layout.h"
25 #include "nv_counters.h"
26 #include "pc_config.h"
27 #include "region_defs.h"
28 #include "RTE_Device.h"
29 #include "smpu_config.h"
30 #include "tfm_spm_log.h"
31 #include "tfm_hal_its.h"
32 #ifdef TFM_PARTITION_PROTECTED_STORAGE
33 #include "tfm_hal_ps.h"
34 #endif
35 #include "tfm_multi_core.h"
36 
37 #include "cy_prot.h"
38 
39 /* Affect all 8 subregions */
40 #define ALL_ENABLED 0
41 #define SMPU_NAME_MAX_SIZE 18
42 
43 struct smpu_resources {
44     PROT_SMPU_SMPU_STRUCT_Type *smpu;
45     cy_stc_smpu_cfg_t slave_config;
46     cy_stc_smpu_cfg_t master_config;
47 };
48 
smpu_name(const SMPU_Resources * smpu_dev)49 static const char * smpu_name(const SMPU_Resources *smpu_dev)
50 {
51     switch ((int)smpu_dev->smpu) {
52     case (int)PROT_SMPU_SMPU_STRUCT0:
53         return "SMPU 0";
54     case (int)PROT_SMPU_SMPU_STRUCT1:
55         return "SMPU 1";
56     case (int)PROT_SMPU_SMPU_STRUCT2:
57         return "SMPU 2";
58     case (int)PROT_SMPU_SMPU_STRUCT3:
59         return "SMPU 3";
60     case (int)PROT_SMPU_SMPU_STRUCT4:
61         return "SMPU 4";
62     case (int)PROT_SMPU_SMPU_STRUCT5:
63         return "SMPU 5";
64     case (int)PROT_SMPU_SMPU_STRUCT6:
65         return "SMPU 6";
66     case (int)PROT_SMPU_SMPU_STRUCT7:
67         return "SMPU 7";
68     case (int)PROT_SMPU_SMPU_STRUCT8:
69         return "SMPU 8";
70     case (int)PROT_SMPU_SMPU_STRUCT9:
71         return "SMPU 9";
72     case (int)PROT_SMPU_SMPU_STRUCT10:
73         return "SMPU 10";
74     case (int)PROT_SMPU_SMPU_STRUCT11:
75         return "SMPU 11";
76     case (int)PROT_SMPU_SMPU_STRUCT12:
77         return "SMPU 12";
78     case (int)PROT_SMPU_SMPU_STRUCT13:
79         return "SMPU 13";
80     case (int)PROT_SMPU_SMPU_STRUCT14:
81         return "SMPU 14";
82     case (int)PROT_SMPU_SMPU_STRUCT15:
83         return "SMPU 15";
84     default:
85         return "Unrecognised SMPU";
86     }
87 }
88 
is_runtime(const SMPU_Resources * smpu_dev)89 static bool is_runtime(const SMPU_Resources *smpu_dev)
90 {
91     if ((smpu_dev->slave_config.address == SMPU_DYNAMIC_BASE) &&
92         (smpu_dev->slave_config.regionSize == SMPU_DYNAMIC_REGIONSIZE) &&
93         (smpu_dev->slave_config.subregions == SMPU_DYNAMIC_SUBREGIONS))
94         return true;
95     return false;
96 }
97 
is_whole_power_of_two(size_t size)98 static bool is_whole_power_of_two(size_t size)
99 {
100     return ((size - 1) & size) == 0;
101 }
102 
is_aligned(uint32_t base,size_t size)103 static bool is_aligned(uint32_t base, size_t size)
104 {
105     return (base % size) == 0;
106 }
107 
108 /* size must be a whole power of two, >= 4 */
bytes_to_regionsize(size_t size)109 static cy_en_prot_size_t bytes_to_regionsize(size_t size)
110 {
111     int ret = 1;
112 
113     while (REGIONSIZE_TO_BYTES(ret) < size)
114         ret += 1;
115     return (cy_en_prot_size_t)ret;
116 }
117 
round_up_to_power_of_two(uint32_t x)118 static uint32_t round_up_to_power_of_two(uint32_t x)
119 {
120     x--;
121     x |= x >> 1;
122     x |= x >> 2;
123     x |= x >> 4;
124     x |= x >> 8;
125     x |= x >> 16;
126     x++;
127     return x;
128 }
129 
round_down_to_power_of_two(uint32_t x)130 static uint32_t round_down_to_power_of_two(uint32_t x)
131 {
132     x |= x >> 1;
133     x |= x >> 2;
134     x |= x >> 4;
135     x |= x >> 8;
136     x |= x >> 16;
137     x = x - (x >> 1);
138     return x;
139 }
140 
round_down_to_multiple(uint32_t base,uint32_t regionSize)141 static uint32_t round_down_to_multiple(uint32_t base, uint32_t regionSize)
142 {
143     return (regionSize * (base / regionSize));
144 }
145 
146 /* Maps 0..7 to CY_PROT_SUBREGION_DIS0..CY_PROT_SUBREGION_DIS7 */
subregion_num_to_mask(int num)147 static uint32_t subregion_num_to_mask(int num) {
148     return CY_PROT_SUBREGION_DIS0 << num;
149 }
150 
151 #define MIN_REGIONSIZE 256
152 /* The largest regionSize is actually 4GB, but that doesn't fit in a uint32_t */
153 #define MAX_REGIONSIZE (1 * 1024 * 1024 * 1024)
154 #define NUM_SUBREGIONS 8
155 
calc_smpu_params(uint32_t base,size_t size,cy_stc_smpu_cfg_t * slave_config)156 static cy_en_prot_status_t calc_smpu_params(uint32_t base,
157                                             size_t size,
158                                             cy_stc_smpu_cfg_t *slave_config)
159 {
160     /* Simplest case - base is a multiple of the size,
161      * and size is a whole power of two, and >= 256
162      */
163     if (is_whole_power_of_two(size) &&
164         is_aligned(base, size) &&
165         (size >= MIN_REGIONSIZE)) {
166         slave_config->address = (void *)base;
167         slave_config->regionSize = bytes_to_regionsize(size);
168         slave_config->subregions = ALL_ENABLED;
169 
170         return CY_PROT_SUCCESS;
171     } else {
172         /* Try to find a regionSize that could work */
173         uint32_t low_rs = round_up_to_power_of_two(size);
174         uint32_t high_rs = round_down_to_power_of_two(size * NUM_SUBREGIONS);
175         uint32_t regionSize;
176 
177         if (low_rs < MIN_REGIONSIZE)
178             low_rs = MIN_REGIONSIZE;
179 
180         if (size > MAX_REGIONSIZE / NUM_SUBREGIONS)
181             high_rs = MAX_REGIONSIZE;
182 
183         for (regionSize = low_rs; regionSize <= high_rs; regionSize <<= 1)
184         {
185             const uint32_t sub_size = regionSize / NUM_SUBREGIONS;
186             uint32_t address;
187             int n;
188             uint32_t mask = 0;
189 
190             /* Would this work with the base address ? */
191             if (base % sub_size) {
192                 /* TODO If we get here, are we guaranteed to fail ? */
193                 continue;
194             }
195 
196             /* is the size 1..8 * subregion size ? */
197             for (n = 1; n <= NUM_SUBREGIONS; n++) {
198                 if (size == n * sub_size) {
199                     break;
200                 }
201             }
202             if (n > NUM_SUBREGIONS) {
203                 continue;
204             }
205 
206             /* What would the base address be? */
207             address = round_down_to_multiple(base, regionSize);
208 
209             /* Would the upper limit of the SMPU region cover what we need? */
210             if (address + regionSize < base + size) {
211                 continue;
212             }
213 
214             /* Calculate the SMPU config */
215             slave_config->address = (void *)address;
216             slave_config->regionSize = bytes_to_regionsize(regionSize);
217 
218             /* Figure out which subregions to disable */
219             for (int num = 0; num < NUM_SUBREGIONS; num += 1) {
220                 if (address + num * sub_size < base) {
221                     /* Disable this subregion */
222                     mask |= subregion_num_to_mask(num);
223                 } else if (address + num * sub_size >= base + size) {
224                     /* Disable this subregion */
225                     mask |= subregion_num_to_mask(num);
226                 }
227             }
228             slave_config->subregions = mask;
229 
230             return CY_PROT_SUCCESS;
231         }
232 
233         /* If we get here, we failed */
234         return CY_PROT_FAILURE;
235     }
236 }
237 
get_region(const PROT_SMPU_SMPU_STRUCT_Type * smpu,uint32_t * base,size_t * size)238 static cy_en_prot_status_t get_region(const PROT_SMPU_SMPU_STRUCT_Type *smpu,
239                                       uint32_t *base, size_t *size)
240 {
241     cy_en_prot_status_t ret = CY_PROT_SUCCESS;
242 
243     /* Figure out the base, size, and subregion mask to use */
244     if (smpu == ITS_SMPU_STRUCT) {
245         struct tfm_hal_its_fs_info_t its_fs_info;
246         /* Retrieve the ITS region definition */
247         tfm_hal_its_fs_info(&its_fs_info);
248         *base = its_fs_info.flash_area_addr;
249         *size = its_fs_info.flash_area_size;
250     } else if (smpu == NVC_SMPU_STRUCT) {
251         /* Retrieve the OTP / NV area info */
252         *base = FLASH_OTP_NV_COUNTERS_AREA_OFFSET;
253         *size = FLASH_OTP_NV_COUNTERS_AREA_SIZE;
254 #ifdef TFM_PARTITION_PROTECTED_STORAGE
255     } else if (smpu == PS_SMPU_STRUCT) {
256         struct tfm_hal_ps_fs_info_t ps_fs_info;
257         /* Retrieve the PS region definition */
258         tfm_hal_ps_fs_info(&ps_fs_info);
259         *base = ps_fs_info.flash_area_addr;
260         *size = ps_fs_info.flash_area_size;
261 #endif
262     } else {
263         /* We don't know where to get the region definition */
264         ret = CY_PROT_FAILURE;
265     }
266     /* flash driver uses offsets rather than absolute addresses,
267      * so we need to add the flash base address here.
268      */
269     *base += FLASH_BASE_ADDRESS;
270 
271     return ret;
272 }
273 
populate_region(const PROT_SMPU_SMPU_STRUCT_Type * smpu,cy_stc_smpu_cfg_t * slave_config)274 static cy_en_prot_status_t populate_region(const PROT_SMPU_SMPU_STRUCT_Type *smpu,
275                                            cy_stc_smpu_cfg_t *slave_config)
276 {
277     cy_en_prot_status_t ret;
278     uint32_t base;
279     size_t size;
280 
281     ret = get_region(smpu, &base, &size);
282 
283     if (ret == CY_PROT_SUCCESS) {
284         /* And figure out how to configure the SMPU region */
285         ret = calc_smpu_params(base, size, slave_config);
286     }
287 
288     return ret;
289 }
290 
print_smpu_config(const cy_stc_smpu_cfg_t * slave_config)291 static void print_smpu_config(const cy_stc_smpu_cfg_t *slave_config)
292 {
293     SPMLOG_INFMSGVAL(" Address = ", (uintptr_t)slave_config->address);
294     SPMLOG_INFMSGVAL(" Size (bytes) = ",
295                      REGIONSIZE_TO_BYTES(slave_config->regionSize));
296     if (slave_config->subregions == ALL_ENABLED) {
297         SPMLOG_INFMSG(" All subregions enabled\r\n");
298     } else {
299         SPMLOG_INFMSGVAL("\tsubregion size (bytes) = ",
300                          REGIONSIZE_TO_BYTES(slave_config->regionSize)/8);
301         for (int i=0; i<8; i++) {
302             if (slave_config->subregions & (1<<i)) {
303                 SPMLOG_INFMSGVAL("\tDisabled subregion ", i);
304             } else {
305                 SPMLOG_INFMSGVAL("\tEnabled subregion ", i);
306             }
307         }
308     }
309 }
310 
SMPU_Read_Region(const PROT_SMPU_SMPU_STRUCT_Type * smpu,uint32_t * address,uint32_t * size,uint32_t * subregions,uint32_t * att0_reg)311 static cy_en_prot_status_t SMPU_Read_Region(const PROT_SMPU_SMPU_STRUCT_Type *smpu,
312                                             uint32_t *address,
313                                             uint32_t *size,
314                                             uint32_t *subregions,
315                                             uint32_t *att0_reg)
316 {
317     uint32_t reg = smpu->ATT0;
318 
319     /* Return a copy of ATT0 if requested */
320     if (att0_reg) {
321         *att0_reg = reg;
322     }
323 
324     if (!_FLD2BOOL(PROT_SMPU_SMPU_STRUCT_ATT0_ENABLED, reg)) {
325         /* Disabled SMPU */
326         return CY_PROT_FAILURE;
327     }
328 
329     *size = REGIONSIZE_TO_BYTES(_FLD2VAL(PROT_SMPU_SMPU_STRUCT_ATT0_REGION_SIZE, reg));
330     reg = smpu->ADDR0;
331     *subregions = _FLD2VAL(PROT_SMPU_SMPU_STRUCT_ADDR0_SUBREGION_DISABLE, reg);
332     *address = _FLD2VAL(PROT_SMPU_SMPU_STRUCT_ADDR0_ADDR24, reg) << 8;
333     /* Some address bits may be ignored */
334     *address -= *address % *size;
335     return CY_PROT_SUCCESS;
336 }
337 
dump_smpu(const PROT_SMPU_SMPU_STRUCT_Type * smpu)338 static void dump_smpu(const PROT_SMPU_SMPU_STRUCT_Type *smpu)
339 {
340     uint32_t base;
341     size_t size;
342     uint32_t size32;
343     uint32_t subregions;
344 
345     if (CY_PROT_SUCCESS == get_region(smpu, &base, &size)) {
346         SPMLOG_INFMSGVAL(" Wanted address = ", base);
347         SPMLOG_INFMSGVAL(" Wanted size (bytes) = ", size);
348     } else {
349         SPMLOG_ERRMSG(" Unsupported dynamic SMPU region\r\n");
350     }
351 
352     if (SMPU_Read_Region(smpu, &base, &size32, &subregions, NULL) == CY_PROT_SUCCESS) {
353         SPMLOG_INFMSGVAL(" Configured address = ", base);
354         SPMLOG_INFMSGVAL(" Configured size (bytes) = ", size32);
355 
356         if (subregions == ALL_ENABLED) {
357             SPMLOG_INFMSG(" All subregions enabled\r\n");
358         } else {
359             SPMLOG_INFMSGVAL("\tsubregion size (bytes) = ", size32/8);
360             for (int i=0; i<8; i++) {
361                 if (subregions & (1<<i)) {
362                     SPMLOG_INFMSGVAL("\tDisabled subregion ", i);
363                 } else {
364                     SPMLOG_INFMSGVAL("\tEnabled subregion ", i);
365                 }
366             }
367         }
368     } else {
369         SPMLOG_ERRMSG("SMPU slave is disabled\r\n");
370     }
371 }
372 
373 /*
374  * For the given Protection Context, check whether the specified
375  * SMPU controls access to the specified memory range for the specified PC.
376  * If so, set *p_attr accordingly.
377  */
SMPU_Covers_Region(const void * p,size_t s,uint32_t pc,PROT_SMPU_SMPU_STRUCT_Type * smpu,struct mem_attr_info_t * p_attr)378 static bool SMPU_Covers_Region(const void *p, size_t s,
379                                uint32_t pc,
380                                PROT_SMPU_SMPU_STRUCT_Type *smpu,
381                                struct mem_attr_info_t *p_attr)
382 {
383     bool pc_mismatch = false;
384     uint32_t address;
385     uint32_t size;
386     uint32_t subregions;
387     uint32_t att0;
388     cy_en_prot_status_t status = SMPU_Read_Region(smpu,
389                                                   &address,
390                                                   &size,
391                                                   &subregions,
392                                                   &att0);
393     if (status != CY_PROT_SUCCESS) {
394         /* Disabled SMPU */
395         return false;
396     }
397 
398     /* Check PC */
399     if ((_FLD2VAL(PROT_SMPU_SMPU_STRUCT_ATT0_PC_MASK_15_TO_1, att0)
400         & (1 << (pc - 1))) == 0) {
401         /* pc does not match the mask */
402         if (_FLD2BOOL(PROT_SMPU_SMPU_STRUCT_ATT0_PC_MATCH, att0)) {
403             /* This SMPU neither allows nor denies access for this PC */
404             return false;
405         }
406         /* In this case we need to check whether the address range is covered */
407         pc_mismatch = true;
408     }
409 
410     /* And the address range */
411     if (check_address_range(p, s, address, size) == SPM_SUCCESS) {
412         if (pc_mismatch) {
413             /* Access denied - PC doesn't match */
414             p_attr->is_mpu_enabled = true;
415             p_attr->is_valid = true;
416             p_attr->is_xn = true;
417             p_attr->is_priv_rd_allow = false;
418             p_attr->is_priv_wr_allow = false;
419             p_attr->is_unpriv_rd_allow = false;
420             p_attr->is_unpriv_wr_allow = false;
421         }  else {
422             p_attr->is_mpu_enabled = true;
423             p_attr->is_valid = true;
424             /* SMPU has separate PX and UX bits. Here we ignore UX */
425             p_attr->is_xn = !_FLD2BOOL(PROT_SMPU_SMPU_STRUCT_ATT0_PX, att0);
426             p_attr->is_priv_rd_allow = _FLD2BOOL(PROT_SMPU_SMPU_STRUCT_ATT0_PR, att0);
427             p_attr->is_priv_wr_allow = _FLD2BOOL(PROT_SMPU_SMPU_STRUCT_ATT0_PW, att0);
428             p_attr->is_unpriv_rd_allow = _FLD2BOOL(PROT_SMPU_SMPU_STRUCT_ATT0_UR, att0);
429             p_attr->is_unpriv_wr_allow = _FLD2BOOL(PROT_SMPU_SMPU_STRUCT_ATT0_UW, att0);
430         }
431         return true;
432     }
433 
434     return false;
435 }
436 
437 /* API functions */
438 
SMPU_Get_Access_Rules(const void * p,size_t s,uint32_t pc,struct mem_attr_info_t * p_attr)439 void SMPU_Get_Access_Rules(const void *p, size_t s,
440                            uint32_t pc,
441                            struct mem_attr_info_t *p_attr)
442 {
443     /* Higher-numbered SMPUs have priority */
444     for (int i = CPUSS_PROT_SMPU_STRUCT_NR; i > 0; i--) {
445         if (SMPU_Covers_Region(p, s, pc, &PROT->SMPU.SMPU_STRUCT[i - 1], p_attr)) {
446             /* It's covered by this SMPU */
447             return;
448         }
449     }
450 
451     /* no SMPU covers it */
452     p_attr->is_mpu_enabled = false;
453     p_attr->is_valid = true;
454     p_attr->is_xn = true;
455     p_attr->is_priv_rd_allow = true;
456     p_attr->is_priv_wr_allow = true;
457     p_attr->is_unpriv_rd_allow = true;
458     p_attr->is_unpriv_wr_allow = true;
459 }
460 
SMPU_Print_Config(const SMPU_Resources * smpu_dev)461 void SMPU_Print_Config(const SMPU_Resources *smpu_dev)
462 {
463     char smpu_str[SMPU_NAME_MAX_SIZE] = {0};
464 
465     strcpy(smpu_str, smpu_name(smpu_dev));
466     SPMLOG_INFMSG(smpu_str);
467     if (is_runtime(smpu_dev)) {
468         SPMLOG_INFMSG(" - configured algorithmically.\r\n");
469 
470         dump_smpu(smpu_dev->smpu);
471     } else {
472         SPMLOG_INFMSG(" - configured at compile time.\r\n");
473 
474         print_smpu_config(&smpu_dev->slave_config);
475     }
476 }
477 
SMPU_Configure(const SMPU_Resources * smpu_dev)478 cy_en_prot_status_t SMPU_Configure(const SMPU_Resources *smpu_dev)
479 {
480     cy_en_prot_status_t ret;
481 
482     if (is_runtime(smpu_dev)) {
483         cy_stc_smpu_cfg_t slave_config;
484 
485         /* Start with a verbatim copy of the slave config */
486         memcpy(&slave_config, &smpu_dev->slave_config, sizeof(slave_config));
487 
488         ret = populate_region(smpu_dev->smpu, &slave_config);
489         if (ret != CY_PROT_SUCCESS) {
490             return ret;
491         }
492 
493         ret = Cy_Prot_ConfigSmpuSlaveStruct(smpu_dev->smpu,
494                                             &slave_config);
495     } else {
496         /* Use the slave config verbatim */
497         ret = Cy_Prot_ConfigSmpuSlaveStruct(smpu_dev->smpu,
498                                             &smpu_dev->slave_config);
499     }
500 
501     if (ret != CY_PROT_SUCCESS) {
502         return ret;
503     }
504     ret = Cy_Prot_ConfigSmpuMasterStruct(smpu_dev->smpu,
505                                          &smpu_dev->master_config);
506     if (ret != CY_PROT_SUCCESS) {
507         return ret;
508     }
509     ret = Cy_Prot_EnableSmpuSlaveStruct(smpu_dev->smpu);
510     if (ret != CY_PROT_SUCCESS) {
511         return ret;
512     }
513     ret = Cy_Prot_EnableSmpuMasterStruct(smpu_dev->smpu);
514     return ret;
515 }
516 
517 /* Only allow privileged secure PC=1 bus masters to change unconfigured SMPUs */
protect_unconfigured_smpus(void)518 cy_en_prot_status_t protect_unconfigured_smpus(void)
519 {
520     const cy_stc_smpu_cfg_t smpu_config = COMMON_SMPU_MASTER_CONFIG;
521     cy_en_prot_status_t ret = CY_PROT_SUCCESS;
522     int i;
523     uint32_t att0, att1;
524 
525     for (i = 0; i < CPUSS_PROT_SMPU_STRUCT_NR; i++) {
526         att0 = PROT->SMPU.SMPU_STRUCT[i].ATT0;
527         att1 = PROT->SMPU.SMPU_STRUCT[i].ATT1;
528 
529         if ((_FLD2VAL(PROT_SMPU_SMPU_STRUCT_ATT0_ENABLED, att0) == 0)
530             && (_FLD2VAL(PROT_SMPU_SMPU_STRUCT_ATT1_ENABLED, att1) == 0)) {
531 
532             ret = Cy_Prot_ConfigSmpuMasterStruct(&PROT->SMPU.SMPU_STRUCT[i],
533                                                  &smpu_config);
534             if (ret != CY_PROT_SUCCESS) {
535                 break;
536             }
537             ret = Cy_Prot_EnableSmpuMasterStruct(&PROT->SMPU.SMPU_STRUCT[i]);
538             if (ret != CY_PROT_SUCCESS) {
539                 break;
540             }
541         }
542     }
543 
544     return ret;
545 }
546 
547 /* Exported per-SMPU macros */
548 #define DEFINE_SMPU(N) const SMPU_Resources SMPU##N##_Resources = { \
549     .smpu = PROT_SMPU_SMPU_STRUCT##N, \
550     .slave_config = SMPU##N##_SLAVE_CONFIG, \
551     .master_config = SMPU##N##_MASTER_CONFIG, \
552 }; \
553 
554 #if (RTE_SMPU0)
555 DEFINE_SMPU(0)
556 #endif /* RTE_SMPU0 */
557 
558 #if (RTE_SMPU1)
559 DEFINE_SMPU(1)
560 #endif /* RTE_SMPU1 */
561 
562 #if (RTE_SMPU2)
563 DEFINE_SMPU(2)
564 #endif /* RTE_SMPU2 */
565 
566 #if (RTE_SMPU3)
567 DEFINE_SMPU(3)
568 #endif /* RTE_SMPU3 */
569 
570 #if (RTE_SMPU4)
571 DEFINE_SMPU(4)
572 #endif /* RTE_SMPU4 */
573 
574 #if (RTE_SMPU5)
575 DEFINE_SMPU(5)
576 #endif /* RTE_SMPU5 */
577 
578 #if (RTE_SMPU6)
579 DEFINE_SMPU(6)
580 #endif /* RTE_SMPU6 */
581 
582 #if (RTE_SMPU7)
583 DEFINE_SMPU(7)
584 #endif /* RTE_SMPU7 */
585 
586 #if (RTE_SMPU8)
587 DEFINE_SMPU(8)
588 #endif /* RTE_SMPU8 */
589 
590 #if (RTE_SMPU9)
591 DEFINE_SMPU(9)
592 #endif /* RTE_SMPU9 */
593 
594 #if (RTE_SMPU10)
595 DEFINE_SMPU(10)
596 #endif /* RTE_SMPU10 */
597 
598 #if (RTE_SMPU11)
599 DEFINE_SMPU(11)
600 #endif /* RTE_SMPU11 */
601 
602 #if (RTE_SMPU12)
603 DEFINE_SMPU(12)
604 #endif /* RTE_SMPU12 */
605 
606 #if (RTE_SMPU13)
607 DEFINE_SMPU(13)
608 #endif /* RTE_SMPU13 */
609 
610 /* Note that SMPUs 14 and 15 are fixed by romboot */
611