1
1
/*
2
- Copyright (c) 2016-2019 Raspberry Pi (Trading) Ltd.
2
+ Copyright (c) 2016-2023 Raspberry Pi Ltd.
3
3
All rights reserved.
4
4
5
5
Redistribution and use in source and binary forms, with or without
@@ -75,6 +75,12 @@ static DTBLOB_T *overlay_map;
75
75
static const char * platform_name ;
76
76
static int platform_name_len ;
77
77
78
+ static void (* cell_changed_callback )(DTBLOB_T * , int , const char * , int , int );
79
+ static void (* intra_fragment_merged_callback )(DTBLOB_T * , int , int );
80
+
81
+ static const void * override_data_start ;
82
+ static const void * cell_source ;
83
+
78
84
static int strmemcmp (const char * mem , int mem_len , const char * str )
79
85
{
80
86
int ret = strncmp (mem , str , mem_len );
@@ -602,7 +608,9 @@ static int dtoverlay_merge_fragment(DTBLOB_T *base_dtb, int target_off,
602
608
err = fdt_appendprop (base_dtb -> fdt , target_off , prop_name , prop_val , prop_len );
603
609
}
604
610
else
611
+ {
605
612
err = fdt_setprop (base_dtb -> fdt , target_off , prop_name , prop_val , prop_len );
613
+ }
606
614
}
607
615
608
616
// Merge each subnode of the node
@@ -1167,7 +1175,6 @@ int dtoverlay_merge_overlay(DTBLOB_T *base_dtb, DTBLOB_T *overlay_dtb)
1167
1175
}
1168
1176
1169
1177
target_off = dtoverlay_get_target_offset (NULL , overlay_dtb , frag_off );
1170
-
1171
1178
if (target_off < 0 )
1172
1179
continue ;
1173
1180
@@ -1176,6 +1183,9 @@ int dtoverlay_merge_overlay(DTBLOB_T *base_dtb, DTBLOB_T *overlay_dtb)
1176
1183
// as source and destination because the source is not expected to
1177
1184
// change. Instead, clone the overlay, apply the fragment, then switch.
1178
1185
1186
+ if (intra_fragment_merged_callback )
1187
+ (* intra_fragment_merged_callback )(overlay_dtb , overlay_off , target_off );
1188
+
1179
1189
if (!overlay_copy )
1180
1190
{
1181
1191
overlay_copy = malloc (overlay_size );
@@ -1192,6 +1202,7 @@ int dtoverlay_merge_overlay(DTBLOB_T *base_dtb, DTBLOB_T *overlay_dtb)
1192
1202
overlay_off , 0 );
1193
1203
if (err )
1194
1204
break ;
1205
+
1195
1206
// Swap the buffers
1196
1207
{
1197
1208
void * temp = overlay_dtb -> fdt ;
@@ -1441,6 +1452,170 @@ int dtoverlay_filter_symbols(DTBLOB_T *dtb)
1441
1452
return 0 ;
1442
1453
}
1443
1454
1455
+ const char * dtoverlay_find_fixup (DTBLOB_T * dtb , const char * fixup_loc )
1456
+ {
1457
+ int fixups_off ;
1458
+
1459
+ fixups_off = fdt_path_offset (dtb -> fdt , "/__fixups__" );
1460
+
1461
+ if (fixups_off > 0 )
1462
+ {
1463
+ int fixup_off ;
1464
+
1465
+ for (fixup_off = fdt_first_property_offset (dtb -> fdt , fixups_off );
1466
+ fixup_off >= 0 ;
1467
+ fixup_off = fdt_next_property_offset (dtb -> fdt , fixup_off ))
1468
+ {
1469
+ const char * fixups_stringlist ;
1470
+ const char * symbol_name ;
1471
+ int list_len ;
1472
+
1473
+ fixups_stringlist = fdt_getprop_by_offset (dtb -> fdt , fixup_off ,
1474
+ & symbol_name , & list_len );
1475
+ if (fdt_stringlist_contains (fixups_stringlist , list_len , fixup_loc ) > 0 )
1476
+ return symbol_name ;
1477
+ }
1478
+ }
1479
+
1480
+ return NULL ;
1481
+ }
1482
+
1483
+ int dtoverlay_add_fixup (DTBLOB_T * dtb , const char * symbol , const char * fixup_loc )
1484
+ {
1485
+ int loc_len = strlen (fixup_loc );
1486
+ int fixups_off ;
1487
+
1488
+ fixups_off = fdt_path_offset (dtb -> fdt , "/__fixups__" );
1489
+ assert (fixups_off > 0 );
1490
+
1491
+ if (fixups_off < 0 )
1492
+ return fixups_off ;
1493
+
1494
+ return fdt_appendprop (dtb -> fdt , fixups_off , symbol , fixup_loc , loc_len + 1 );
1495
+ }
1496
+
1497
+ static const char * stringlist_find (const char * strlist , int listlen , const char * str , int len )
1498
+ {
1499
+ const char * p ;
1500
+
1501
+ while (listlen >= len ) {
1502
+ if (memcmp (str , strlist , len + 1 ) == 0 )
1503
+ return strlist ;
1504
+ p = memchr (strlist , '\0' , listlen );
1505
+ if (!p )
1506
+ return NULL ; /* malformed strlist.. */
1507
+ listlen -= (p - strlist ) + 1 ;
1508
+ strlist = p + 1 ;
1509
+ }
1510
+
1511
+ return NULL ;
1512
+ }
1513
+
1514
+ int dtoverlay_delete_fixup (DTBLOB_T * dtb , const char * fixup_loc )
1515
+ {
1516
+ int loc_len = strlen (fixup_loc );
1517
+ int fixups_off ;
1518
+
1519
+ fixups_off = fdt_path_offset (dtb -> fdt , "/__fixups__" );
1520
+
1521
+ if (fixups_off > 0 )
1522
+ {
1523
+ int fixup_off ;
1524
+
1525
+ for (fixup_off = fdt_first_property_offset (dtb -> fdt , fixups_off );
1526
+ fixup_off >= 0 ;
1527
+ fixup_off = fdt_next_property_offset (dtb -> fdt , fixup_off ))
1528
+ {
1529
+ const char * fixups_stringlist ;
1530
+ const char * symbol_name ;
1531
+ const char * match ;
1532
+ int list_len ;
1533
+
1534
+ fixups_stringlist = fdt_getprop_by_offset (dtb -> fdt , fixup_off ,
1535
+ & symbol_name , & list_len );
1536
+
1537
+ match = stringlist_find (fixups_stringlist , list_len , fixup_loc , loc_len );
1538
+ if (match )
1539
+ {
1540
+ int match_len = loc_len + 1 ;
1541
+ if (match_len == list_len )
1542
+ {
1543
+ /* This was the only fixup - the symbol is no longer referenced */
1544
+ return fdt_delprop (dtb -> fdt , fixups_off , symbol_name );
1545
+ }
1546
+ else
1547
+ {
1548
+ char * buf = malloc (list_len - match_len );
1549
+ int match_off = match - fixups_stringlist ;
1550
+ int after_match = list_len - (match_off + match_len );
1551
+ int err ;
1552
+ if (match_off )
1553
+ memcpy (buf , fixups_stringlist , match_off );
1554
+ if (after_match )
1555
+ memcpy (buf + match_off , match + match_len , after_match );
1556
+ err = fdt_setprop (dtb -> fdt , fixups_off , symbol_name , buf , list_len - match_len );
1557
+ free (buf );
1558
+ return err ;
1559
+ }
1560
+ }
1561
+ }
1562
+ }
1563
+
1564
+ return - FDT_ERR_NOTFOUND ;
1565
+ }
1566
+
1567
+ int dtoverlay_stringlist_replace (const char * src , int src_len ,
1568
+ const char * src_prefix , int src_prefix_len ,
1569
+ const char * dst_prefix , int dst_prefix_len ,
1570
+ char * dst )
1571
+ {
1572
+ /* With a NULL dst, only returns the new length */
1573
+ char * dst_p = dst ;
1574
+ int replaced = 0 ;
1575
+
1576
+ while (src_len )
1577
+ {
1578
+ const char * p ;
1579
+ int copy_bytes ;
1580
+
1581
+ p = memchr (src , '\0' , src_len );
1582
+ if (!p )
1583
+ return -1 ; /* malformed strlist.. */
1584
+
1585
+ if (src_prefix_len < src_len && memcmp (src , src_prefix , src_prefix_len ) == 0 )
1586
+ {
1587
+ if (dst )
1588
+ memcpy (dst_p , dst_prefix , dst_prefix_len );
1589
+ src_len -= src_prefix_len ;
1590
+ src += src_prefix_len ;
1591
+ dst_p += dst_prefix_len ;
1592
+ replaced = 1 ;
1593
+ }
1594
+
1595
+ copy_bytes = (p - src ) + 1 ;
1596
+ if (dst )
1597
+ memcpy (dst_p , src , copy_bytes );
1598
+ dst_p += copy_bytes ;
1599
+ src_len -= copy_bytes ;
1600
+ src = p + 1 ;
1601
+ }
1602
+
1603
+ if (!replaced )
1604
+ return -1 ;
1605
+
1606
+ return dst_p - dst ;
1607
+ }
1608
+
1609
+ void dtoverlay_set_intra_fragment_merged_callback (void (* callback )(DTBLOB_T * , int , int ))
1610
+ {
1611
+ intra_fragment_merged_callback = callback ;
1612
+ }
1613
+
1614
+ void dtoverlay_set_cell_changed_callback (void (* callback )(DTBLOB_T * , int , const char * , int , int ))
1615
+ {
1616
+ cell_changed_callback = callback ;
1617
+ }
1618
+
1444
1619
/* Returns a pointer to the override data and (through data_len) its length.
1445
1620
On error, sets *data_len to be the error code. */
1446
1621
const char * dtoverlay_find_override (DTBLOB_T * dtb , const char * override_name ,
@@ -1790,6 +1965,10 @@ int dtoverlay_override_one_target(int override_type,
1790
1965
}
1791
1966
}
1792
1967
1968
+ if (!err && cell_changed_callback && cell_source && override_type == DTOVERRIDE_INTEGER && target_size == 4 )
1969
+ (* cell_changed_callback )(dtb , node_off , prop_name , target_off ,
1970
+ (int )(cell_source - override_data_start ));
1971
+
1793
1972
return err ;
1794
1973
}
1795
1974
@@ -1844,6 +2023,7 @@ int dtoverlay_foreach_override_target(DTBLOB_T *dtb, const char *override_name,
1844
2023
memcpy (data_buf , override_data , data_len );
1845
2024
data = data_buf ;
1846
2025
data_end = data + data_len ;
2026
+ override_data_start = data_buf ;
1847
2027
1848
2028
while (err == 0 )
1849
2029
{
@@ -1869,7 +2049,6 @@ int dtoverlay_foreach_override_target(DTBLOB_T *dtb, const char *override_name,
1869
2049
err = override_type ;
1870
2050
break ;
1871
2051
}
1872
- /* Pass DTOVERRIDE_END to the callback, in case it is interested */
1873
2052
1874
2053
if (target_phandle != 0 )
1875
2054
{
@@ -1889,8 +2068,10 @@ int dtoverlay_foreach_override_target(DTBLOB_T *dtb, const char *override_name,
1889
2068
prop_name [name_len ] = '\0' ;
1890
2069
}
1891
2070
2071
+ /* Pass DTOVERRIDE_END to the callback, in case it is interested */
1892
2072
err = callback (override_type , target_value , dtb , node_off , prop_name ,
1893
- target_phandle , target_off , target_size , callback_state );
2073
+ target_phandle , target_off , target_size ,
2074
+ callback_state );
1894
2075
1895
2076
if (override_type == DTOVERRIDE_END )
1896
2077
break ;
@@ -1930,6 +2111,8 @@ static int dtoverlay_extract_override(const char *override_name,
1930
2111
char literal_type = '?' ;
1931
2112
int type ;
1932
2113
2114
+ cell_source = NULL ;
2115
+
1933
2116
data = * datap ;
1934
2117
len = data_end - data ;
1935
2118
if (len <= 0 )
@@ -2104,6 +2287,7 @@ static int dtoverlay_extract_override(const char *override_name,
2104
2287
{
2105
2288
/* Cell */
2106
2289
sprintf (override_value , "%d" , dtoverlay_read_u32 (data , 0 ));
2290
+ cell_source = data ;
2107
2291
* datap = data + 4 ;
2108
2292
}
2109
2293
}
@@ -2159,6 +2343,7 @@ static const char *dtoverlay_extract_immediate(const char *data, const char *dat
2159
2343
return NULL ;
2160
2344
}
2161
2345
val = dtoverlay_read_u32 (data , 0 );
2346
+ cell_source = data ;
2162
2347
if (buf )
2163
2348
snprintf (buf , buf_len , "%d" , val );
2164
2349
data += 4 ;
0 commit comments