diff --git a/.gitignore b/.gitignore
index 487117e..aaa1502 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1 @@
-SOURCES/microcode_ctl-2.1-20180425.tar.xz
+SOURCES/microcode_ctl-2.1-20180703.tar.xz
diff --git a/.microcode_ctl.metadata b/.microcode_ctl.metadata
index c9bd3e4..6888465 100644
--- a/.microcode_ctl.metadata
+++ b/.microcode_ctl.metadata
@@ -1 +1 @@
-6571a7941864bb7bc3feee13d4c2ca40cbb8b7cb SOURCES/microcode_ctl-2.1-20180425.tar.xz
+60aeb4e9b797c74941815ca4d5877507caee043c SOURCES/microcode_ctl-2.1-20180703.tar.xz
diff --git a/SOURCES/06-4f-01_config b/SOURCES/06-4f-01_config
new file mode 100644
index 0000000..c568ed5
--- /dev/null
+++ b/SOURCES/06-4f-01_config
@@ -0,0 +1,13 @@
+model GenuineIntel 06-4f-01
+path intel-ucode/06-4f-01
+kernel 4.17.0
+kernel 3.10.0-894
+kernel 3.10.0-862.6.1
+kernel 3.10.0-693.35.1
+kernel 3.10.0-514.52.1
+kernel 3.10.0-327.70.1
+kernel 2.6.32-754.1.1
+kernel 2.6.32-573.58.1
+kernel 2.6.32-504.71.1
+kernel 2.6.32-431.90.1
+kernel 2.6.32-358.90.1
diff --git a/SOURCES/06-4f-01_readme b/SOURCES/06-4f-01_readme
new file mode 100644
index 0000000..afb4d2d
--- /dev/null
+++ b/SOURCES/06-4f-01_readme
@@ -0,0 +1,19 @@
+The microcode for Broadwell-EP/EX (BDX-ML B/M/R0, family 6, model 79,
+stepping 1) processors requires a kernel with special commits present,
+otherwise it might result in unexpected system behaviour.  In order
+to handle this, /usr/libexec/microcode_ctl/update_ucode script creates
+necessary symlinks to make it available on kernels with the aforementioned
+patches present.
+
+If you want to avoid adding this ucode for a specific kernel, please create
+a disallow-06-4f-01 file inside /lib/firmware/<kernel_version> directory:
+
+    touch /lib/firmware/3.10.0-862.9.1/disallow-06-4f-01
+
+If you want to skip processing of this firmware for all kernels, please create
+a disallow-06-4f-01 file inside /etc/microcode_ctl/ucode_with_caveats directory:
+
+    touch /etc/microcode_ctl/ucode_with_caveats/disallow-06-4f-01
+
+If you want avoid removal of the ucode file during cleanup, please remove the
+corresponding readme file.
diff --git a/SOURCES/check_caveats b/SOURCES/check_caveats
new file mode 100755
index 0000000..04975c2
--- /dev/null
+++ b/SOURCES/check_caveats
@@ -0,0 +1,251 @@
+#! /bin/bash -eu
+
+# Script for checking various microcode caveats
+#
+#
+# SPDX-License-Identifier: CC0-1.0
+
+: ${MC_CAVEATS_DATA_DIR=/usr/share/microcode_ctl/ucode_with_caveats}
+
+usage() {
+	echo 'Usage: check_caveats [-k TARGET_KVER] [-c CONFIG] [-m] [-v]'
+	echo
+	echo '   -k - target version to check against, $(uname -r) is used'
+	echo '        otherwise'
+	echo '   -c - caveat config(s) to check, all configs are checked'
+	echo '        otherwise'
+	echo '   -m - check that caveats actually apply to the current model'
+	echo '   -v - verbose output'
+	echo
+	echo 'Environment:'
+	echo '  MC_CAVEATS_DATA_DIR - directory that contains caveats'
+	echo '                        configuration data'
+}
+
+debug() { [ 0 = "$verbose" ] || echo "$*" >&2; }
+
+# A simplified RPM version comparison that takes into account knowledge about
+# Y- and Z-streams (so it compares versions inside Y-stram or Z-stream if
+# the version against which comparison is performed has appropriate versioning
+# scheme).
+#
+# $1 - kernel version to check
+# $* - list of kernel versions to check against
+check_kver()
+{
+	local t_major= t_minor= t_patch= t_y= t_z1= t_z2= t_rest=
+	local m_major= m_minor= m_patch= m_y= m_z1= m_z2= m_rest=
+	local cmp_type=
+
+	# IFS=.- read -r t_major t_minor t_patch t_y t_z1 t_z2 t_rest <<<"$1"
+	# "cannot create temp file for here-document: Read-only file system"
+	# that's why we can't have nice things.
+	t_major=${1%%[.-]*}
+	t_rest=${1#${t_major}}
+	t_rest=${t_rest#[.-]}
+	t_minor=${t_rest%%[.-]*}
+	t_rest=${t_rest#${t_minor}}
+	t_rest=${t_rest#[.-]}
+	t_patch=${t_rest%%[.-]*}
+	t_rest=${t_rest#${t_patch}}
+	t_rest=${t_rest#[.-]}
+	t_y=${t_rest%%[.-]*}
+	t_rest=${t_rest#${t_y}}
+	t_rest=${t_rest#[.-]}
+	t_z1=${t_rest%%[.-]*}
+	t_rest=${t_rest#${t_z1}}
+	t_rest=${t_rest#[.-]}
+	t_z2=${t_rest%%[.-]*}
+
+	# minor/major/patch/y should be numeric
+	[ -n "${t_major##*[!0-9]*}" ] || return 1
+	[ -n "${t_minor##*[!0-9]*}" ] || return 1
+	[ -n "${t_patch##*[!0-9]*}" ] || return 1
+	[ -n "${t_y##*[!0-9]*}" ] || return 1
+	# reset z1/z2 to zero if non-numeric
+	[ -n "${t_z1##*[!0-9]*}" ] || t_z1=0
+	[ -n "${t_z2##*[!0-9]*}" ] || t_z2=0
+
+	while [ 1 -lt "$#" ]; do
+		cmp_type=upstream
+
+		shift
+		m_major=${1%%[.-]*}
+		m_rest=${1#${m_major}}
+		m_rest=${m_rest#[.-]}
+		m_minor=${m_rest%%[.-]*}
+		m_rest=${m_rest#${m_minor}}
+		m_rest=${m_rest#[.-]}
+		m_patch=${m_rest%%[.-]*}
+		m_rest=${m_rest#${m_patch}}
+		m_rest=${m_rest#[.-]}
+		m_y=${m_rest%%[.-]*}
+		m_rest=${m_rest#${m_y}}
+		m_rest=${m_rest#[.-]}
+		m_z1=${m_rest%%[.-]*}
+		m_rest=${m_rest#${m_z1}}
+		m_rest=${m_rest#[.-]}
+		m_z2=${m_rest%%[.-]*}
+
+		# minor/major/patch should be numeric
+		[ -n "${m_major##*[!0-9]*}" ] || continue
+		[ -n "${m_minor##*[!0-9]*}" ] || continue
+		[ -n "${m_patch##*[!0-9]*}" ] || continue
+		# reset z1/z2 to zero if non-numeric
+		[ -n "${m_y##*[!0-9]*}" ] && cmp_type=y || m_y=0
+		[ -n "${m_z1##*[!0-9]*}" ] && cmp_type=z || m_z1=0
+		[ -n "${m_z2##*[!0-9]*}" ] && cmp_type=z || m_z2=0
+
+		# Comparing versions
+		case "$cmp_type" in
+		upstream)
+			[ "$t_major" -ge "$m_major" ] || continue
+			[ "$t_minor" -ge "$m_minor" ] || continue
+			[ "$t_patch" -ge "$m_patch" ] || continue
+			return 0
+			;;
+		y)
+			[ "$t_major" -eq "$m_major" ] || continue
+			[ "$t_minor" -eq "$m_minor" ] || continue
+			[ "$t_patch" -eq "$m_patch" ] || continue
+			[ "$t_y" -ge "$m_y" ] || continue
+			return 0
+			;;
+		z)
+			[ "$t_major" -eq "$m_major" ] || continue
+			[ "$t_minor" -eq "$m_minor" ] || continue
+			[ "$t_patch" -eq "$m_patch" ] || continue
+			[ "$t_y" -eq "$m_y" ] || continue
+			[ "$t_z1" -ge "$m_z1" ] || continue
+			[ "$t_z2" -ge "$m_z2" ] || continue
+			return 0
+			;;
+		esac
+	done
+
+	return 1
+}
+
+# Provides model in format "VENDOR_ID FAMILY-MODEL-STEPPING"
+#
+# We check only the first processor as we don't expect non-symmetrical setups
+# with CPUs with caveats
+get_model_string()
+{
+	/usr/bin/printf "%s %02x-%02x-%02x" \
+		$(/bin/sed -rn '1,/^$/{
+			s/^vendor_id[[:space:]]*: (.*)$/\1/p;
+			s/^cpu family[[:space:]]*: (.*)$/\1/p;
+			s/^model[[:space:]]*: (.*)$/\1/p;
+			s/^stepping[[:space:]]*: (.*)$/\1/p;
+		}' /proc/cpuinfo)
+}
+
+get_model_name()
+{
+	/bin/sed -rn '1,/^$/s/^model name[[:space:]]*: (.*)$/\1/p' /proc/cpuinfo
+}
+
+#check_kver "$@"
+#get_model_name
+
+match_model=0
+configs=
+kver=$(/bin/uname -r)
+verbose=0
+
+while getopts "k:c:mv" opt; do
+	case "${opt}" in
+	k)
+		kver="$OPTARG"
+		;;
+	c)
+		configs="$configs $OPTARG"
+		;;
+	m)
+		match_model=1
+		;;
+	v)
+		verbose=1
+		;;
+	*)
+		usage
+		exit 1;
+		;;
+	esac
+done
+
+: ${configs:=$(find "${MC_CAVEATS_DATA_DIR}" -maxdepth 1 -mindepth 1 -type d -printf "%f\n")}
+
+cpu_model=$(get_model_string)
+cpu_model_name=$(get_model_name)
+
+for cfg in $(echo "${configs}"); do
+	dir="$MC_CAVEATS_DATA_DIR/$cfg"
+	[ -r "${dir}/config" ] || {
+		debug "File 'config' in ${dir} is not found, skipping"
+		continue
+	}
+
+	cfg_model=
+	cfg_path=
+	cfg_kvers=
+	cfg_blacklist=
+
+	while read -r key value; do
+		case "$key" in
+		model)
+			cfg_model="$value"
+			;;
+		path)
+			cfg_path="$cfg_path $value"
+			;;
+		kernel)
+			cfg_kvers="$cfg_kvers $value"
+			;;
+		blacklist)
+			cfg_blacklist=1
+			break
+			;;
+		esac
+	done < "${dir}/config"
+
+	[ -z "${cfg_blacklist}" ] || \
+		cfg_blacklist=$(/bin/sed -n '/^blacklist$/,$p' "${dir}/config" |
+					/usr/bin/tail -n +2)
+
+	debug "${cfg}: model '$cfg_model', path '$cfg_path', kvers '$cfg_kvers'"
+	debug "${cfg}: blacklist '$cfg_blacklist'"
+
+	if [ -n "$cfg_model" ]; then
+		[ 0 -eq "$match_model" ] || {
+			[ "x$cpu_model" = "x$cfg_model" ] || {
+				debug "Current CPU model '$cpu_model' doesn't" \
+				      "match config CPU model '$cfg_model'," \
+				      "skipping"
+				continue
+			}
+		}
+	fi
+
+	if [ -n "$cfg_kvers" ]; then
+		check_kver "$kver" $cfg_kvers || {
+			debug "${cfg}: kernel version check for '$kver'" \
+			      "against '$cfg_kvers' failed"
+			exit 1
+		}
+	fi
+
+	if [ -n "$cfg_blacklist" ]; then
+		echo "$cfg_blacklist" | /bin/grep -vqFx "${cpu_model_name}" || {
+			debug "${cfg}: model '${cpu_model_name}' is blacklisted"
+			exit 1
+		}
+	fi
+
+	#printf "%s " "$cfg"
+	#[ 0 -eq "$match_model" ] || printf "%s " "$cpu_model"
+	echo $cfg_path
+done
+
+exit 0
diff --git a/SOURCES/dracut_99microcode_ctl-fw_dir_override_module_init.sh b/SOURCES/dracut_99microcode_ctl-fw_dir_override_module_init.sh
new file mode 100755
index 0000000..200548c
--- /dev/null
+++ b/SOURCES/dracut_99microcode_ctl-fw_dir_override_module_init.sh
@@ -0,0 +1,79 @@
+#!/bin/bash
+
+# Hack in kernel-specific firmware directory so it can be processed along with
+# the dracut default ones.  Note that upstream dracut currently has defaults
+# that include kernel-version-specific directories (dracut commit
+# 041-100-gb52cfbea).
+#
+# SPDX-License-Identifier: CC0-1.0
+
+check() {
+	return 0
+}
+
+DATA_DIR=/usr/share/microcode_ctl/ucode_with_caveats
+check_caveats=/usr/libexec/microcode_ctl/check_caveats
+
+install() {
+	verbose_opt=
+	[ 4 -gt "$stdloglvl" ] || verbose_opt="-v"
+
+	# HACK: we override external fw_dir variable in order to get
+	#       an additional ucode based on the kernel version.
+	dinfo "  microcode_ctl module: hacking fw_dir"
+
+	[ -z "$fw_dir_l" ] || {
+		dinfo "    microcode_ctl module: avoid touching fw_dir as" \
+		      "it has been changed (fw_dir_l is '$fw_dir_l')"
+
+		return 0
+	}
+
+	ucode=$(get_ucode_file)
+
+	for i in $(ls "$DATA_DIR"); do
+		dinfo "    microcode_ctl: processing data directory " \
+		      "\"$DATA_DIR/$i\"..."
+		[ -e "$DATA_DIR/$i/readme" ] || {
+			dinfo "      microcode_ctl: skipping \"$i\": no readme"
+			continue
+		}
+		[ -e "$DATA_DIR/$i/config" ] || {
+			dinfo "    microcode_ctl: skipping \"$i\": no config"
+			continue
+		}
+		[ ! -e "/etc/microcode_ctl/ucode_with_caveats/disallow-$i" ] || {
+			dinfo "    microcode_ctl: skipping \"$i\":" \
+			      "\"/etc/microcode_ctl/ucode_with_caveats/disallow-$i\"" \
+			      "present"
+			continue
+		}
+		path=$($check_caveats -k "$kernel" -c "$i")
+                fname=$(basename "$path")
+
+		if [ "x" != "x$hostonly" ]; then
+			[ "x$ucode" = "x$fname" ] || {
+				dinfo "    microcode_ctl: Host-Only mode" \
+                                      "is enabled and ucode name does not" \
+                                      "match the expected one" \
+                                      "(\"$ucode\" != \"$fname\")"
+				continue
+			}
+		fi
+
+		dinfo "    microcode_ctl: processing file \"$path\""
+		if $check_caveats -k "$kernel" -c "$i" $verbose_opt > /dev/null
+		then
+			dinfo "      microcode_ctl: caveats check for kernel" \
+			      "version \"$kernel\" passed, adding" \
+			      "\"/lib/firmware/$kernel\" to fw_dir variable"
+			fw_dir="/lib/firmware/$kernel $fw_dir"
+			break
+		else
+			dinfo "      microcode_ctl: kernel version \"$kernel\"" \
+			      "failed caveats check, skipping"
+			continue
+		fi
+	done
+}
+
diff --git a/SOURCES/microcode.service b/SOURCES/microcode.service
index 09f542d..a96138f 100644
--- a/SOURCES/microcode.service
+++ b/SOURCES/microcode.service
@@ -7,6 +7,6 @@ ConditionPathExists=/sys/devices/system/cpu/microcode/reload
 [Service]
 Type=oneshot
 RemainAfterExit=no
-ExecStart=/usr/bin/bash -c 'grep -l GenuineIntel /proc/cpuinfo | xargs grep -l -E "model[[:space:]]*: 79$" > /dev/null || echo 1 > /sys/devices/system/cpu/microcode/reload'
+ExecStart=/usr/libexec/microcode_ctl/reload_microcode
 [Install]
 WantedBy=basic.target
diff --git a/SOURCES/reload_microcode b/SOURCES/reload_microcode
new file mode 100644
index 0000000..62fb43e
--- /dev/null
+++ b/SOURCES/reload_microcode
@@ -0,0 +1,13 @@
+#! /bin/bash -efu
+
+# Trigger microcode reload with additional check for BDW-EP that can have
+# microcode reloaded only in case kernel has specific patches.
+#
+# SPDX-License-Identifier: CC0-1.0
+
+CHECK_CAVEATS=/usr/libexec/microcode_ctl/check_caveats
+trigger=1
+
+"$CHECK_CAVEATS" -m > /dev/null || trigger=0
+
+[ 0 -eq "$trigger" ] || echo 2>/dev/null 1 > /sys/devices/system/cpu/microcode/reload || true
diff --git a/SOURCES/update_ucode b/SOURCES/update_ucode
new file mode 100644
index 0000000..df8033f
--- /dev/null
+++ b/SOURCES/update_ucode
@@ -0,0 +1,256 @@
+#! /bin/bash -eu
+
+# Maintain kernel-version-specific symlinks in /lib/firmware based on
+# configuration present in /usr/share/microcode_ctl/ucode_with_caveats.
+#
+# SPDX-License-Identifier: CC0-1.0
+
+usage()
+{
+	echo "Usage: update_ucode [--action {add|remove|refresh}]" \
+	     "[--kernel KERNELVER]* [--verbose] [--dry-run]" \
+	     "[--trigger-dracut] [--cleanup intel_ucode caveats_ucode]" >&2
+}
+
+debug() { [ 0 = "$verbose" ] || echo "$*" >&2; }
+
+MC_DIR=/usr/share/microcode_ctl
+INTEL_UCODE_DIR=intel-ucode
+DATA_DIR=/usr/share/microcode_ctl/ucode_with_caveats
+FW_DIR=/lib/firmware
+check_caveats=/usr/libexec/microcode_ctl/check_caveats
+
+action=refresh
+kernel=
+verbose=0
+verbose_opt=
+dry_run=0
+trigger_dracut=0
+remove_cleanup=0
+cleanup_intel=
+cleanup_caveats=
+
+while [ 1 -le "$#" ]; do
+	case "$1" in
+	-a|--action)
+		shift
+		action="$1"
+		;;
+	-k|--kernel)
+		shift
+		kernel="$kernel $1"
+		;;
+	-v|--verbose)
+		verbose=1
+		verbose_opt="-v"
+		;;
+	-n|--dry-run)
+		dry_run=1
+		;;
+	-d|--trigger-dracut)
+		trigger_dracut=1
+		;;
+	-c|--cleanup)
+		remove_cleanup=1
+		shift
+		cleanup_intel="$1"
+		shift
+		cleanup_caveats="$1"
+		;;
+	*)
+		echo "Unknown argument \"$1\"" >&2
+		usage
+		exit 1
+	esac
+	shift
+done
+
+cmd=
+[ 0 -eq "$dry_run" ] || cmd=echo
+
+case "$action" in
+add|remove|refresh)
+	# Scan all directories in FW_DIR and all existing kernels
+	if [ -z "$kernel" ]; then
+		debug "No kernel versions provided, scanning..."
+
+		kvers=$(find /lib/modules/ -name '[2-9].*' -print)
+		for k_dir in $kvers; do
+			k="${k_dir#/lib/modules/}"
+			[ ! -e "/boot/symvers-$k.gz" ] || {
+				debug "  Adding $k (from /lib/modules)"
+				kernel="$kernel $k"
+			}
+		done
+
+		kvers=$(find /lib/firmware/ -name '[2-9].*' -print)
+		for k_dir in $kvers; do
+			k="${k_dir#/lib/firmware/}"
+			[ ! -d "$k_dir" ] || {
+				debug "  Adding $k (from /lib/firmware)"
+				kernel="$kernel $k"
+			}
+		done
+	fi
+	;;
+*)
+	echo "Unknown action \"$action\"" >&2
+	usage
+	exit 1
+	;;
+esac
+
+# Generic part: managing intel ucode
+debug "Running action \"$action\" on common Intel microcode directory"
+while :; do
+	[ ! -e "/etc/microcode_ctl/intel-ucode-disallow" ] || {
+		debug "  Skipping \"$i\":" \
+		      "\"/etc/microcode_ctl/intel-ucode-disallow\"" \
+		      "present"
+		break
+	}
+	[ ! -e "$FW_DIR/intel-ucode-disallow" ] || {
+		debug "  Found \"$FW_DIR/intel-ucode-disallow\"," \
+		      "skipping"
+		break
+	}
+
+	# Removing old files
+	case "$action" in
+	refresh|remove)
+		debug "  Removing old files from ${MC_DIR}/${INTEL_UCODE_DIR}"
+		if [ 0 = "$remove_cleanup" ]; then
+			find "${MC_DIR}/${INTEL_UCODE_DIR}" \
+				-maxdepth 1 -mindepth 1 \
+				-type f -printf '%f\n'
+		else
+			cat "$cleanup_intel"
+		fi | while read -r fname; do
+			name="${FW_DIR}/${INTEL_UCODE_DIR}/${fname}"
+
+			# Needed in case we downgrade to a version where
+			# no symlinks in /lib/firmware were used
+			if [ 1 = "$remove_cleanup" ]; then
+				[ -L "$name" ] || continue
+			fi
+
+			$cmd rm -f $verbose_opt "$name"
+		done
+		$cmd rmdir -p $verbose_opt "${FW_DIR}/${INTEL_UCODE_DIR}" 2>/dev/null || true
+		;;
+	esac
+
+	# Adding new ones
+	case "$action" in
+	add|refresh)
+		if grep -q '^flags[[:space:]]*:.*hypervisor' /proc/cpuinfo; then
+			debug "  A virtualised environment has been detected" \
+			      "(hypervisor flag is present in /proc/cpuinfo)," \
+			      "skipping"
+			break
+		fi
+
+		debug "  Creating symlinks in ${MC_DIR}/${INTEL_UCODE_DIR}"
+		$cmd mkdir -p $verbose_opt "${FW_DIR}/${INTEL_UCODE_DIR}"
+		$cmd find "${MC_DIR}/${INTEL_UCODE_DIR}" -maxdepth 1 -mindepth 1 \
+			-type f -exec bash -c 'ln -s '"$verbose_opt"' '\''{}'\'' \
+				"'"${FW_DIR}/${INTEL_UCODE_DIR}/"'$(basename '\''{}'\'')"' \;
+		;;
+	esac
+
+	break
+done
+
+debug "Running action \"$action\" on kernels $kernel"
+
+if [ 0 = "$remove_cleanup" ]; then
+	ls "$DATA_DIR"
+else
+	cat "$cleanup_caveats"
+fi | while read -r i; do
+	debug "Processing data directory \"$i\"..."
+	[ -e "$DATA_DIR/$i/readme" ] || {
+		debug "  Skipping \"$i\": no readme"
+		continue
+	}
+	[ -e "$DATA_DIR/$i/config" ] || {
+		debug "  Skipping \"$i\": no config"
+		continue
+	}
+	[ ! -e "/etc/microcode_ctl/ucode_with_caveats/disallow-$i" ] || {
+		debug "  Skipping \"$i\":" \
+		      "\"/etc/microcode_ctl/ucode_with_caveats/disallow-$i\"" \
+		      "present"
+		continue
+	}
+
+	for k in $(echo "$kernel"); do
+		debug "    Processing kernel version \"$k\""
+		$check_caveats -k "$k" -c "$i" $verbose_opt > /dev/null || {
+			debug "    Checking for caveats failed" \
+			      "(kernel version \"$k\"), skipping"
+			continue
+		}
+		path=$($check_caveats -k "$k" -c "$i")
+
+		case "$action" in
+		remove|refresh)
+			debug "    Removing $path (part of $action)..."
+
+			if [ -e "$FW_DIR/$k/readme-$i" ]; then
+				debug "      Removing \"$FW_DIR/$k/$path\""
+				$cmd rm -f $verbose_opt "$FW_DIR/$k/$path"
+				$cmd rm -f $verbose_opt "$FW_DIR/$k/readme-$i"
+				$cmd rmdir -p $verbose_opt "$(dirname "$FW_DIR/$k/$path")" 2>/dev/null || true
+
+				[ 0 -eq "$trigger_dracut" ] || {
+					debug "      Triggering dracut for kernel \"$k\""
+					$cmd dracut -f $verbose_opt --kver "$k"
+				}
+			else
+				debug "      \"$FW_DIR/$k/readme-$i\" is not found," \
+				      "skipping \"$FW_DIR/$k/$path\" removal"
+			fi
+			;;
+		esac
+
+		case "$action" in
+		add|refresh)
+			debug "    Adding $path (part of $action)..."
+
+			[ -e "/boot/symvers-$k.gz" ] || {
+				debug "      \"/boot/symvers-$k.gz\"" \
+				      "does not exist, skipping"
+				continue
+			}
+			if grep -q '^flags[[:space:]]*:.*hypervisor' /proc/cpuinfo; then
+				debug "      A virtualised environment has been detected" \
+				      "(hypervisor flag is present in /proc/cpuinfo)," \
+				      "skipping"
+				break
+			fi
+			[ ! -e "$FW_DIR/$k/disallow-$i" ] || {
+				debug "      Found \"$FW_DIR/$k/disallow-$i\"," \
+				      "skipping"
+				continue
+			}
+			[ ! -e "$FW_DIR/$k/$path" ] || {
+				debug "      \"$FW_DIR/$k/$path\" already exists," \
+				      "skipping"
+				continue
+			}
+
+			debug "      Adding \"$FW_DIR/$k/$path\""
+			$cmd mkdir -p "$(dirname "$FW_DIR/$k/$path")"
+			$cmd ln -s "$DATA_DIR/$i/$path" "$FW_DIR/$k/$path"
+			$cmd cp "$DATA_DIR/$i/readme" "$FW_DIR/$k/readme-$i"
+
+			[ 0 -eq "$trigger_dracut" ] || {
+				debug "      Triggering dracut for kernel \"$k\""
+				$cmd dracut -f $verbose_opt --kver "$k"
+			}
+			;;
+		remove)
+		esac
+	done
+done
diff --git a/SPECS/microcode_ctl.spec b/SPECS/microcode_ctl.spec
index fbdeb12..102109d 100644
--- a/SPECS/microcode_ctl.spec
+++ b/SPECS/microcode_ctl.spec
@@ -1,17 +1,28 @@
-%define upstream_version 2.1-20180425
+%define upstream_version 2.1-20180703
+%define microcode_ctl_libexec /usr/libexec/microcode_ctl
+%define update_ucode %{microcode_ctl_libexec}/update_ucode
+%define check_caveats %{microcode_ctl_libexec}/check_caveats
+%define reload_microcode %{microcode_ctl_libexec}/reload_microcode
 
 Summary:        Tool to transform and deploy CPU microcode update for x86.
 Name:           microcode_ctl
 Version:        2.1
-Release:        29.2%{?dist}
+Release:        29.10%{?dist}
 Epoch:          2
 Group:          System Environment/Base
 License:        GPLv2+ and Redistributable, no modification permitted
 URL:            https://pagure.io/microcode_ctl
-Source0:        https://releases.pagure.org/microcode_ctl/%{name}-%{upstream_version}.tar.xz
+Source0:        %{name}-%{upstream_version}.tar.xz
 Source1:        microcode.service
 Source2:        01-microcode.conf
 Source3:        disclaimer
+Source4:        update_ucode
+Source5:        check_caveats
+Source6:        reload_microcode
+Source7:        dracut_99microcode_ctl-fw_dir_override_module_init.sh
+Source8:        06-4f-01_readme
+Source9:        06-4f-01_config
+
 Buildroot:      %{_tmppath}/%{name}-%{version}-root
 ExclusiveArch:  %{ix86} x86_64
 BuildRequires:  systemd-units
@@ -34,9 +45,11 @@ back to the old microcode.
 %build
 make CFLAGS="$RPM_OPT_FLAGS" %{?_smp_mflags}
 
+find intel-ucode -type f | sed 's/^/%%ghost \/lib\/firmware\//' > ghost_list
+
 %install
 rm -rf %{buildroot}
-make DESTDIR=%{buildroot} PREFIX=%{_prefix} INSDIR=/usr/sbin install clean
+make DESTDIR=%{buildroot} PREFIX=%{_prefix} INSDIR=/usr/sbin MICDIR=/usr/share/microcode_ctl install clean
 
 mkdir -p %{buildroot}/usr/lib/dracut/dracut.conf.d
 mkdir -p %{buildroot}%{_unitdir}
@@ -44,16 +57,32 @@ install -m 644 %{SOURCE1} %{buildroot}%{_unitdir}
 install -m 644 %{SOURCE2} %{buildroot}/usr/lib/dracut/dracut.conf.d
 install -m 644 %{SOURCE3} %{buildroot}/usr/share/doc/microcode_ctl/disclaimer
 
+mkdir -p %{buildroot}/%{microcode_ctl_libexec}
+install -m 755 %{SOURCE4} %{buildroot}/%{update_ucode}
+install -m 755 %{SOURCE5} %{buildroot}/%{check_caveats}
+install -m 755 %{SOURCE6} %{buildroot}/%{reload_microcode}
+
+mkdir -p "%{buildroot}/usr/lib/dracut/modules.d/99microcode_ctl-fw_dir_override"
+install -m 755 %{SOURCE7} %{buildroot}/usr/lib/dracut/modules.d/99microcode_ctl-fw_dir_override/module-setup.sh
+
+mkdir -p "%{buildroot}/usr/share/microcode_ctl/ucode_with_caveats/intel-06-4f-01/intel-ucode"
+install -m 644 intel-ucode-with-caveats/06-4f-01 %{buildroot}/usr/share/microcode_ctl/ucode_with_caveats/intel-06-4f-01/intel-ucode/06-4f-01
+install -m 644 %{SOURCE8} %{buildroot}/usr/share/microcode_ctl/ucode_with_caveats/intel-06-4f-01/readme
+install -m 644 %{SOURCE9} %{buildroot}/usr/share/microcode_ctl/ucode_with_caveats/intel-06-4f-01/config
+
+rm -f intel-ucode-with-caveats/06-4f-01
+rmdir intel-ucode-with-caveats
+
 %post
 %systemd_post microcode.service
+%{update_ucode}
 # "reload" file is not presented on a certain virtualized hw
 if [ -w /sys/devices/system/cpu/microcode/reload ] ; then
-	grep -l GenuineIntel /proc/cpuinfo | xargs grep -l -E "model[[:space:]]*: 79$" > /dev/null || \
-	echo 1 > /sys/devices/system/cpu/microcode/reload
+	%{reload_microcode}
 fi
 # send the message to syslog, so it gets recorded on /var/log
 if [ -e /usr/bin/logger ]; then
-        /usr/bin/logger -p syslog.notice -t DISCLAIMER -f /usr/share/doc/microcode_ctl/disclaimer
+	/usr/bin/logger -p syslog.notice -t DISCLAIMER -f /usr/share/doc/microcode_ctl/disclaimer
 fi
 # also paste it over dmesg (some customers drop dmesg messages while
 # others keep them into /var/log for the later case, we'll have the
@@ -73,21 +102,97 @@ fi
 %preun
 %systemd_preun microcode.service
 
+# Storing ucode list before uninstall
+ls /usr/share/microcode_ctl/intel-ucode |
+	sort > "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_intel-ucode"
+ls /usr/share/microcode_ctl/ucode_with_caveats |
+	sort > "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_ucode_caveats"
+
 %postun
 %systemd_postun microcode.service
 
+ls /usr/share/microcode_ctl/intel-ucode 2> /dev/null |
+	sort > "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_intel-ucode_after"
+ls /usr/share/microcode_ctl/ucode_with_caveats 2> /dev/null |
+	sort > "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_ucode_caveats_after"
+
+comm -23 \
+	"%{_localstatedir}/lib/rpm-state/microcode_ctl_un_intel-ucode" \
+	"%{_localstatedir}/lib/rpm-state/microcode_ctl_un_intel-ucode_after" \
+	> "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_intel-ucode_diff"
+
+comm -23 \
+	"%{_localstatedir}/lib/rpm-state/microcode_ctl_un_ucode_caveats" \
+	"%{_localstatedir}/lib/rpm-state/microcode_ctl_un_ucode_caveats_after" \
+	> "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_ucode_caveats_diff"
+
+if [ -e "%{update_ucode}" ]; then
+	%{update_ucode} --action remove --cleanup \
+		"%{_localstatedir}/lib/rpm-state/microcode_ctl_un_intel-ucode_diff" \
+		"%{_localstatedir}/lib/rpm-state/microcode_ctl_un_ucode_caveats_diff" || exit 0
+else
+	while read f; do
+		[ -L "/lib/firmware/intel-ucode/$f" ] || continue
+		rm -f "/lib/firmware/intel-ucode/$f"
+	done < "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_intel-ucode_diff"
+fi
+
+rm -f "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_intel-ucode"
+rm -f "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_ucode_caveats"
+
+rm -f "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_intel-ucode_after"
+rm -f "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_ucode_caveats_after"
+
+rm -f "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_intel-ucode_diff"
+rm -f "%{_localstatedir}/lib/rpm-state/microcode_ctl_un_ucode_caveats_diff"
+
+%triggerin -- kernel
+%{update_ucode}
+
+%triggerpostun -- kernel
+%{update_ucode}
+
+
 %clean
 rm -rf %{buildroot}
 
-%files
+%files -f ghost_list
+%ghost %attr(0100755, root, root) /lib/firmware/intel-ucode/
 /usr/sbin/intel-microcode2ucode
-/lib/firmware/*
+%{microcode_ctl_libexec}
+/usr/share/microcode_ctl
+/usr/lib/dracut/modules.d/99microcode_ctl-fw_dir_override
 %config(noreplace) /usr/lib/dracut/dracut.conf.d/01-microcode.conf
 %{_unitdir}/microcode.service
 %doc /usr/share/doc/microcode_ctl/*
 
 
 %changelog
+* Fri Jul 27 2018 Eugene Syromiatnikov <esyr@redhat.com> - 2:2.1-29.10
+- Provide %attr for the ghosted /lib/firmware.
+
+* Thu Jul 26 2018 Eugene Syromiatnikov <esyr@redhat.com> - 2:2.1-29.9
+- Remove model name blacklists from caveats configuration files.
+
+* Tue Jul 24 2018 Eugene Syromiatnikov <esyr@redhat.com> - 2.1-29.8
+- Add model name blacklist infrastructure.
+- Store Intel ucode files in /usr/share/microcode_ctl; do not populate them
+  in a virtualised environment.
+- Resolves: #1576334
+
+* Tue Jul 17 2018 Eugene Syromiatnikov <esyr@redhat.com> - 2.1-29.7
+- Add infrastructure for handling kernel-version-dependant microcode.
+- Resolves: #1576334
+
+* Mon Jul 16 2018 Eugene Syromiatnikov <esyr@redhat.com> - 2.1-29.4
+- Intel CPU microcode update to 20180703.
+- Resolves: #1573456
+
+* Wed Jun 13 2018 Petr Oros <poros@redhat.com> - 2.1-29.3
+- Fix: Operation not permitted when installing microcode_ctl
+- CVE-2018-3639 hw: cpu: speculative store bypass
+- Resolves: #1573456
+
 * Tue May 15 2018 Petr Oros <poros@redhat.com> - 2.1-29.2
 - Update disclaimer text
 - Resolves: #1575570