@@ -228,7 +228,7 @@ uint32_t val_mmu_update_entry(uint64_t address, uint32_t size, uint64_t attr)
228228/**
229229 @brief This is local function is used to get log base 2 of input value.
230230
231- @param value - input value
231+ @param value - input value.
232232
233233 @return result
234234**/
@@ -258,27 +258,54 @@ void val_setup_mair_register(void)
258258 MAIR_DEVICE_nGnRnE , MAIR_NORMAL_NC , MAIR_NORMAL_WT_AGR ,
259259 MAIR_NORMAL_WB , MAIR_DEVICE_nGnRE , MAIR_DEVICE_nGRE , MAIR_DEVICE_GRE ,
260260 MAIR_NORMAL_WT };
261- uint64_t mair_val = 0 ;
261+ uint64_t mair_val ;
262+ uint64_t current_mair ;
263+ uint8_t attr_seen [256 ];
264+ uint8_t free_slots [8 ];
265+ uint32_t free_cnt = 0 ;
262266
263267 currentEL = (val_read_current_el () & 0xc ) >> 2 ;
264- /*
265- * Setup Memory Attribute Indirection Register
266- * Attr0 = MAIR_DEVICE_nGnRnE
267- * Attr1 = MAIR_NORMAL_NC
268- * Attr2 = MAIR_NORMAL_WT_AGR
269- * Attr3 = MAIR_NORMAL_WB
270- * Attr4 = MAIR_DEVICE_nGnRE
271- * Attr5 = MAIR_DEVICE_nGRE
272- * Attr6 = MAIR_DEVICE_GRE
273- * Attr7 = MAIR_NORMAL_WT
274- */
275- for (uint64_t attr = 0 ; attr < (sizeof (mair_attr ) / sizeof (mair_attr [0 ])); attr ++ )
268+
269+ current_mair = val_pe_reg_read (MAIR_ELx );
270+ mair_val = current_mair ;
271+
272+ val_memory_set (attr_seen , sizeof (attr_seen ), 0 );
273+ /* Identify unique existing attributes so we leave them untouched,
274+ and treat any duplicate slots as available for new attributes. */
275+ for (uint32_t idx = 0 ; idx < 8 ; idx ++ ) {
276+ uint8_t entry = (current_mair >> (idx * 8 )) & 0xFF ;
277+
278+ if (!attr_seen [entry ]) {
279+ attr_seen [entry ] = 1 ;
280+ } else {
281+ free_slots [free_cnt ++ ] = idx ;
282+ }
283+ }
284+
285+ for (uint32_t attr = 0 ; attr < (sizeof (mair_attr ) / sizeof (mair_attr [0 ])); attr ++ )
276286 {
277- mair_val = mair_val | ((uint64_t )(mair_attr [attr ]) << (attr * 8 ));
287+ uint8_t new_attr = mair_attr [attr ];
288+
289+ if (attr_seen [new_attr ])
290+ continue ;
291+
292+ if (free_cnt == 0 ) {
293+ val_print (ACS_PRINT_WARN ,
294+ "\n MAIR register full, could not add attribute 0x%02x" , new_attr );
295+ break ;
296+ }
297+
298+ uint32_t slot = free_slots [-- free_cnt ];
299+ mair_val &= ~((uint64_t )0xFF << (slot * 8 ));
300+ mair_val |= ((uint64_t )new_attr << (slot * 8 ));
301+ attr_seen [new_attr ] = 1 ;
278302 }
279303
280- val_mair_write (mair_val , currentEL );
304+ if (mair_val != current_mair )
305+ val_mair_write (mair_val , currentEL );
281306
307+ val_print (ACS_PRINT_DEBUG , "\n Previous MAIR register value 0x%lx" , current_mair );
308+ val_print (ACS_PRINT_DEBUG , "\n Current MAIR register value 0x%lx\n" , mair_val );
282309 return ;
283310}
284311
0 commit comments