Translate

Archives

Utilities for Parsing Intel Microcode

A recent issue on a Linux platform with an Intel CPU prompted me to check to see if there was a microcode patch available from Intel to fix the issue. This blog post provides the source code for some of the Python utilities I wrote to assist me in determining if a microcode update was available for my particular issue or not.

Intel distributes microcode updates in the form of a text file consisting of groups of big endian 32-bit integers represented as hexadecimals. As an example, here is a portion of one such file:

/*  Fri Nov 4 16:09:13 CST 2016  */
/*  m02f0a15.inc  */
0x00000001,	0x00000015,	0x08212002,	0x00000f0a,
0x63e49a0c,	0x00000001,	0x00000002,	0x00000000,
0x00000000,	0x00000000,	0x00000000,	0x00000000,
0xffffffe9,	0x80e0e61a,	0x7cb2c607,	0xbe1e2fc9,
0xacaf1526,	0x31514e28,	0x9252d426,	0xb999ebf8,
0x8469bb8a,	0x95e72fd2,	0x5f7c5472,	0x254adcf0,
0xf706b236,	0x21ef3efb,	0x82d05526,	0x8b10bd77,
0x268ab8bd,	0x929739a5,	0x0f180e02,	0x3ad1cc5a,
0x23a10814,	0xbc4257f8,	0x026ded8d,	0x84bf45be,
0xe13e69f3,	0xbb0edf16,	0x85218fd2,	0x898af4e1,
0xcd635f26,	0x846ab0c6,	0x85a5d5cd,	0x077b4a16,
0x71514de0,	0xbff893a6,	0x47536ab0,	0x1fc4b546,
0x906f4b85,	0xc1f997d5,	0x0ba4b594,	0xa823eb50,


The first 16 integers (48 bytes) represent a standard microcode header which is fully documented in Section 9.11 (Microcode Update Facilities) of the Intel 64 and IA-32 Architectures Software Developer’s Manual, Volume 3A: System Programming Guide, Part 1.

Here is Table 9-6 from that section:


This table also details an extended header (> 48 bytes, starting with the field named Update Data) which does not form part of this blog post.

Here is a simple Python script which converts the downloaded microcode.dat ASCII file and converts it into a little endian binary file suitable for use on a Linux system which supports loading microcode updates.

#!/usr/bin/python3
#
#   Author: Finnbarr P. Murphy
#  License: BSD
#     Date: November 2016
#    Usage: scriptname microcode.dat microcode.bin
#


import sys
import binascii

def convert2int(sval) :
    sval = sval.replace('\t','').replace('0x','').replace(' ','')
    return int.from_bytes(binascii.unhexlify(sval), 'little')


if len(sys.argv) != 3 :
    print("ERROR: An input and output filename is required")
    exit(1)

try :
    infile = open(sys.argv[1], "r")
except IOError :
    print("ERROR: Failed to open input file")
    exit(1)

try :
    outfile = open(sys.argv[2], "wb")
except IOError :
    print("ERROR: Failed to open output file")
    infile.close()
    exit(2)
 
for line in infile : 
    if line[0] == '/' :
        continue
    hvals = line.split(',')
    for hval in hvals :
        if hval == '\r\n' or hval == '\n' or hval == '\r' :
            continue
        outfile.write(bytes.fromhex('%0.8X' % convert2int(hval)))

infile.close()
outfile.close()

exit(0)


Note that this script does not break the individual microcode updates into individual files as some tools such as iucode_tool do. This functionality could easily be added if desired.

The following script takes the downloaded file and outputs a line of information for each microcode header found in the file. Note that the script only parses the standard microcode header and not any extended headers. Functionality to parse any extended headers found in the file could easily be added if desired but I did not include such code as I had no need for this information.

#!/usr/bin/python3
#
#   Author: Finnbarr P. Murphy
#  License: BSD
#     Date: November 2016
#    Usage: scriptname < microcode.dat 
#


import sys
import binascii
import re


def CpuFamily(sig) :
    fam = (sig >> 8) & 0xF 
    if fam == 0xF :
       fam += (sig >> 20) & 0xFF
    return fam


def CpuModel(sig) :
    fam = CpuFamily(sig)
    model = (sig >> 4) & 0xF
    if fam >= 0x6 :
        model += ((sig >> 16) & 0xF) << 4
    return model
 

def CpuStepping(sig) :
    return sig & 0xF


def convert2int(sval) :
    sval = sval.replace('\t','').replace('0x','').replace(' ','')
    # return int.from_bytes(binascii.unhexlify(sval), 'little')
    return int(sval, 16)

 
ints = 0
outline = ""
total = 0
matched = 0
datestr = "[A-Z][a-z]{2}\ [A-Z][a-z]{2}\ \d{1,2}\ \d{2}:\d{2}:\d{2}\ [A-Z]{3}\ \d{4}"


for line in sys.stdin:
    if line[0] == '/' :
        if line[1] != '*' :
            continue
        line = line.replace('\n','').replace('\r','').replace('/*','').replace('*/','')
        if not matched :
            match = re.search(datestr, line)
            if match is not None :
                matched = 1
                print("Release Date: {0}".format(line.strip()))
                print("\nDate          Sig F/M/S   Flags       Datasize      Name\n")
                continue
        if outline :
            print("{0}    {1}".format(outline, name))
            total += 1
            outline = ""
        name = line.upper().replace('.INC','')
        ints = 0
        continue
    hvals = line.split(',')
    for hval in hvals:
        if hval == '\r\n' or hval == '\r' or hval == '\n' :
            continue
        if ints == 2 :      # date
            outline += "{0:s}-{1:s}-{2:s}".format(hval[7:], hval[3:5], hval[5:7])
        elif ints == 3 :    # signature
            sig = convert2int(hval)
            fms = "     {0:d}/{1:d}/{2:d}".format(CpuFamily(sig), CpuModel(sig), CpuStepping(sig))
            outline += fms.ljust(12) 
        elif ints == 6 :    # processor flags
            procflags = convert2int(hval)
            outline += "    {0:08b}".format(procflags)
        elif ints == 7 :    # data size
            datasize = convert2int(hval)
            if datasize == 0 :
               datasize = 2000
            outline += "    0x{0:06X}".format(datasize)
        ints += 1

print("\nTotal: {0}".format(total))

exit(0)


Note that the above script does not elegantly handle any errors it encounters when invoked. I leave it up to you the reader to modify the script to make it more robust.

Here is the output generated by the above script when run against the latest Intel Linux microcode (November 4th, 2016) download:

Release Date: Fri Nov 4 16:09:13 CST 2016

Date          Sig F/M/S   Flags       Datasize      Name

2002-08-21     15/0/10    00000010    0x0007D0      M02F0A15  
2004-08-26     15/2/5     00010000    0x0007D0      M10F252C  
1999-06-28     6/5/3      00000001    0x0007D0      MU165310  
2001-02-20     6/11/1     00100000    0x0007D0      MU16B11D  
2003-06-04     15/2/7     00001000    0x0007D0      M08F2739  
1999-05-05     6/6/10     00001000    0x0007D0      MU166A0D  
2002-07-16     15/0/10    00000100    0x0007D0      M04F0A14  
2000-03-06     6/10/1     00000100    0x0007D0      MU26A101  
1999-05-25     6/5/0      00000010    0x0007D0      MU165041  
2005-04-21     15/4/9     10111101    0x0007D0      MBDF4903  
1999-09-21     6/8/1      00001000    0x0007D0      MU16810F  
1998-06-10     6/3/2      00000000    0x0007D0      MU163202  
2000-05-05     6/8/6      00000001    0x0007D0      MU168607  
2004-11-09     6/9/5      00100000    0x0007D0      M2069507  
1999-05-05     6/6/13     00100000    0x0007D0      MU166D07  
1999-05-25     6/5/0      00001000    0x0007D0      MU165045  
2004-08-11     15/2/9     00001000    0x0007D0      M08F292F  
2004-10-17     6/13/6     00100000    0x0007D0      M206D618  
2002-01-10     6/11/4     00010000    0x0007D0      MU16B401  
2005-04-21     15/3/3     00001101    0x0007D0      M0DF330C  
2000-01-10     6/10/0     00000100    0x0007D0      MU26A003  
1999-05-20     6/5/3      00000100    0x0007D0      MU26530B  
2000-05-04     6/8/6      00000010    0x0007D0      MU16860A  
2006-07-14     15/6/8     00100010    0x0007D0      M22F6809  
1999-05-05     6/6/5      00010000    0x0007D0      MU166503  
2004-05-11     15/3/2     00001101    0x0007D0      M0DF320A  
2004-11-09     6/9/5      00010000    0x0007D0      M1069507  
2001-02-15     6/11/1     00010000    0x0007D0      MU16B11C  
2000-05-04     6/8/6      00000100    0x0007D0      MU268602  
2004-08-11     15/2/5     00000010    0x0007D0      M02F252A  
2003-05-02     15/1/2     00000100    0x0007D0      M04F122E  
1999-09-21     6/8/1      00000100    0x0007D0      MU268110  
1999-09-21     6/8/1      00100000    0x0007D0      MU16810E  
2004-08-11     15/2/9     00000100    0x0007D0      M04F292E  
1999-05-25     6/5/0      00000001    0x0007D0      MU165040  
2000-12-07     6/8/10     10000000    0x0007D0      MU168A05  
2004-08-11     15/2/9     00000010    0x0007D0      M02F292D  
1999-05-05     6/6/10     00000010    0x0007D0      MU166A0C  
2005-12-14     15/4/10    01011100    0x0007D0      M5CF4A04  
2002-01-11     6/11/4     00100000    0x0007D0      MU16B402  
1999-05-18     6/5/3      00000010    0x0007D0      MU16530C  
1999-10-15     6/8/3      00001000    0x0007D0      MU168308  
1999-03-12     6/6/13     00001000    0x0007D0      MU166D06  
2003-06-05     15/2/4     00000010    0x0007D0      M02F241F  
2003-06-04     15/2/7     00000100    0x0007D0      M04F2737  
1999-09-10     6/7/3      00000100    0x0007D0      MU26732E  
1999-03-12     6/6/13     00000010    0x0007D0      MU166D05  
2000-11-02     6/8/10     00010000    0x0007D0      MU168A01  
1999-09-21     6/8/1      00000001    0x0007D0      MU16810D  
1999-05-12     6/5/2      00000100    0x0007D0      MU26522B  
2000-12-07     6/8/10     00100000    0x0007D0      MU168A04  
2004-11-09     6/9/5      10000000    0x0007D0      M8069547  
2000-05-04     6/8/6      10000000    0x0007D0      MU16860C  
2003-06-04     15/2/7     00000010    0x0007D0      M02F2738  
2005-04-21     15/4/3     10011101    0x0007D0      M9DF4305  
1999-05-12     6/5/2      00000001    0x0007D0      MU16522A  
2004-08-05     15/2/6     00000010    0x0007D0      M02F2610  
2003-06-10     15/2/4     00010000    0x0007D0      M10F2421  
2000-11-15     15/0/7     00000010    0x0007D0      2F0708  
1999-05-17     6/5/2      00000010    0x0007D0      MU16522C  
1999-05-18     6/5/3      00001000    0x0007D0      MU16530D  
2002-07-16     15/0/10    00000001    0x0007D0      M01F0A13  
1999-05-05     6/6/10     00100000    0x0007D0      MU166A0B  
1999-10-15     6/8/3      00100000    0x0007D0      MU168307  
1998-08-11     6/7/1      00000100    0x0007D0      MU267114  
1999-09-21     6/8/1      00010000    0x0007D0      MU168111  
2005-06-10     15/4/10    01011101    0x0007D0      M5DF4A02  
2002-07-16     15/0/7     00000001    0x0007D0      M01F0712  
2003-06-05     15/2/4     00000100    0x0007D0      M04F241E  
1999-09-22     6/7/2      00000100    0x0007D0      MU267238  
1999-05-05     6/6/0      00000001    0x0007D0      MU16600A  
1999-05-25     6/5/1      00000001    0x0007D0      MU165140  
2000-05-05     6/8/6      00010000    0x0007D0      MU168608  
2004-08-11     15/2/5     00000001    0x0007D0      M01F2529  
2004-08-11     15/2/5     00000100    0x0007D0      M04F252B  
2010-10-03     6/15/11    00100000    0x000FD0      M206FBBA  
2005-04-22     15/4/1     10111101    0x0013D0      MBDF4117  
2010-10-03     6/15/11    00001000    0x000FD0      M086FBBB  
2010-09-30     6/15/6     00000001    0x000FD0      M16F6D0  
2009-08-25     6/28/10    00000100    0x0013D0      M04106CA107  
2009-08-25     6/28/10    00000001    0x0013D0      M01106CA107  
2010-09-29     6/23/7     00010000    0x000FD0      M101067770A  
2010-10-03     6/15/11    10000000    0x000FD0      M806FBBA  
2005-04-21     15/4/4     10011101    0x000BD0      M9DF4406  
2005-04-21     15/4/7     10011101    0x000BD0      M9DF4703  
2005-06-30     15/4/8     01011111    0x000BD0      M5FF4807  
2005-12-15     15/6/4     00000001    0x000BD0      M01F6402  
2010-10-04     6/22/1     10000000    0x000FD0      M801066144  
2010-09-29     6/23/6     00000001    0x000FD0      M011067660F  
2010-10-01     6/15/6     00000100    0x000FD0      M46F6D2  
2010-09-29     6/23/6     10000000    0x000FD0      M801067660F  
2005-12-15     15/6/2     00000100    0x000BD0      M04F620F  
2010-10-02     6/15/13    00100000    0x000FD0      M206FDA4  
2010-10-03     6/15/11    01000000    0x000FD0      M406FBBC  
2010-10-02     6/15/13    00000001    0x000FD0      M16FDA4  
2009-04-10     6/28/2     00000001    0x0013D0      M01106C2217  
2010-10-03     6/15/11    00010000    0x000FD0      M106FBBA  
2005-12-23     15/6/4     00110100    0x000BD0      M34F6404  
2010-09-29     6/23/6     00010000    0x000FD0      M101067660F  
2009-04-10     6/28/2     00000100    0x0013D0      M04106C2218  
2009-08-25     6/28/10    00010000    0x0013D0      M10106CA107  
2009-04-10     6/28/2     00001000    0x0013D0      M08106C2219  
2010-10-02     6/15/13    10000000    0x000FD0      M806FDA4  
2005-04-21     15/4/1     00000010    0x0013D0      M02F4116  
2005-11-15     6/14/8     00100000    0x000FD0      M206E839  
2010-10-03     6/15/11    00000001    0x000FD0      M016FBBA  
2006-05-01     6/14/12    00100000    0x000FD0      M206EC54  
2010-10-03     6/15/11    00000100    0x000FD0      M046FBBC  
2009-08-25     6/28/10    00001000    0x0013D0      M08106CA107  
2009-10-23     6/38/1     00000001    0x0013D0      M0120661104  
2010-10-04     6/22/1     00000010    0x000FD0      M021066142  
2010-10-02     6/15/2     00000001    0x000FD0      M16F25D  
2006-04-26     15/6/5     00000001    0x0007D0      M01F6508  
2010-10-01     6/15/6     00100000    0x000FD0      M206F6D1  
2006-05-08     15/4/8     00000001    0x000BD0      M01F480C  
2005-04-21     15/3/4     00011101    0x001BD0      M1DF3417  
2010-10-02     6/15/7     00010000    0x000FD0      M106F76A  
2006-09-12     6/14/12    10000000    0x000FD0      M806EC59  
2010-10-02     6/15/2     00100000    0x000FD0      M206F25C  
2010-10-02     6/15/7     01000000    0x000FD0      M406F76B  
2008-01-15     15/4/8     00000010    0x000BD0      M02F480E  
2011-07-18     6/38/1     00000010    0x0013D0      M0220661105_CV  
2010-10-02     6/15/10    10000000    0x000FD0      M806FA95  
2010-10-04     6/22/1     00000001    0x000FD0      M011066143  
2013-08-20     6/30/5     00010011    0x001BD0      M13106E5_00000007  
2014-05-29     6/62/4     11101101    0x0033D0      MED306E4_00000428  
2010-09-28     6/23/10    10100000    0x001FD0      MA01067AA0B  
2013-06-26     6/37/2     00010010    0x001FD0      M1220652_0000000E  
2013-06-21     6/26/5     00000011    0x0027D0      M03106A5_00000019  
2010-09-28     6/23/10    00010001    0x001FD0      M111067AA0B  
2013-06-17     6/45/7     01101101    0x0043D0      M6D206D7_00000710  
2013-06-28     6/37/5     10010010    0x000BD0      M9220655_00000004  
2013-06-21     6/26/4     00000011    0x0037D0      M03106A4_00000012  
2013-06-19     6/62/6     11101101    0x002BD0      MED306E6_00000600  
2012-05-22     6/45/6     01101101    0x003FD0      M6D206D6_00000619  
2013-06-12     6/42/7     00010010    0x0027D0      M12206A7_00000029  
2014-05-29     6/62/7     11101101    0x003BD0      MED306E7_0000070D  
2015-02-26     6/58/9     00010010    0x002FD0      M12306A9_0000001C  
2016-10-07     6/79/1     11101111    0x0063D0      MEF406F1_0B00001F  
2016-06-22     6/78/3     11000000    0x017BD0      MC0406E3_0000009D_0000009E  
2016-04-29     6/61/4     11000000    0x0043D0      MC0306D4_00000024  
2016-04-01     6/69/1     01110010    0x004FD0      M7240651_0000001F  
2016-04-01     6/70/1     00110010    0x005FD0      M3240661_00000016  
2016-04-29     6/71/1     00100010    0x002BD0      M2240671_00000016  
2015-12-12     6/86/2     00010000    0x006FD0      M1050662_0000000F  
2016-06-07     6/63/4     10000000    0x003BD0      M80306F4_0000000D  
2016-06-22     6/94/3     00110110    0x017BD0      M36506E3_0000009D_0000009E  
2016-03-16     6/60/3     00110010    0x0057D0      M32306C3_00000020  
2016-10-07     6/63/2     01101111    0x007FD0      M6F306F2_00000039  
2013-06-18     6/47/2     00000101    0x0033D0      M05206F2_00000037  
2010-09-28     6/23/10    01000100    0x001FD0      M441067AA0B  
2010-09-29     6/23/6     01000000    0x000FD0      M401067660F  
2010-09-30     6/29/1     00001000    0x000FD0      M08106D129  
2010-09-29     6/23/6     00000100    0x000FD0      M041067660F  
2016-06-02     6/86/4     00010000    0x0053D0      M1050664_0F00000A  

Total: 155


The first column is the individual microcode release date, the second column is the processor family, model and stepping which were extracted from the Processor Signature field, the third column represents processor type bits extracted from the Processor Flag field, the next column is the size of the microcode code in bytes, and the final column is the identification string used by Intel.

Well, that is all for now. The source code I have provided above should be enough to enable you to develop your own Python tool(s) to slice and dice the Intel microcode file in whatever manner you wish. Both scripts ware developed using Python 3.5 on Windows 10 using the Subsystem for Linux; thus there is no guarantee that the code will work without modification on Python 2.7.

Enjoy the holiday season and Merry Christmas to all my readers.

Comments are closed.