@ -39,27 +39,10 @@
# include <asm/setup.h>
# include <asm/msr.h>
/*
* Temporary microcode blobs pointers storage . We note here during early load
* the pointers to microcode blobs we ' ve got from whatever storage ( detached
* initrd , builtin ) . Later on , we put those into final storage
* mc_saved_data . mc_saved .
*
* Important : those are offsets from the beginning of initrd or absolute
* addresses within the kernel image when built - in .
*/
static unsigned long mc_tmp_ptrs [ MAX_UCODE_COUNT ] ;
static struct mc_saved_data {
unsigned int num_saved ;
struct microcode_intel * * mc_saved ;
} mc_saved_data ;
static const char ucode_path [ ] = " kernel/x86/microcode/GenuineIntel.bin " ;
/* Microcode blobs within the initrd. 0 if builtin. */
static struct ucode_blobs {
unsigned long start ;
bool valid ;
} blobs ;
/* Current microcode patch used in early patching */
struct microcode_intel * intel_ucode_patch ;
static inline bool cpu_signatures_match ( unsigned int s1 , unsigned int p1 ,
unsigned int s2 , unsigned int p2 )
@ -116,103 +99,23 @@ static int has_newer_microcode(void *mc, unsigned int csig, int cpf, int new_rev
return find_matching_signature ( mc , csig , cpf ) ;
}
/* Go through saved patches and find the one suitable for the current CPU. */
static enum ucode_state
find_microcode_patch ( struct microcode_intel * * saved ,
unsigned int num_saved , struct ucode_cpu_info * uci )
{
struct microcode_intel * ucode_ptr , * new_mc = NULL ;
struct microcode_header_intel * mc_hdr ;
int new_rev , ret , i ;
new_rev = uci - > cpu_sig . rev ;
for ( i = 0 ; i < num_saved ; i + + ) {
ucode_ptr = saved [ i ] ;
mc_hdr = ( struct microcode_header_intel * ) ucode_ptr ;
ret = has_newer_microcode ( ucode_ptr ,
uci - > cpu_sig . sig ,
uci - > cpu_sig . pf ,
new_rev ) ;
if ( ! ret )
continue ;
new_rev = mc_hdr - > rev ;
new_mc = ucode_ptr ;
}
if ( ! new_mc )
return UCODE_NFOUND ;
uci - > mc = ( struct microcode_intel * ) new_mc ;
return UCODE_OK ;
}
static inline void
copy_ptrs ( struct microcode_intel * * mc_saved , unsigned long * mc_ptrs ,
unsigned long off , int num_saved )
{
int i ;
for ( i = 0 ; i < num_saved ; i + + )
mc_saved [ i ] = ( struct microcode_intel * ) ( mc_ptrs [ i ] + off ) ;
}
# ifdef CONFIG_X86_32
static void
microcode_phys ( struct microcode_intel * * mc_saved_tmp , struct mc_saved_data * mcs )
{
int i ;
struct microcode_intel * * * mc_saved ;
mc_saved = ( struct microcode_intel * * * ) __pa_nodebug ( & mcs - > mc_saved ) ;
for ( i = 0 ; i < mcs - > num_saved ; i + + ) {
struct microcode_intel * p ;
p = * ( struct microcode_intel * * ) __pa_nodebug ( mcs - > mc_saved + i ) ;
mc_saved_tmp [ i ] = ( struct microcode_intel * ) __pa_nodebug ( p ) ;
}
}
# endif
static enum ucode_state
load_microcode ( struct mc_saved_data * mcs , unsigned long * mc_ptrs ,
unsigned long offset , struct ucode_cpu_info * uci )
{
struct microcode_intel * mc_saved_tmp [ MAX_UCODE_COUNT ] ;
unsigned int count = mcs - > num_saved ;
if ( ! mcs - > mc_saved ) {
copy_ptrs ( mc_saved_tmp , mc_ptrs , offset , count ) ;
return find_microcode_patch ( mc_saved_tmp , count , uci ) ;
} else {
# ifdef CONFIG_X86_32
microcode_phys ( mc_saved_tmp , mcs ) ;
return find_microcode_patch ( mc_saved_tmp , count , uci ) ;
# else
return find_microcode_patch ( mcs - > mc_saved , count , uci ) ;
# endif
}
}
/*
* Given CPU signature and a microcode patch , this function finds if the
* microcode patch has matching family and model with the CPU .
*
* % true - if there ' s a match
* % false - otherwise
*/
static enum ucode_state
matching_model_microcode ( struct microcode_header_intel * mc_header ,
unsigned long sig )
static bool microcode_matches ( struct microcode_header_intel * mc_header ,
unsigned long sig )
{
unsigned int fam , model ;
unsigned int fam_ucode , model_ucode ;
struct extended_sigtable * ext_header ;
unsigned long total_size = get_totalsize ( mc_header ) ;
unsigned long data_size = get_datasize ( mc_header ) ;
int ext_sigcount , i ;
struct extended_sigtable * ext_header ;
unsigned int fam_ucode , model_ucode ;
struct extended_signature * ext_sig ;
unsigned int fam , model ;
int ext_sigcount , i ;
fam = x86_family ( sig ) ;
model = x86_model ( sig ) ;
@ -221,11 +124,11 @@ matching_model_microcode(struct microcode_header_intel *mc_header,
model_ucode = x86_model ( mc_header - > sig ) ;
if ( fam = = fam_ucode & & model = = model_ucode )
return UCODE_OK ;
return true ;
/* Look for ext. headers: */
if ( total_size < = data_size + MC_HEADER_SIZE )
return UCODE_NFOUND ;
return false ;
ext_header = ( void * ) mc_header + data_size + MC_HEADER_SIZE ;
ext_sig = ( void * ) ext_header + EXT_HEADER_SIZE ;
@ -236,114 +139,69 @@ matching_model_microcode(struct microcode_header_intel *mc_header,
model_ucode = x86_model ( ext_sig - > sig ) ;
if ( fam = = fam_ucode & & model = = model_ucode )
return UCODE_OK ;
return true ;
ext_sig + + ;
}
return UCODE_NFOUND ;
return false ;
}
static int
save_microcode ( struct mc_saved_data * mcs ,
struct microcode_intel * * mc_saved_src ,
unsigned int num_saved )
static struct ucode_patch * __alloc_microcode_buf ( void * data , unsigned int size )
{
int i , j ;
struct microcode_intel * * saved_ptr ;
int ret ;
if ( ! num_saved )
return - EINVAL ;
/*
* Copy new microcode data .
*/
saved_ptr = kcalloc ( num_saved , sizeof ( struct microcode_intel * ) , GFP_KERNEL ) ;
if ( ! saved_ptr )
return - ENOMEM ;
for ( i = 0 ; i < num_saved ; i + + ) {
struct microcode_header_intel * mc_hdr ;
struct microcode_intel * mc ;
unsigned long size ;
if ( ! mc_saved_src [ i ] ) {
ret = - EINVAL ;
goto err ;
}
struct ucode_patch * p ;
mc = mc_saved_src [ i ] ;
mc_hdr = & mc - > hdr ;
size = get_totalsize ( mc_hdr ) ;
p = kzalloc ( size , GFP_KERNEL ) ;
if ( ! p )
return ERR_PTR ( - ENOMEM ) ;
saved_ptr [ i ] = kmemdup ( mc , size , GFP_KERNEL ) ;
if ( ! saved_ptr [ i ] ) {
ret = - ENOMEM ;
goto err ;
}
p - > data = kmemdup ( data , size , GFP_KERNEL ) ;
if ( ! p - > data ) {
kfree ( p ) ;
return ERR_PTR ( - ENOMEM ) ;
}
/*
* Point to newly saved microcode .
*/
mcs - > mc_saved = saved_ptr ;
mcs - > num_saved = num_saved ;
return 0 ;
err :
for ( j = 0 ; j < = i ; j + + )
kfree ( saved_ptr [ j ] ) ;
kfree ( saved_ptr ) ;
return ret ;
return p ;
}
/*
* A microcode patch in ucode_ptr is saved into mc_saved
* - if it has matching signature and newer revision compared to an existing
* patch mc_saved .
* - or if it is a newly discovered microcode patch .
*
* The microcode patch should have matching model with CPU .
*
* Returns : The updated number @ num_saved of saved microcode patches .
*/
static unsigned int _save_mc ( struct microcode_intel * * mc_saved ,
u8 * ucode_ptr , unsigned int num_saved )
static void save_microcode_patch ( void * data , unsigned int size )
{
struct microcode_header_intel * mc_hdr , * mc_saved_hdr ;
struct ucode_patch * iter , * tmp , * p ;
bool prev_found = false ;
unsigned int sig , pf ;
int found = 0 , i ;
mc_hdr = ( struct microcode_header_intel * ) ucode_ptr ;
mc_hdr = ( struct microcode_header_intel * ) data ;
for ( i = 0 ; i < num_saved ; i + + ) {
mc_saved_hdr = ( struct microcode_header_intel * ) mc_saved [ i ] ;
list_for_each_entry_safe ( iter , tmp , & microcode_cache , plist ) {
mc_saved_hdr = ( struct microcode_header_intel * ) iter - > data ;
sig = mc_saved_hdr - > sig ;
pf = mc_saved_hdr - > pf ;
if ( ! find_matching_signature ( ucode_ptr , sig , pf ) )
continue ;
found = 1 ;
if ( find_matching_signature ( data , sig , pf ) ) {
prev_found = true ;
if ( mc_hdr - > rev < = mc_saved_hdr - > rev )
continue ;
if ( mc_hdr - > rev < = mc_saved_hdr - > rev )
continue ;
/*
* Found an older ucode saved earlier . Replace it with
* this newer one .
*/
mc_saved [ i ] = ( struct microcode_intel * ) ucode_ptr ;
break ;
p = __alloc_microcode_buf ( data , size ) ;
if ( IS_ERR ( p ) )
pr_err ( " Error allocating buffer %p \n " , data ) ;
else
list_replace ( & iter - > plist , & p - > plist ) ;
}
}
/* Newly detected microcode, save it to memory. */
if ( i > = num_saved & & ! found )
mc_saved [ num_saved + + ] = ( struct microcode_intel * ) ucode_ptr ;
return num_saved ;
/*
* There weren ' t any previous patches found in the list cache ; save the
* newly found .
*/
if ( ! prev_found ) {
p = __alloc_microcode_buf ( data , size ) ;
if ( IS_ERR ( p ) )
pr_err ( " Error allocating buffer for %p \n " , data ) ;
else
list_add_tail ( & p - > plist , & microcode_cache ) ;
}
}
static int microcode_sanity_check ( void * mc , int print_err )
@ -448,78 +306,75 @@ static int microcode_sanity_check(void *mc, int print_err)
* Get microcode matching with BSP ' s model . Only CPUs with the same model as
* BSP can stay in the platform .
*/
static enum ucode_state __init
get_matching_model_microcode ( unsigned long start , void * data , size_t size ,
struct mc_saved_data * mcs , unsigned long * mc_ptrs ,
struct ucode_cpu_info * uci )
static struct microcode_intel *
scan_microcode ( void * data , size_t size , struct ucode_cpu_info * uci , bool save )
{
struct microcode_intel * mc_saved_tmp [ MAX_UCODE_COUNT ] ;
struct microcode_header_intel * mc_header ;
unsigned int num_saved = mcs - > num_saved ;
enum ucode_state state = UCODE_OK ;
unsigned int leftover = size ;
u8 * ucode_ptr = data ;
struct microcode_intel * patch = NULL ;
unsigned int mc_size ;
int i ;
while ( leftover & & num_saved < ARRAY_SIZE ( mc_saved_tmp ) ) {
if ( leftover < sizeof ( mc_header ) )
while ( size ) {
if ( size < sizeof ( struct microcode_header_intel ) )
break ;
mc_header = ( struct microcode_header_intel * ) ucode_ptr ;
mc_header = ( struct microcode_header_intel * ) data ;
mc_size = get_totalsize ( mc_header ) ;
if ( ! mc_size | | mc_size > leftover | |
microcode_sanity_check ( ucode_ptr , 0 ) < 0 )
if ( ! mc_size | |
mc_size > size | |
microcode_sanity_check ( data , 0 ) < 0 )
break ;
leftover - = mc_size ;
size - = mc_size ;
/*
* Since APs with same family and model as the BSP may boot in
* the platform , we need to find and save microcode patches
* with the same family and model as the BSP .
*/
if ( matching_model_microcode ( mc_header , uci - > cpu_sig . sig ) ! = UCODE_OK ) {
ucode_ptr + = mc_size ;
if ( ! microcode_matches ( mc_header , uci - > cpu_sig . sig ) ) {
data + = mc_size ;
continue ;
}
num_saved = _save_mc ( mc_saved_tmp , ucode_ptr , num_saved ) ;
if ( save ) {
save_microcode_patch ( data , mc_size ) ;
goto next ;
}
ucode_ptr + = mc_size ;
}
if ( leftover ) {
state = UCODE_ERROR ;
return state ;
}
if ( ! patch ) {
if ( ! has_newer_microcode ( data ,
uci - > cpu_sig . sig ,
uci - > cpu_sig . pf ,
uci - > cpu_sig . rev ) )
goto next ;
if ( ! num_saved ) {
state = UCODE_NFOUND ;
return state ;
}
} else {
struct microcode_header_intel * phdr = & patch - > hdr ;
if ( ! has_newer_microcode ( data ,
phdr - > sig ,
phdr - > pf ,
phdr - > rev ) )
goto next ;
}
for ( i = 0 ; i < num_saved ; i + + )
mc_ptrs [ i ] = ( unsigned long ) mc_saved_tmp [ i ] - start ;
/* We have a newer patch, save it. */
patch = data ;
mcs - > num_saved = num_saved ;
next :
data + = mc_size ;
}
return state ;
if ( size )
return NULL ;
return patch ;
}
static int collect_cpu_info_early ( struct ucode_cpu_info * uci )
{
unsigned int val [ 2 ] ;
unsigned int family , model ;
struct cpu_signature csig ;
struct cpu_signature csig = { 0 } ;
unsigned int eax , ebx , ecx , edx ;
csig . sig = 0 ;
csig . pf = 0 ;
csig . rev = 0 ;
memset ( uci , 0 , sizeof ( * uci ) ) ;
eax = 0x00000001 ;
@ -527,8 +382,8 @@ static int collect_cpu_info_early(struct ucode_cpu_info *uci)
native_cpuid ( & eax , & ebx , & ecx , & edx ) ;
csig . sig = eax ;
family = x86_family ( csig . sig ) ;
model = x86_model ( csig . sig ) ;
family = x86_family ( eax ) ;
model = x86_model ( eax ) ;
if ( ( model > = 5 ) | | ( family > 6 ) ) {
/* get processor flags from MSR 0x17 */
@ -554,40 +409,41 @@ static int collect_cpu_info_early(struct ucode_cpu_info *uci)
static void show_saved_mc ( void )
{
# ifdef DEBUG
int i , j ;
int i = 0 , j ;
unsigned int sig , pf , rev , total_size , data_size , date ;
struct ucode_cpu_info uci ;
struct ucode_patch * p ;
if ( ! mc_saved_data . num_saved ) {
if ( list_empty ( & microcode_cache ) ) {
pr_debug ( " no microcode data saved. \n " ) ;
return ;
}
pr_debug ( " Total microcode saved: %d \n " , mc_saved_data . num_saved ) ;
collect_cpu_info_early ( & uci ) ;
sig = uci . cpu_sig . sig ;
pf = uci . cpu_sig . pf ;
rev = uci . cpu_sig . rev ;
sig = uci . cpu_sig . sig ;
pf = uci . cpu_sig . pf ;
rev = uci . cpu_sig . rev ;
pr_debug ( " CPU: sig=0x%x, pf=0x%x, rev=0x%x \n " , sig , pf , rev ) ;
for ( i = 0 ; i < mc_saved_data . num_saved ; i + + ) {
list_for_each_entry ( p , & microcode_cache , plist ) {
struct microcode_header_intel * mc_saved_header ;
struct extended_sigtable * ext_header ;
int ext_sigcount ;
struct extended_signature * ext_sig ;
int ext_sigcount ;
mc_saved_header = ( struct microcode_header_intel * ) p - > data ;
sig = mc_saved_header - > sig ;
pf = mc_saved_header - > pf ;
rev = mc_saved_header - > rev ;
date = mc_saved_header - > date ;
mc_saved_header = ( struct microcode_header_intel * )
mc_saved_data . mc_saved [ i ] ;
sig = mc_saved_header - > sig ;
pf = mc_saved_header - > pf ;
rev = mc_saved_header - > rev ;
total_size = get_totalsize ( mc_saved_header ) ;
data_size = get_datasize ( mc_saved_header ) ;
date = mc_saved_header - > date ;
total_size = get_totalsize ( mc_saved_header ) ;
data_size = get_datasize ( mc_saved_header ) ;
pr_debug ( " mc_saved[%d]: sig=0x%x, pf=0x%x, rev=0x%x, total size=0x%x, date = %04x-%02x-%02x \n " ,
i , sig , pf , rev , total_size ,
i + + , sig , pf , rev , total_size ,
date & 0xffff ,
date > > 24 ,
( date > > 16 ) & 0xff ) ;
@ -596,7 +452,7 @@ static void show_saved_mc(void)
if ( total_size < = data_size + MC_HEADER_SIZE )
continue ;
ext_header = ( void * ) mc_saved_header + data_size + MC_HEADER_SIZE ;
ext_header = ( void * ) mc_saved_header + data_size + MC_HEADER_SIZE ;
ext_sigcount = ext_header - > count ;
ext_sig = ( void * ) ext_header + EXT_HEADER_SIZE ;
@ -609,85 +465,43 @@ static void show_saved_mc(void)
ext_sig + + ;
}
}
# endif
}
/*
* Save this mc into mc_saved_data . So it will be loaded early when a CPU is
* hot added or resumes .
*
* Please make sure this mc should be a valid microcode patch before calling
* this function .
* Save this microcode patch . It will be loaded early when a CPU is
* hot - added or resumes .
*/
static void save_mc_for_early ( u8 * mc )
static void save_mc_for_early ( u8 * mc , unsigned int size )
{
# ifdef CONFIG_HOTPLUG_CPU
/* Synchronization during CPU hotplug. */
static DEFINE_MUTEX ( x86_cpu_microcode_mutex ) ;
struct microcode_intel * mc_saved_tmp [ MAX_UCODE_COUNT ] ;
unsigned int mc_saved_count_init ;
unsigned int num_saved ;
struct microcode_intel * * mc_saved ;
int ret , i ;
mutex_lock ( & x86_cpu_microcode_mutex ) ;
mc_saved_count_init = mc_saved_data . num_saved ;
num_saved = mc_saved_data . num_saved ;
mc_saved = mc_saved_data . mc_saved ;
if ( mc_saved & & num_saved )
memcpy ( mc_saved_tmp , mc_saved ,
num_saved * sizeof ( struct microcode_intel * ) ) ;
/*
* Save the microcode patch mc in mc_save_tmp structure if it ' s a newer
* version .
*/
num_saved = _save_mc ( mc_saved_tmp , mc , num_saved ) ;
/*
* Save the mc_save_tmp in global mc_saved_data .
*/
ret = save_microcode ( & mc_saved_data , mc_saved_tmp , num_saved ) ;
if ( ret ) {
pr_err ( " Cannot save microcode patch. \n " ) ;
goto out ;
}
save_microcode_patch ( mc , size ) ;
show_saved_mc ( ) ;
/*
* Free old saved microcode data .
*/
if ( mc_saved ) {
for ( i = 0 ; i < mc_saved_count_init ; i + + )
kfree ( mc_saved [ i ] ) ;
kfree ( mc_saved ) ;
}
out :
mutex_unlock ( & x86_cpu_microcode_mutex ) ;
# endif
}
static bool __init load_builtin_intel_microcode ( struct cpio_data * cp )
static bool load_builtin_intel_microcode ( struct cpio_data * cp )
{
# ifdef CONFIG_X86_64
unsigned int eax = 0x00000001 , ebx , ecx = 0 , edx ;
unsigned int eax = 1 , ebx , ecx = 0 , edx ;
char name [ 30 ] ;
if ( IS_ENABLED ( CONFIG_X86_32 ) )
return false ;
native_cpuid ( & eax , & ebx , & ecx , & edx ) ;
sprintf ( name , " intel-ucode/%02x-%02x-%02x " ,
x86_family ( eax ) , x86_model ( eax ) , x86_stepping ( eax ) ) ;
return get_builtin_firmware ( cp , name ) ;
# else
return false ;
# endif
}
/*
@ -723,8 +537,7 @@ void show_ucode_info_early(void)
}
/*
* At this point , we can not call printk ( ) yet . Keep microcode patch number in
* mc_saved_data . mc_saved and delay printing microcode info in
* At this point , we can not call printk ( ) yet . Delay printing microcode info in
* show_ucode_info_early ( ) until printk ( ) works .
*/
static void print_ucode ( struct ucode_cpu_info * uci )
@ -801,206 +614,140 @@ static int apply_microcode_early(struct ucode_cpu_info *uci, bool early)
return 0 ;
}
/*
* This function converts microcode patch offsets previously stored in
* mc_tmp_ptrs to pointers and stores the pointers in mc_saved_data .
*/
int __init save_microcode_in_initrd_intel ( void )
{
struct microcode_intel * mc_saved [ MAX_UCODE_COUNT ] ;
unsigned int count = mc_saved_data . num_saved ;
unsigned long offset = 0 ;
int ret ;
if ( ! count )
return 0 ;
struct ucode_cpu_info uci ;
struct cpio_data cp ;
/*
* We have found a valid initrd but it might ' ve been relocated in the
* meantime so get its updated address .
* AP loading didn ' t find any microcode patch , no need to save anything .
*/
if ( IS_ENABLED ( CONFIG_BLK_DEV_INITRD ) & & blobs . valid )
offset = initrd_start ;
copy_ptrs ( mc_saved , mc_tmp_ptrs , offset , count ) ;
if ( ! intel_ucode_patch | | IS_ERR ( intel_ucode_patch ) )
return 0 ;
ret = save_microcode ( & mc_saved_data , mc_saved , count ) ;
if ( ret )
pr_err ( " Cannot save microcode patches from initrd. \n " ) ;
else
show_saved_mc ( ) ;
if ( ! load_builtin_intel_microcode ( & cp ) )
cp = find_microcode_in_initrd ( ucode_path , false ) ;
return ret ;
}
if ( ! ( cp . data & & cp . size ) )
return 0 ;
static __init enum ucode_state
__scan_microcode_initrd ( struct cpio_data * cd , struct ucode_blobs * blbp )
{
# ifdef CONFIG_BLK_DEV_INITRD
static __initdata char ucode_name [ ] = " kernel/x86/microcode/GenuineIntel.bin " ;
char * p = IS_ENABLED ( CONFIG_X86_32 ) ? ( char * ) __pa_nodebug ( ucode_name )
: ucode_name ;
# ifdef CONFIG_X86_32
unsigned long start = 0 , size ;
struct boot_params * params ;
collect_cpu_info_early ( & uci ) ;
params = ( struct boot_params * ) __pa_nodebug ( & boot_params ) ;
size = params - > hdr . ramdisk_size ;
scan_microcode ( cp . data , cp . size , & uci , true ) ;
/*
* Set start only if we have an initrd image . We cannot use initrd_start
* because it is not set that early yet .
*/
start = ( size ? params - > hdr . ramdisk_image : 0 ) ;
show_saved_mc ( ) ;
# else /* CONFIG_X86_64 */
unsigned long start = 0 , size ;
return 0 ;
}
size = ( u64 ) boot_params . ext_ramdisk_size < < 32 ;
size | = boot_params . hdr . ramdisk_size ;
if ( size ) {
start = ( u64 ) boot_params . ext_ramdisk_image < < 32 ;
start | = boot_params . hdr . ramdisk_image ;
/*
* @ res_patch , output : a pointer to the patch we found .
*/
static struct microcode_intel * __load_ucode_intel ( struct ucode_cpu_info * uci )
{
static const char * path ;
struct cpio_data cp ;
bool use_pa ;
start + = PAGE_OFFSET ;
if ( IS_ENABLED ( CONFIG_X86_32 ) ) {
path = ( const char * ) __pa_nodebug ( ucode_path ) ;
use_pa = true ;
} else {
path = ucode_path ;
use_pa = false ;
}
# endif
* cd = find_cpio_data ( p , ( void * ) start , size , NULL ) ;
if ( cd - > data ) {
blbp - > start = start ;
blbp - > valid = true ;
return UCODE_OK ;
} else
# endif /* CONFIG_BLK_DEV_INITRD */
return UCODE_ERROR ;
}
/* try built-in microcode first */
if ( ! load_builtin_intel_microcode ( & cp ) )
cp = find_microcode_in_initrd ( path , use_pa ) ;
static __init enum ucode_state
scan_microcode ( struct mc_saved_data * mcs , unsigned long * mc_ptrs ,
struct ucode_cpu_info * uci , struct ucode_blobs * blbp )
{
struct cpio_data cd = { NULL , 0 , " " } ;
enum ucode_state ret ;
if ( ! ( cp . data & & cp . size ) )
return NULL ;
/* try built-in microcode first */
if ( load_builtin_intel_microcode ( & cd ) )
/*
* Invalidate blobs as we might ' ve gotten an initrd too ,
* supplied by the boot loader , by mistake or simply forgotten
* there . That ' s fine , we ignore it since we ' ve found builtin
* microcode already .
*/
blbp - > valid = false ;
else {
ret = __scan_microcode_initrd ( & cd , blbp ) ;
if ( ret ! = UCODE_OK )
return ret ;
}
collect_cpu_info_early ( uci ) ;
return get_matching_model_microcode ( blbp - > start , cd . data , cd . size ,
mcs , mc_ptrs , uci ) ;
return scan_microcode ( cp . data , cp . size , uci , false ) ;
}
static void __init
_load_ucode_intel_bsp ( struct mc_saved_data * mcs , unsigned long * mc_ptrs ,
struct ucode_blobs * blbp )
void __init load_ucode_intel_bsp ( void )
{
struct microcode_intel * patch ;
struct ucode_cpu_info uci ;
enum ucode_state ret ;
collect_cpu_info_early ( & uci ) ;
ret = scan_microcode ( mcs , mc_ptrs , & uci , blbp ) ;
if ( ret ! = UCODE_OK )
patch = __load_ucode_intel ( & uci ) ;
if ( ! patch )
return ;
ret = load_microcode ( mcs , mc_ptrs , blbp - > start , & uci ) ;
if ( ret ! = UCODE_OK )
return ;
uci . mc = patch ;
apply_microcode_early ( & uci , true ) ;
}
void __init load_ucode_intel_bs p( void )
void load_ucode_intel_a p( void )
{
struct ucode_blobs * blobs_p ;
struct mc_saved_data * mcs ;
unsigned long * ptrs ;
struct microcode_intel * patch , * * iup ;
struct ucode_cpu_info uci ;
# ifdef CONFIG_X86_32
mcs = ( struct mc_saved_data * ) __pa_nodebug ( & mc_saved_data ) ;
ptrs = ( unsigned long * ) __pa_nodebug ( & mc_tmp_ptrs ) ;
blobs_p = ( struct ucode_blobs * ) __pa_nodebug ( & blobs ) ;
# else
mcs = & mc_saved_data ;
ptrs = mc_tmp_ptrs ;
blobs_p = & blobs ;
# endif
if ( IS_ENABLED ( CONFIG_X86_32 ) )
iup = ( struct microcode_intel * * ) __pa_nodebug ( & intel_ucode_patch ) ;
else
iup = & intel_ucode_patch ;
reget :
if ( ! * iup ) {
patch = __load_ucode_intel ( & uci ) ;
if ( ! patch )
return ;
_load_ucode_intel_bsp ( mcs , ptrs , blobs_p ) ;
* iup = patch ;
}
uci . mc = * iup ;
if ( apply_microcode_early ( & uci , true ) ) {
/* Mixed-silicon system? Try to refetch the proper patch: */
* iup = NULL ;
goto reget ;
}
}
void load_ucode_intel_ap ( void )
static struct microcode_intel * find_patch ( struct ucode_cpu_info * uci )
{
struct ucode_blobs * blobs_p ;
unsigned long * ptrs , start = 0 ;
struct mc_saved_data * mcs ;
struct ucode_cpu_info uci ;
enum ucode_state ret ;
struct microcode_header_intel * phdr ;
struct ucode_patch * iter , * tmp ;
# ifdef CONFIG_X86_32
mcs = ( struct mc_saved_data * ) __pa_nodebug ( & mc_saved_data ) ;
ptrs = ( unsigned long * ) __pa_nodebug ( mc_tmp_ptrs ) ;
blobs_p = ( struct ucode_blobs * ) __pa_nodebug ( & blobs ) ;
# else
mcs = & mc_saved_data ;
ptrs = mc_tmp_ptrs ;
blobs_p = & blobs ;
# endif
/*
* If there is no valid ucode previously saved in memory , no need to
* update ucode on this AP .
*/
if ( ! mcs - > num_saved )
return ;
list_for_each_entry_safe ( iter , tmp , & microcode_cache , plist ) {
if ( blobs_p - > valid ) {
start = blobs_p - > start ;
phdr = ( struct microcode_header_intel * ) iter - > data ;
/*
* Pay attention to CONFIG_RANDOMIZE_MEMORY = y as it shuffles
* physmem mapping too and there we have the initrd .
*/
start + = PAGE_OFFSET - __PAGE_OFFSET_BASE ;
}
if ( phdr - > rev < = uci - > cpu_sig . rev )
continue ;
collect_cpu_info_early ( & uci ) ;
ret = load_microcode ( mcs , ptrs , start , & uci ) ;
if ( ret ! = UCODE_OK )
return ;
if ( ! find_matching_signature ( phdr ,
uci - > cpu_sig . sig ,
uci - > cpu_sig . pf ) )
continue ;
apply_microcode_early ( & uci , true ) ;
return iter - > data ;
}
return NULL ;
}
void reload_ucode_intel ( void )
{
struct microcode_intel * p ;
struct ucode_cpu_info uci ;
enum ucode_state ret ;
if ( ! mc_saved_data . num_saved )
return ;
collect_cpu_info_early ( & uci ) ;
ret = find_microcode_patch ( mc_saved_data . mc_saved ,
mc_saved_data . num_saved , & uci ) ;
if ( ret ! = UCODE_OK )
p = find_patch ( & uci ) ;
if ( ! p )
return ;
uci . mc = p ;
apply_microcode_early ( & uci , false ) ;
}
@ -1032,24 +779,6 @@ static int collect_cpu_info(int cpu_num, struct cpu_signature *csig)
return 0 ;
}
/*
* return 0 - no update found
* return 1 - found update
*/
static int get_matching_mc ( struct microcode_intel * mc , int cpu )
{
struct cpu_signature cpu_sig ;
unsigned int csig , cpf , crev ;
collect_cpu_info ( cpu , & cpu_sig ) ;
csig = cpu_sig . sig ;
cpf = cpu_sig . pf ;
crev = cpu_sig . rev ;
return has_newer_microcode ( mc , csig , cpf , crev ) ;
}
static int apply_microcode_intel ( int cpu )
{
struct microcode_intel * mc ;
@ -1064,16 +793,12 @@ static int apply_microcode_intel(int cpu)
uci = ucode_cpu_info + cpu ;
mc = uci - > mc ;
if ( ! mc )
return 0 ;
/*
* Microcode on this CPU could be updated earlier . Only apply the
* microcode patch in mc when it is newer than the one on this
* CPU .
*/
if ( ! get_matching_mc ( mc , cpu ) )
return 0 ;
if ( ! mc ) {
/* Look for a newer patch in our cache: */
mc = find_patch ( uci ) ;
if ( ! mc )
return 0 ;
}
/* write microcode via MSR 0x79 */
wrmsrl ( MSR_IA32_UCODE_WRITE , ( unsigned long ) mc - > bits ) ;
@ -1181,7 +906,7 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size,
* permanent memory . So it will be loaded early when a CPU is hot added
* or resumes .
*/
save_mc_for_early ( new_mc ) ;
save_mc_for_early ( new_mc , curr_mc_size ) ;
pr_debug ( " CPU%d found a matching microcode update with version 0x%x (current=0x%x) \n " ,
cpu , new_rev , uci - > cpu_sig . rev ) ;
@ -1230,20 +955,11 @@ request_microcode_user(int cpu, const void __user *buf, size_t size)
return generic_load_microcode ( cpu , ( void * ) buf , size , & get_ucode_user ) ;
}
static void microcode_fini_cpu ( int cpu )
{
struct ucode_cpu_info * uci = ucode_cpu_info + cpu ;
vfree ( uci - > mc ) ;
uci - > mc = NULL ;
}
static struct microcode_ops microcode_intel_ops = {
. request_microcode_user = request_microcode_user ,
. request_microcode_fw = request_microcode_fw ,
. collect_cpu_info = collect_cpu_info ,
. apply_microcode = apply_microcode_intel ,
. microcode_fini_cpu = microcode_fini_cpu ,
} ;
struct microcode_ops * __init init_intel_microcode ( void )