2121
2222static u64 __boot_status __initdata ;
2323
24+ // temporary __prel64 related definitions
25+ // to be removed when this code is moved under pi/
26+
27+ #define __prel64_initconst __initconst
28+
29+ #define PREL64 (type , name ) union { type *name; }
30+
31+ #define prel64_pointer (__d ) (__d)
32+
33+ typedef bool filter_t (u64 val );
34+
2435struct ftr_set_desc {
2536 char name [FTR_DESC_NAME_LEN ];
26- struct arm64_ftr_override * override ;
37+ PREL64 ( struct arm64_ftr_override , override ) ;
2738 struct {
2839 char name [FTR_DESC_FIELD_LEN ];
2940 u8 shift ;
3041 u8 width ;
31- bool ( * filter )( u64 val );
42+ PREL64 ( filter_t , filter );
3243 } fields [];
3344};
3445
@@ -46,7 +57,7 @@ static bool __init mmfr1_vh_filter(u64 val)
4657 val == 0 );
4758}
4859
49- static const struct ftr_set_desc mmfr1 __initconst = {
60+ static const struct ftr_set_desc mmfr1 __prel64_initconst = {
5061 .name = "id_aa64mmfr1" ,
5162 .override = & id_aa64mmfr1_override ,
5263 .fields = {
@@ -70,7 +81,7 @@ static bool __init pfr0_sve_filter(u64 val)
7081 return true;
7182}
7283
73- static const struct ftr_set_desc pfr0 __initconst = {
84+ static const struct ftr_set_desc pfr0 __prel64_initconst = {
7485 .name = "id_aa64pfr0" ,
7586 .override = & id_aa64pfr0_override ,
7687 .fields = {
@@ -94,7 +105,7 @@ static bool __init pfr1_sme_filter(u64 val)
94105 return true;
95106}
96107
97- static const struct ftr_set_desc pfr1 __initconst = {
108+ static const struct ftr_set_desc pfr1 __prel64_initconst = {
98109 .name = "id_aa64pfr1" ,
99110 .override = & id_aa64pfr1_override ,
100111 .fields = {
@@ -105,7 +116,7 @@ static const struct ftr_set_desc pfr1 __initconst = {
105116 },
106117};
107118
108- static const struct ftr_set_desc isar1 __initconst = {
119+ static const struct ftr_set_desc isar1 __prel64_initconst = {
109120 .name = "id_aa64isar1" ,
110121 .override = & id_aa64isar1_override ,
111122 .fields = {
@@ -117,7 +128,7 @@ static const struct ftr_set_desc isar1 __initconst = {
117128 },
118129};
119130
120- static const struct ftr_set_desc isar2 __initconst = {
131+ static const struct ftr_set_desc isar2 __prel64_initconst = {
121132 .name = "id_aa64isar2" ,
122133 .override = & id_aa64isar2_override ,
123134 .fields = {
@@ -128,7 +139,7 @@ static const struct ftr_set_desc isar2 __initconst = {
128139 },
129140};
130141
131- static const struct ftr_set_desc smfr0 __initconst = {
142+ static const struct ftr_set_desc smfr0 __prel64_initconst = {
132143 .name = "id_aa64smfr0" ,
133144 .override = & id_aa64smfr0_override ,
134145 .fields = {
@@ -149,7 +160,7 @@ static bool __init hvhe_filter(u64 val)
149160 ID_AA64MMFR1_EL1_VH_SHIFT ));
150161}
151162
152- static const struct ftr_set_desc sw_features __initconst = {
163+ static const struct ftr_set_desc sw_features __prel64_initconst = {
153164 .name = "arm64_sw" ,
154165 .override = & arm64_sw_feature_override ,
155166 .fields = {
@@ -159,22 +170,23 @@ static const struct ftr_set_desc sw_features __initconst = {
159170 },
160171};
161172
162- static const struct ftr_set_desc * const regs [] __initconst = {
163- & mmfr1 ,
164- & pfr0 ,
165- & pfr1 ,
166- & isar1 ,
167- & isar2 ,
168- & smfr0 ,
169- & sw_features ,
173+ static const
174+ PREL64 (const struct ftr_set_desc , reg ) regs [] __prel64_initconst = {
175+ { & mmfr1 },
176+ { & pfr0 },
177+ { & pfr1 },
178+ { & isar1 },
179+ { & isar2 },
180+ { & smfr0 },
181+ { & sw_features },
170182};
171183
172184static const struct {
173185 char alias [FTR_ALIAS_NAME_LEN ];
174186 char feature [FTR_ALIAS_OPTION_LEN ];
175187} aliases [] __initconst = {
176- { "kvm-arm .mode=nvhe" , "id_aa64mmfr1.vh=0" },
177- { "kvm-arm .mode=protected" , "id_aa64mmfr1.vh=0" },
188+ { "kvm_arm .mode=nvhe" , "id_aa64mmfr1.vh=0" },
189+ { "kvm_arm .mode=protected" , "id_aa64mmfr1.vh=0" },
178190 { "arm64.nosve" , "id_aa64pfr0.sve=0" },
179191 { "arm64.nosme" , "id_aa64pfr1.sme=0" },
180192 { "arm64.nobti" , "id_aa64pfr1.bt=0" },
@@ -187,62 +199,78 @@ static const struct {
187199 { "nokaslr" , "arm64_sw.nokaslr=1" },
188200};
189201
190- static int __init parse_nokaslr ( char * unused )
202+ static int __init parse_hexdigit ( const char * p , u64 * v )
191203{
192- /* nokaslr param handling is done by early cpufeature code */
204+ // skip "0x" if it comes next
205+ if (p [0 ] == '0' && tolower (p [1 ]) == 'x' )
206+ p += 2 ;
207+
208+ // check whether the RHS is a single hex digit
209+ if (!isxdigit (p [0 ]) || (p [1 ] && !isspace (p [1 ])))
210+ return - EINVAL ;
211+
212+ * v = tolower (* p ) - (isdigit (* p ) ? '0' : 'a' - 10 );
193213 return 0 ;
194214}
195- early_param ("nokaslr" , parse_nokaslr );
196215
197- static int __init find_field (const char * cmdline ,
216+ static int __init find_field (const char * cmdline , char * opt , int len ,
198217 const struct ftr_set_desc * reg , int f , u64 * v )
199218{
200- char opt [FTR_DESC_NAME_LEN + FTR_DESC_FIELD_LEN + 2 ];
201- int len ;
219+ int flen = strlen (reg -> fields [f ].name );
202220
203- len = snprintf (opt , ARRAY_SIZE (opt ), "%s.%s=" ,
204- reg -> name , reg -> fields [f ].name );
221+ // append '<fieldname>=' to obtain '<name>.<fieldname>='
222+ memcpy (opt + len , reg -> fields [f ].name , flen );
223+ len += flen ;
224+ opt [len ++ ] = '=' ;
205225
206- if (! parameqn (cmdline , opt , len ))
226+ if (memcmp (cmdline , opt , len ))
207227 return -1 ;
208228
209- return kstrtou64 (cmdline + len , 0 , v );
229+ return parse_hexdigit (cmdline + len , v );
210230}
211231
212232static void __init match_options (const char * cmdline )
213233{
234+ char opt [FTR_DESC_NAME_LEN + FTR_DESC_FIELD_LEN + 2 ];
214235 int i ;
215236
216237 for (i = 0 ; i < ARRAY_SIZE (regs ); i ++ ) {
238+ const struct ftr_set_desc * reg = prel64_pointer (regs [i ].reg );
239+ struct arm64_ftr_override * override ;
240+ int len = strlen (reg -> name );
217241 int f ;
218242
219- if (!regs [i ]-> override )
220- continue ;
243+ override = prel64_pointer (reg -> override );
221244
222- for (f = 0 ; strlen (regs [i ]-> fields [f ].name ); f ++ ) {
223- u64 shift = regs [i ]-> fields [f ].shift ;
224- u64 width = regs [i ]-> fields [f ].width ?: 4 ;
245+ // set opt[] to '<name>.'
246+ memcpy (opt , reg -> name , len );
247+ opt [len ++ ] = '.' ;
248+
249+ for (f = 0 ; reg -> fields [f ].name [0 ] != '\0' ; f ++ ) {
250+ u64 shift = reg -> fields [f ].shift ;
251+ u64 width = reg -> fields [f ].width ?: 4 ;
225252 u64 mask = GENMASK_ULL (shift + width - 1 , shift );
253+ bool (* filter )(u64 val );
226254 u64 v ;
227255
228- if (find_field (cmdline , regs [ i ] , f , & v ))
256+ if (find_field (cmdline , opt , len , reg , f , & v ))
229257 continue ;
230258
231259 /*
232260 * If an override gets filtered out, advertise
233261 * it by setting the value to the all-ones while
234262 * clearing the mask... Yes, this is fragile.
235263 */
236- if ( regs [ i ] -> fields [f ].filter &&
237- ! regs [ i ] -> fields [ f ]. filter (v )) {
238- regs [ i ] -> override -> val |= mask ;
239- regs [ i ] -> override -> mask &= ~mask ;
264+ filter = prel64_pointer ( reg -> fields [f ].filter );
265+ if ( filter && ! filter (v )) {
266+ override -> val |= mask ;
267+ override -> mask &= ~mask ;
240268 continue ;
241269 }
242270
243- regs [ i ] -> override -> val &= ~mask ;
244- regs [ i ] -> override -> val |= (v << shift ) & mask ;
245- regs [ i ] -> override -> mask |= mask ;
271+ override -> val &= ~mask ;
272+ override -> val |= (v << shift ) & mask ;
273+ override -> mask |= mask ;
246274
247275 return ;
248276 }
@@ -258,23 +286,29 @@ static __init void __parse_cmdline(const char *cmdline, bool parse_aliases)
258286
259287 cmdline = skip_spaces (cmdline );
260288
261- for ( len = 0 ; cmdline [ len ] && ! isspace ( cmdline [ len ]); len ++ );
262- if (! len )
289+ /* terminate on "--" appearing on the command line by itself */
290+ if (cmdline [ 0 ] == '-' && cmdline [ 1 ] == '-' && isspace ( cmdline [ 2 ]) )
263291 return ;
264292
265- len = min (len , ARRAY_SIZE (buf ) - 1 );
266- memcpy (buf , cmdline , len );
267- buf [len ] = '\0' ;
268-
269- if (strcmp (buf , "--" ) == 0 )
293+ for (len = 0 ; cmdline [len ] && !isspace (cmdline [len ]); len ++ ) {
294+ if (len >= sizeof (buf ) - 1 )
295+ break ;
296+ if (cmdline [len ] == '-' )
297+ buf [len ] = '_' ;
298+ else
299+ buf [len ] = cmdline [len ];
300+ }
301+ if (!len )
270302 return ;
271303
304+ buf [len ] = 0 ;
305+
272306 cmdline += len ;
273307
274308 match_options (buf );
275309
276310 for (i = 0 ; parse_aliases && i < ARRAY_SIZE (aliases ); i ++ )
277- if (parameq (buf , aliases [i ].alias ))
311+ if (! memcmp (buf , aliases [i ].alias , len + 1 ))
278312 __parse_cmdline (aliases [i ].feature , false);
279313 } while (1 );
280314}
@@ -316,23 +350,26 @@ void init_feature_override(u64 boot_status);
316350
317351asmlinkage void __init init_feature_override (u64 boot_status )
318352{
353+ struct arm64_ftr_override * override ;
354+ const struct ftr_set_desc * reg ;
319355 int i ;
320356
321357 for (i = 0 ; i < ARRAY_SIZE (regs ); i ++ ) {
322- if (regs [i ]-> override ) {
323- regs [i ]-> override -> val = 0 ;
324- regs [i ]-> override -> mask = 0 ;
325- }
358+ reg = prel64_pointer (regs [i ].reg );
359+ override = prel64_pointer (reg -> override );
360+
361+ override -> val = 0 ;
362+ override -> mask = 0 ;
326363 }
327364
328365 __boot_status = boot_status ;
329366
330367 parse_cmdline ();
331368
332369 for (i = 0 ; i < ARRAY_SIZE (regs ); i ++ ) {
333- if (regs [i ]-> override )
334- dcache_clean_inval_poc (( unsigned long ) regs [ i ] -> override ,
335- ( unsigned long )regs [ i ] -> override +
336- sizeof ( * regs [ i ] -> override ));
370+ reg = prel64_pointer (regs [i ]. reg );
371+ override = prel64_pointer ( reg -> override );
372+ dcache_clean_inval_poc (( unsigned long )override ,
373+ ( unsigned long )( override + 1 ));
337374 }
338375}
0 commit comments