Update Intel Microcode on FreeBSD

From Thomas-Krenn-Wiki
Jump to navigation Jump to search

FreeBSD provides support for updating the microcode of a processor at startup or at runtime. In this article, we use a server running FreeBSD 12.0 to show how to check the Intel Microcode version and how to install newer microcode versions if necessary.

Example Setup

In this example we use the following setup:

  • Server using an ASUS P9D-MV Mainboard with BIOS Version 2101 and an Intel Celeron G1820T CPU
  • FreeBSD 12.0

The example was carried out on 16.01.2019 with the most current BIOS, microcode and software versions available at that time. It clearly shows how the latest security updates can be installed in security-critical environments, both in terms of microcode and software updates.

Read current microcode version

In the Microcode Update Guidance from 08.08.2018, Intel lists the new microcode version 0x25 for the Intel Celeron G1820T (CPUID 306c3) used here in the example.

Information about the CPU (name, CPUID, microcode version) can be queried with the tool x86info after loading the module cpuctl:

kldload cpuctl
x86info -a

In the output the line Microcode version shows the version (in the example 0x000000000000000024), the CPUID can be found in the second line in the eax output (in the example 000306c3):

root@freebsd12:~ # kldload cpuctl
root@freebsd12:~ # x86info -a
x86info v1.31pre
MP Table:
#	APIC ID	Version	State		Family	Model	Step	Flags
#	 0	 0x15	 BSP, usable	 6	 12	 3	 0x0381
#	 2	 0x15	 AP, usable	 6	 12	 3	 0x0381

Found 2 identical CPUs
Extended Family: 0 Extended Model: 3 Family: 6 Model: 60 Stepping: 3
Type: 0 (Original OEM)
CPU Model (x86info's best guess): Xeon E3 [Haswell]
Processor name string (BIOS programmed): Intel(R) Celeron(R) CPU G1820T @ 2.40GHz

[...]

Microcode version: 0x0000000000000024

eax in: 0x00000000, eax = 0000000d ebx = 756e6547 ecx = 6c65746e edx = 49656e69
eax in: 0x00000001, eax = 000306c3 ebx = 00100800 ecx = 4ddaebbf edx = bfebfbff

Intel provides information about available microcode versions in the document Microcode Update Guidance (see Intel Microcode - Microcode Versions). This document lists CPUs by their CPUID.

When searching for 306c3 in the document Microcode Update Guidance of 08.08.2018, the column New Production MCU Rev contains the microcode version 0x25. In this case Intel provides a newer microcode version than is currently available through the BIOS on the example system.

Variant 1: Update via devcpu-data

The port devcpu-data contains Intel and AMD CPU microcode updates (binary files). The microcodes of devcpu-data are imported into the CPU via cpuctl(4) / cpucontrol(8). So that the update of the microcode is carried out automatically during the start process, the entries cpu_microcode_load and cpu_microcode_name must be added to /boot/loader.conf.

To install the microcode updates automatically in the future, install the package devcpu-data and enter both options in /boot/loader.conf:

# pkg install devcpu-data
# vi /boot/loader.conf
# cat /boot/loader.conf
cpu_microcode_load="YES"
cpu_microcode_name="/boot/firmware/intel-ucode.bin"
# reboot

On the example system, the microcode version is updated from 0x24 to 0x25:

root@freebsd12:~ # pkg install devcpu-data
[...]
Message from devcpu-data-1.20:

Installing this port will allow host startup to update the CPU microcode on 
a FreeBSD system automatically.  There are two methods for updating CPU
microcode: the first methods loads and applies the update before the kernel
begins booting, and the second method loads and applies updates using an
rc script.  The first method is preferred, but is currently only supported
on Intel i386 and amd64 processors running FreeBSD 12.0.  It is safe to
enable both methods.

The first method ensures that any CPU features introduced by a microcode
update are visible to the kernel.  In other words, the update is loaded
before the kernel performs CPU feature detection.

To enable updates using the first method, add the following lines to
the system's /boot/loader.conf:

cpu_microcode_load="YES"
cpu_microcode_name="/boot/firmware/intel-ucode.bin"

This method will not load the microcode update until the system is
rebooted.

To enable updates using the second method, add the following line to
the system's /etc/rc.conf:

microcode_update_enable="YES"

Then, to ensure the update is applied, reboot the system or start the
microcode update service via:

# service microcode_update start

If the CPU requires a microcode update, a console message such as the following
will appear:

Updating CPU Microcode...
/usr/local/share/cpucontrol/m32306c3_00000022.fw: updating cpu /dev/cpuctl0 from rev 0x17 to rev 0x22... done.
/usr/local/share/cpucontrol/m32306c3_00000022.fw: updating cpu /dev/cpuctl2 from rev 0x17 to rev 0x22... done.
/usr/local/share/cpucontrol/m32306c3_00000022.fw: updating cpu /dev/cpuctl4 from rev 0x17 to rev 0x22... done.
/usr/local/share/cpucontrol/m32306c3_00000022.fw: updating cpu /dev/cpuctl6 from rev 0x17 to rev 0x22... done.
Done.
root@freebsd12:~ # ls -lh /boot/firmware/intel-ucode.bin
-rw-r--r--  1 root  wheel   1.7M Jan 11 23:18 /boot/firmware/intel-ucode.bin
root@freebsd12:~ # vi /boot/loader.conf
root@freebsd12:~ # cat /boot/loader.conf
cpu_microcode_load="YES"
cpu_microcode_name="/boot/firmware/intel-ucode.bin"
root@freebsd12:~ # reboot
[...]

After the reboot the new microcode is in use:

root@freebsd12:~ # kldload cpuctl
root@freebsd12:~ # x86info -a | grep -i microcode
Microcode version: 0x0000000000000025

Variant 2: Update via cpupdate

In addition to the variant described above, another port for updating the microcode has been available since 2018: sysutils/cpupdate. This was developed by Stefan Blachmann as an alternative to devcpu-data to avoid bugs and limitations of devcpu-data.[1][2][3] The new tool cpupdate offers additional functions, e.g. the simple query of the current microcode via cpupdate -i.[4]

The developer recommends that you compile the tool yourself.[5]

As an upgrade from self-compiled ports is difficult,[6] the #Variant 1

The installation of cpupdate on a test system can be done as follows:

# portsnap auto
# cd /usr/ports/sysutils/cpupdate
# make install

Am Beispielsystem ausgeführt:

root@freebsd12:~ # portsnap auto
root@freebsd12:~ # cd /usr/ports
root@freebsd12:/usr/ports # make search name=cpupdate
Port:	cpupdate-g20180513_1
Path:	/usr/ports/sysutils/cpupdate
Info:	CPU microcode update utility for x86
Maint:	eugen@FreeBSD.org
B-deps:	
R-deps:	
WWW:	https://github.com/kernschmelze/cpupdate

root@freebsd12:/usr/ports # cd /usr/ports/sysutils/cpupdate
root@freebsd12:/usr/ports/sysutils/cpupdate # make install
===> Building/installing dialog4ports as it is required for the config dialog
[...]
                                          ┌─────────────────────────── cpupdate-g20180513_1 ─────────────────────────────┐
                                          │ ┌──────────────────────────────────────────────────────────────────────────┐ │  
                                          │ │+[x] CPM    Download platomav/CPUMicrocodes collection                    │ │  
                                          │ │+[x] INTEL  Download Intel microcode pack microcode-20180807.tgz          │ │  
                                          │ └──────────────────────────────────────────────────────────────────────────┘ │  
                                          ├──────────────────────────────────────────────────────────────────────────────┤  
                                          │                       <  OK  >            <Cancel>                           │  
                                          └──────────────────────────────────────────────────────────────────────────────┘  
===>  License BSD2CLAUSE accepted by the user
===>   cpupdate-g20180513_1 depends on file: /usr/local/sbin/pkg - found
=> microcode-20180807.tgz doesn't seem to exist in /usr/ports/distfiles/.
=> Attempting to fetch https://downloadmirror.intel.com/28039/eng/microcode-20180807.tgz
microcode-20180807.tgz                                1591 kB 7924 kBps    01s
[...]
Installing cpupdate-g20180513_1...
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
NOTE: The following directories

/usr/ports/sysutils/cpupdate/work/CPUMicrocodes-0d88b2e
/usr/ports/sysutils/cpupdate/work/intel-ucode

contain Intel and/or platomav/CPUMicrocodes collections respectively
if you have just built the port with corresponding CPM/INTEL option(s) enabled.
In this case you can run "make install-microcodes" to install them to

/usr/local/share/cpupdate
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Suspend/resume sequence clears microcode update, so make sure your system runs
"service cpupdate start" again on resume.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

root@freebsd12:/usr/ports/sysutils/cpupdate # make install-microcodes
/bin/rm -f -rf /usr/local/share/cpupdate/CPUMicrocodes/primary/Intel
/bin/mkdir -p /usr/local/share/cpupdate/CPUMicrocodes/primary/Intel
[...]

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
NOTE: you have to manually remove the directory
/usr/local/share/cpupdate/CPUMicrocodes/primary/Intel
after deinstallation of cpupdate.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
NOTE: you have to manually remove the directory
/usr/local/share/cpupdate/CPUMicrocodes/secondary/Intel
after deinstallation of cpupdate.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
root@freebsd12:/usr/ports/sysutils/cpupdate #

Cpupdate bietet die folgenden Optionen:

# cpupdate 
Usage: cpupdate [-qwvvuiCXIAVh] [-<f|U> <microcodefile>] [-<cpsST> <datadir>]
  -i   show processor information
  -u   update microcode
  -U   update microcode using file <microcodefile>
  -w   write it: without this option cpupdate only simulates updating
  -q   quiet mode
  -v   verbose mode, -vv very verbose
  -p   use primary repo path <datadir>
  -s   use secondary repo path <datadir>
  -V   print version
  -h   show this help
  -IAV for the options below: vendor mode must be set [atm only Intel (-I) implemented]
  -f   show version information of microcode file
  -c   Check integrity of microcode files in <datadir>
  -d   As -c, in addition print microcode file statistics
  -C   convert/compact microcode files from legacy to multi-blob intel-ucode file format
  -X   convert (extract) microcode files from multi-blob intel-ucode to legacy file format
  -S   source dir for converting
  -T   target dir for converting

The update of the microcode at runtime looks as follows in the example system:

root@freebsd12:/usr/ports/sysutils/cpupdate # cpupdate -i
Found CPU(s) from Intel
Core 0 to 1: CPUID: 306c3  Fam 06  Mod 3c  Step 03  Flag 02 uCode 00000024
root@freebsd12:/usr/ports/sysutils/cpupdate # cpupdate -u
Found CPU(s) from Intel
No updating error. Registering CPU features
Successfully registered new CPU features
ATTENTION NOTICE: -w option missing! No actual update, only dry run done!.
root@freebsd12:/usr/ports/sysutils/cpupdate # cpupdate -w -u
Found CPU(s) from Intel
No updating error. Registering CPU features
Successfully registered new CPU features
root@freebsd12:/usr/ports/sysutils/cpupdate # cpupdate -i
Found CPU(s) from Intel
Core 0 to 1: CPUID: 306c3  Fam 06  Mod 3c  Step 03  Flag 02 uCode 00000025
root@freebsd12:/usr/ports/sysutils/cpupdate #

To automatically update the microcode at startup, the following steps are required:

  1. Add in /boot/loader.conf:
    cpuctl_load="YES"
  2. Add in /etc/rc.conf:
    cpupdate_enable="YES"
  3. Do a rebot.

After the reboot cpupdate shows the new microcode version 0x25 on the example system:

root@freebsd12:~ # cpupdate -i
Found CPU(s) from Intel
Core 0 to 1: CPUID: 306c3  Fam 06  Mod 3c  Step 03  Flag 02 uCode 00000025
root@freebsd12:~ # 

Differences

When testing the two variants on 16.01.2018, it became apparent that the microcode of #Variant 1: Update via devcpu-data is loaded very early during the boot process.[7] Already at the first initialization of the CPU the four Structured Extended Features3 (IBPB,STIBP,L1DFL,SSBD) are recognized, which are provided by the microcode version 0x25. Here is the excerpt of the dmesg output:

Copyright (c) 1992-2018 The FreeBSD Project.
Copyright (c) 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994
	The Regents of the University of California. All rights reserved.
FreeBSD is a registered trademark of The FreeBSD Foundation.
FreeBSD 12.0-RELEASE-p2 GENERIC amd64
FreeBSD clang version 6.0.1 (tags/RELEASE_601/final 335540) (based on LLVM 6.0.1)
VT(efifb): resolution 800x600
CPU: Intel(R) Celeron(R) CPU G1820T @ 2.40GHz (2394.52-MHz K8-class CPU)
  Origin="GenuineIntel"  Id=0x306c3  Family=0x6  Model=0x3c  Stepping=3
[...]
  Structured Extended Features3=0x9c000000<IBPB,STIBP,L1DFL,SSBD>
[...]
real memory  = 2147483648 (2048 MB)
avail memory = 2002632704 (1909 MB)
CPU microcode: updated from 0x24 to 0x25

With the #Variant 2: Update via cpupdate two of the four Structured Extended Features 3 are missing at the beginning - therefore the older Microcode Version 0x24 is still in use at the beginning. This can be seen via dmesg:

Copyright (c) 1992-2018 The FreeBSD Project.
[...]
CPU: Intel(R) Celeron(R) CPU G1820T @ 2.40GHz (2394.52-MHz K8-class CPU)
  Origin="GenuineIntel"  Id=0x306c3  Family=0x6  Model=0x3c  Stepping=3
[...]
  Structured Extended Features3=0xc000000<IBPB,STIBP>
[...]
real memory  = 2147483648 (2048 MB)
[...]
Trying to mount root from ufs:/dev/ada0p2 [rw]...
CPU: Intel(R) Celeron(R) CPU G1820T @ 2.40GHz (2394.52-MHz K8-class CPU)
  Origin="GenuineIntel"  Id=0x306c3  Family=0x6  Model=0x3c  Stepping=3
[...]
  Structured Extended Features3=0x9c000000<IBPB,STIBP,L1DFL,SSBD>

With #Variant 2: Update via cpupdate it is also possible to load the microcode at the beginning. However, the exact microcode file of the CPU must be listed.[8] On the example system this is possible by the following entry in /boot/loader.conf:

cpu_microcode_load="YES"
cpu_microcode_name="/usr/local/share/cpupdate/CPUMicrocodes/primary/Intel/06-3c-03"

References

  1. Introducing cpupdate, a microcode tool for FreeBSD (forums.freebsd.org, 09.02.2018)
  2. cpupdate (github.com)
  3. Bug 192487 - cpucontrol uses unsafe procedure to detect current microcode version (bugs.freebsd.org)
  4. cpupdate manpage draft (bsd.denkverbot.info, 19.03.2018)
  5. cpupdate (github.com) Please do not install via pkg. Please use ports or manually clone it with git.
  6. Absolute FreeBSD 3rd Edition Chapter 16, page 371: Ports and Production: I would strongly encourage you to build build your own package repository with poudriere and manage your servers' ports from that repository. Upgrading ports directly installed on a host is annoying and difficult. [...] You have been warned.
  7. D16370: Implement early microcode loading for Intel i386 and amd64 platforms (reviews.freebsd.org)
  8. Introducing cpupdate, a microcode tool for FreeBSD - Comment #16 (forums.freebsd.org, 16.01.2019)


Foto Werner Fischer.jpg

Author: Werner Fischer

Werner Fischer, working in the Knowledge Transfer team at Thomas-Krenn, completed his studies of Computer and Media Security at FH Hagenberg in Austria. He is a regular speaker at many conferences like LinuxTag, OSMC, OSDC, LinuxCon, and author for various IT magazines. In his spare time he enjoys playing the piano and training for a good result at the annual Linz marathon relay.


Related articles

Broadcom BCM574xx VLAN problem under FreeBSD 13.2 with bnxt driver
Timecounter HPET frequency 19200000 Hz quality 950
Update FreeBSD