22#include <linux/types.h>
33#include <linux/init.h>
44#include <linux/libfdt.h>
5+ #include <linux/ctype.h>
56
6- /*
7- * Declare the functions that are exported (but prefixed) here so that LLVM
8- * does not complain it lacks the 'static' keyword (which, if added, makes
9- * LLVM complain because the function is actually unused in this file).
10- */
11- u64 get_kaslr_seed (uintptr_t dtb_pa );
7+ #include "pi.h"
128
139u64 get_kaslr_seed (uintptr_t dtb_pa )
1410{
@@ -28,3 +24,162 @@ u64 get_kaslr_seed(uintptr_t dtb_pa)
2824 * prop = 0 ;
2925 return ret ;
3026}
27+
28+ /**
29+ * fdt_device_is_available - check if a device is available for use
30+ *
31+ * @fdt: pointer to the device tree blob
32+ * @node: offset of the node whose property to find
33+ *
34+ * Returns true if the status property is absent or set to "okay" or "ok",
35+ * false otherwise
36+ */
37+ static bool fdt_device_is_available (const void * fdt , int node )
38+ {
39+ const char * status ;
40+ int statlen ;
41+
42+ status = fdt_getprop (fdt , node , "status" , & statlen );
43+ if (!status )
44+ return true;
45+
46+ if (statlen > 0 ) {
47+ if (!strcmp (status , "okay" ) || !strcmp (status , "ok" ))
48+ return true;
49+ }
50+
51+ return false;
52+ }
53+
54+ /* Copy of fdt_nodename_eq_ */
55+ static int fdt_node_name_eq (const void * fdt , int offset ,
56+ const char * s )
57+ {
58+ int olen ;
59+ int len = strlen (s );
60+ const char * p = fdt_get_name (fdt , offset , & olen );
61+
62+ if (!p || olen < len )
63+ /* short match */
64+ return 0 ;
65+
66+ if (memcmp (p , s , len ) != 0 )
67+ return 0 ;
68+
69+ if (p [len ] == '\0' )
70+ return 1 ;
71+ else if (!memchr (s , '@' , len ) && (p [len ] == '@' ))
72+ return 1 ;
73+ else
74+ return 0 ;
75+ }
76+
77+ /**
78+ * isa_string_contains - check if isa string contains an extension
79+ *
80+ * @isa_str: isa string to search
81+ * @ext_name: the extension to search for
82+ *
83+ * Returns true if the extension is in the given isa string,
84+ * false otherwise
85+ */
86+ static bool isa_string_contains (const char * isa_str , const char * ext_name )
87+ {
88+ size_t i , single_end , len = strlen (ext_name );
89+ char ext_end ;
90+
91+ /* Error must contain rv32/64 */
92+ if (strlen (isa_str ) < 4 )
93+ return false;
94+
95+ if (len == 1 ) {
96+ single_end = strcspn (isa_str , "sSxXzZ" );
97+ /* Search for single chars between rv32/64 and multi-letter extensions */
98+ for (i = 4 ; i < single_end ; i ++ ) {
99+ if (tolower (isa_str [i ]) == ext_name [0 ])
100+ return true;
101+ }
102+ return false;
103+ }
104+
105+ /* Skip to start of multi-letter extensions */
106+ isa_str = strpbrk (isa_str , "sSxXzZ" );
107+ while (isa_str ) {
108+ if (strncasecmp (isa_str , ext_name , len ) == 0 ) {
109+ ext_end = isa_str [len ];
110+ /* Check if matches the whole extension. */
111+ if (ext_end == '\0' || ext_end == '_' )
112+ return true;
113+ }
114+ /* Multi-letter extensions must be split from other multi-letter
115+ * extensions with an "_", the end of a multi-letter extension will
116+ * either be the null character or the "_" at the start of the next
117+ * multi-letter extension.
118+ */
119+ isa_str = strchr (isa_str , '_' );
120+ if (isa_str )
121+ isa_str ++ ;
122+ }
123+
124+ return false;
125+ }
126+
127+ /**
128+ * early_cpu_isa_ext_available - check if cpu node has an extension
129+ *
130+ * @fdt: pointer to the device tree blob
131+ * @node: offset of the cpu node
132+ * @ext_name: the extension to search for
133+ *
134+ * Returns true if the cpu node has the extension,
135+ * false otherwise
136+ */
137+ static bool early_cpu_isa_ext_available (const void * fdt , int node , const char * ext_name )
138+ {
139+ const void * prop ;
140+ int len ;
141+
142+ prop = fdt_getprop (fdt , node , "riscv,isa-extensions" , & len );
143+ if (prop && fdt_stringlist_contains (prop , len , ext_name ))
144+ return true;
145+
146+ prop = fdt_getprop (fdt , node , "riscv,isa" , & len );
147+ if (prop && isa_string_contains (prop , ext_name ))
148+ return true;
149+
150+ return false;
151+ }
152+
153+ /**
154+ * fdt_early_match_extension_isa - check if all cpu nodes have an extension
155+ *
156+ * @fdt: pointer to the device tree blob
157+ * @ext_name: the extension to search for
158+ *
159+ * Returns true if the all available the cpu nodes have the extension,
160+ * false otherwise
161+ */
162+ bool fdt_early_match_extension_isa (const void * fdt , const char * ext_name )
163+ {
164+ int node , parent ;
165+ bool ret = false;
166+
167+ parent = fdt_path_offset (fdt , "/cpus" );
168+ if (parent < 0 )
169+ return false;
170+
171+ fdt_for_each_subnode (node , fdt , parent ) {
172+ if (!fdt_node_name_eq (fdt , node , "cpu" ))
173+ continue ;
174+
175+ if (!fdt_device_is_available (fdt , node ))
176+ continue ;
177+
178+ if (!early_cpu_isa_ext_available (fdt , node , ext_name ))
179+ return false;
180+
181+ ret = true;
182+ }
183+
184+ return ret ;
185+ }
0 commit comments