2021-01-11 22:52:20 +00:00
// SPDX-License-Identifier: MIT
/*
* Copyright © 2021 Intel Corporation
*/
# include <linux/kernel.h>
# include <linux/moduleparam.h>
# include <linux/slab.h>
# include <linux/string.h>
2022-02-09 14:31:21 +02:00
# include "i915_driver.h"
2021-01-11 22:52:20 +00:00
# include "i915_drv.h"
# include "i915_mitigations.h"
static unsigned long mitigations __read_mostly = ~ 0UL ;
enum {
CLEAR_RESIDUALS = 0 ,
} ;
static const char * const names [ ] = {
[ CLEAR_RESIDUALS ] = " residuals " ,
} ;
bool i915_mitigate_clear_residuals ( void )
{
return READ_ONCE ( mitigations ) & BIT ( CLEAR_RESIDUALS ) ;
}
static int mitigations_set ( const char * val , const struct kernel_param * kp )
{
unsigned long new = ~ 0UL ;
char * str , * sep , * tok ;
bool first = true ;
int err = 0 ;
BUILD_BUG_ON ( ARRAY_SIZE ( names ) > = BITS_PER_TYPE ( mitigations ) ) ;
str = kstrdup ( val , GFP_KERNEL ) ;
if ( ! str )
return - ENOMEM ;
for ( sep = str ; ( tok = strsep ( & sep , " , " ) ) ; ) {
bool enable = true ;
int i ;
/* Be tolerant of leading/trailing whitespace */
tok = strim ( tok ) ;
if ( first ) {
first = false ;
if ( ! strcmp ( tok , " auto " ) )
continue ;
new = 0 ;
if ( ! strcmp ( tok , " off " ) )
continue ;
}
if ( * tok = = ' ! ' ) {
enable = ! enable ;
tok + + ;
}
if ( ! strncmp ( tok , " no " , 2 ) ) {
enable = ! enable ;
tok + = 2 ;
}
if ( * tok = = ' \0 ' )
continue ;
for ( i = 0 ; i < ARRAY_SIZE ( names ) ; i + + ) {
if ( ! strcmp ( tok , names [ i ] ) ) {
if ( enable )
new | = BIT ( i ) ;
else
new & = ~ BIT ( i ) ;
break ;
}
}
if ( i = = ARRAY_SIZE ( names ) ) {
pr_err ( " Bad \" %s.mitigations=%s \" , '%s' is unknown \n " ,
DRIVER_NAME , val , tok ) ;
err = - EINVAL ;
break ;
}
}
kfree ( str ) ;
if ( err )
return err ;
WRITE_ONCE ( mitigations , new ) ;
return 0 ;
}
static int mitigations_get ( char * buffer , const struct kernel_param * kp )
{
unsigned long local = READ_ONCE ( mitigations ) ;
int count , i ;
bool enable ;
if ( ! local )
return scnprintf ( buffer , PAGE_SIZE , " %s \n " , " off " ) ;
if ( local & BIT ( BITS_PER_LONG - 1 ) ) {
count = scnprintf ( buffer , PAGE_SIZE , " %s, " , " auto " ) ;
enable = false ;
} else {
enable = true ;
count = 0 ;
}
for ( i = 0 ; i < ARRAY_SIZE ( names ) ; i + + ) {
if ( ( local & BIT ( i ) ) ! = enable )
continue ;
count + = scnprintf ( buffer + count , PAGE_SIZE - count ,
" %s%s, " , enable ? " " : " ! " , names [ i ] ) ;
}
buffer [ count - 1 ] = ' \n ' ;
return count ;
}
static const struct kernel_param_ops ops = {
. set = mitigations_set ,
. get = mitigations_get ,
} ;
module_param_cb_unsafe ( mitigations , & ops , NULL , 0600 ) ;
MODULE_PARM_DESC ( mitigations ,
" Selectively enable security mitigations for all Intel® GPUs in the system. \n "
" \n "
" auto -- enables all mitigations required for the platform [default] \n "
" off -- disables all mitigations \n "
" \n "
" Individual mitigations can be enabled by passing a comma-separated string, \n "
" e.g. mitigations=residuals to enable only clearing residuals or \n "
" mitigations=auto,noresiduals to disable only the clear residual mitigation. \n "
" Either '!' or 'no' may be used to switch from enabling the mitigation to \n "
" disabling it. \n "
" \n "
" Active mitigations for Ivybridge, Baytrail, Haswell: \n "
" residuals -- clear all thread-local registers between contexts "
) ;