1/* 2 * Intel CPU Microcode Update Driver for Linux 3 * 4 * Copyright (C) 2012 Fenghua Yu <fenghua.yu@intel.com> 5 * H Peter Anvin" <hpa@zytor.com> 6 * 7 * This driver allows to upgrade microcode on Intel processors 8 * belonging to IA-32 family - PentiumPro, Pentium II, 9 * Pentium III, Xeon, Pentium 4, etc. 10 * 11 * Reference: Section 8.11 of Volume 3a, IA-32 Intel? Architecture 12 * Software Developer's Manual 13 * Order Number 253668 or free download from: 14 * 15 * http://developer.intel.com/Assets/PDF/manual/253668.pdf 16 * 17 * For more information, go to http://www.urbanmyth.org/microcode 18 * 19 * This program is free software; you can redistribute it and/or 20 * modify it under the terms of the GNU General Public License 21 * as published by the Free Software Foundation; either version 22 * 2 of the License, or (at your option) any later version. 23 * 24 */ 25#include <linux/firmware.h> 26#include <linux/uaccess.h> 27#include <linux/kernel.h> 28#include <linux/module.h> 29 30#include <asm/microcode_intel.h> 31#include <asm/processor.h> 32#include <asm/msr.h> 33 34static inline int 35update_match_cpu(unsigned int csig, unsigned int cpf, 36 unsigned int sig, unsigned int pf) 37{ 38 return (!sigmatch(sig, csig, pf, cpf)) ? 0 : 1; 39} 40 41int microcode_sanity_check(void *mc, int print_err) 42{ 43 unsigned long total_size, data_size, ext_table_size; 44 struct microcode_header_intel *mc_header = mc; 45 struct extended_sigtable *ext_header = NULL; 46 int sum, orig_sum, ext_sigcount = 0, i; 47 struct extended_signature *ext_sig; 48 49 total_size = get_totalsize(mc_header); 50 data_size = get_datasize(mc_header); 51 52 if (data_size + MC_HEADER_SIZE > total_size) { 53 if (print_err) 54 pr_err("error! Bad data size in microcode data file\n"); 55 return -EINVAL; 56 } 57 58 if (mc_header->ldrver != 1 || mc_header->hdrver != 1) { 59 if (print_err) 60 pr_err("error! Unknown microcode update format\n"); 61 return -EINVAL; 62 } 63 ext_table_size = total_size - (MC_HEADER_SIZE + data_size); 64 if (ext_table_size) { 65 if ((ext_table_size < EXT_HEADER_SIZE) 66 || ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) { 67 if (print_err) 68 pr_err("error! Small exttable size in microcode data file\n"); 69 return -EINVAL; 70 } 71 ext_header = mc + MC_HEADER_SIZE + data_size; 72 if (ext_table_size != exttable_size(ext_header)) { 73 if (print_err) 74 pr_err("error! Bad exttable size in microcode data file\n"); 75 return -EFAULT; 76 } 77 ext_sigcount = ext_header->count; 78 } 79 80 /* check extended table checksum */ 81 if (ext_table_size) { 82 int ext_table_sum = 0; 83 int *ext_tablep = (int *)ext_header; 84 85 i = ext_table_size / DWSIZE; 86 while (i--) 87 ext_table_sum += ext_tablep[i]; 88 if (ext_table_sum) { 89 if (print_err) 90 pr_warn("aborting, bad extended signature table checksum\n"); 91 return -EINVAL; 92 } 93 } 94 95 /* calculate the checksum */ 96 orig_sum = 0; 97 i = (MC_HEADER_SIZE + data_size) / DWSIZE; 98 while (i--) 99 orig_sum += ((int *)mc)[i]; 100 if (orig_sum) { 101 if (print_err) 102 pr_err("aborting, bad checksum\n"); 103 return -EINVAL; 104 } 105 if (!ext_table_size) 106 return 0; 107 /* check extended signature checksum */ 108 for (i = 0; i < ext_sigcount; i++) { 109 ext_sig = (void *)ext_header + EXT_HEADER_SIZE + 110 EXT_SIGNATURE_SIZE * i; 111 sum = orig_sum 112 - (mc_header->sig + mc_header->pf + mc_header->cksum) 113 + (ext_sig->sig + ext_sig->pf + ext_sig->cksum); 114 if (sum) { 115 if (print_err) 116 pr_err("aborting, bad checksum\n"); 117 return -EINVAL; 118 } 119 } 120 return 0; 121} 122EXPORT_SYMBOL_GPL(microcode_sanity_check); 123 124/* 125 * Returns 1 if update has been found, 0 otherwise. 126 */ 127int get_matching_sig(unsigned int csig, int cpf, int rev, void *mc) 128{ 129 struct microcode_header_intel *mc_header = mc; 130 struct extended_sigtable *ext_header; 131 unsigned long total_size = get_totalsize(mc_header); 132 int ext_sigcount, i; 133 struct extended_signature *ext_sig; 134 135 if (update_match_cpu(csig, cpf, mc_header->sig, mc_header->pf)) 136 return 1; 137 138 /* Look for ext. headers: */ 139 if (total_size <= get_datasize(mc_header) + MC_HEADER_SIZE) 140 return 0; 141 142 ext_header = mc + get_datasize(mc_header) + MC_HEADER_SIZE; 143 ext_sigcount = ext_header->count; 144 ext_sig = (void *)ext_header + EXT_HEADER_SIZE; 145 146 for (i = 0; i < ext_sigcount; i++) { 147 if (update_match_cpu(csig, cpf, ext_sig->sig, ext_sig->pf)) 148 return 1; 149 ext_sig++; 150 } 151 return 0; 152} 153 154/* 155 * Returns 1 if update has been found, 0 otherwise. 156 */ 157int get_matching_microcode(unsigned int csig, int cpf, int rev, void *mc) 158{ 159 struct microcode_header_intel *mc_hdr = mc; 160 161 if (!revision_is_newer(mc_hdr, rev)) 162 return 0; 163 164 return get_matching_sig(csig, cpf, rev, mc); 165} 166EXPORT_SYMBOL_GPL(get_matching_microcode); 167