Compare commits

...

2 Commits

Author SHA1 Message Date
eabdullin bded3e6ca0 Import from AlmaLinux stable repository 2024-05-31 17:52:15 +00:00
eabdullin d673e93116 import EuroLinux linux-firmware-20230824-120.git0e048b06.el8_9 2024-02-09 09:27:04 +00:00
4 changed files with 25 additions and 393 deletions

2
.gitignore vendored
View File

@ -1 +1 @@
SOURCES/linux-firmware-20230824.tar.xz
SOURCES/linux-firmware-20240111.tar.xz

View File

@ -1 +0,0 @@
074c0923c1a85e1ea5843bf77d5e88d2da87522b SOURCES/linux-firmware-20230824.tar.xz

View File

@ -1,374 +0,0 @@
#!/usr/bin/python3
# SPDX-License-Identifier: MIT License
# Copyright (C) 2020 Advanced Micro Devices, Inc.
"""
Parse an amd-ucode container file and print the family, model, stepping number,
and patch level for each patch in the file. The --extract option will dump the
raw microcode patches to a provided directory.
"""
import argparse
import sys
import os
from collections import namedtuple
from collections import OrderedDict
EQ_TABLE_ENTRY_SIZE = 16
EQ_TABLE_LEN_OFFSET = 8
EQ_TABLE_OFFSET = 12
EQ_TABLE_TYPE = 0
PATCH_TYPE = 1
VERBOSE_DEBUG = 2
FMS = namedtuple("FMS", ("family", "model", "stepping"))
EquivTableEntry = namedtuple("EquivTableEntry", ("cpuid", "equiv_id", "data", "offset"))
PatchEntry = namedtuple("PatchEntry", ("file", "offset", "size", "equiv_id", "level"))
def read_int32(ucode_file):
""" Read four bytes of binary data and return as a 32 bit int """
return int.from_bytes(ucode_file.read(4), 'little')
def read_int16(ucode_file):
""" Read two bytes of binary data and return as a 16 bit int """
return int.from_bytes(ucode_file.read(2), 'little')
def read_int8(ucode_file):
""" Read one byte of binary data and return as a 8 bit int """
return int.from_bytes(ucode_file.read(1), 'little')
def cpuid2fms(cpu_id):
family = (cpu_id >> 8) & 0xf
family += (cpu_id >> 20) & 0xff
model = (cpu_id >> 4) & 0xf
model |= (cpu_id >> 12) & 0xf0
stepping = cpu_id & 0xf
return FMS(family, model, stepping)
def fms2str(fms):
return "Family=%#04x Model=%#04x Stepping=%#04x" % \
(fms.family, fms.model, fms.stepping)
def parse_equiv_table(opts, ucode_file, start_offset, eq_table_len):
"""
Read equivalence table and return a list of the equivalence ids contained
"""
table = {}
raw_table = []
# For sanity check only
cpuid_map = {}
table_item = start_offset + EQ_TABLE_OFFSET
table_stop = start_offset + EQ_TABLE_OFFSET + eq_table_len
while table_item < table_stop:
ucode_file.seek(table_item, 0)
data = ucode_file.read(EQ_TABLE_ENTRY_SIZE)
ucode_file.seek(table_item, 0)
cpu_id = read_int32(ucode_file)
if opts.verbose >= VERBOSE_DEBUG:
errata_mask = read_int32(ucode_file)
errata_compare = read_int32(ucode_file)
else:
# Skip errata mask and compare fields
ucode_file.seek(8, 1)
equiv_id = read_int16(ucode_file)
if opts.verbose >= VERBOSE_DEBUG:
res = read_int16(ucode_file)
if equiv_id != 0:
if equiv_id not in table:
table[equiv_id] = OrderedDict()
if cpu_id in table[equiv_id]:
print("WARNING: Duplicate CPUID %#010x (%s) in the equivalence table for equiv_id %#06x " %
(fms2str(cpuid2fms(cpu_id)), equiv_id))
if cpu_id in cpuid_map:
if equiv_id != cpuid_map[cpu_id]:
print("WARNING: Different equiv_id's (%#06x and %#06x) are present in the equivalence table for CPUID %#010x (%s)" %
(equiv_id, cpuid_map[cpu_id], cpu_id,
fms2str(cpuid2fms(cpu_id))))
else:
cpuid_map[cpu_id] = equiv_id
entry = EquivTableEntry(cpu_id, equiv_id, data, table_item)
table[equiv_id][cpu_id] = entry
raw_table.append(entry)
if opts.verbose >= VERBOSE_DEBUG:
print(" [equiv entry@%#010x: cpuid %#010x, equiv id %#06x, errata mask %#010x, errata compare %#010x, res %#06x]" %
(table_item, cpu_id, equiv_id, errata_mask, errata_compare, res))
table_item += EQ_TABLE_ENTRY_SIZE
return (table, raw_table)
def extract_patch(opts, out_dir, ucode_file, patch, equiv_table=None):
"""
Extract raw microcode patch starting at patch_start to the directory
provided by the -o option or the current directory if not specified.
Directory will be created if it doesn't already exist.
"""
cwd = os.getcwd()
if not os.path.exists(out_dir):
os.makedirs(out_dir)
os.chdir(out_dir)
if equiv_table is None:
# Raw patch
out_file_name = "mc_patch_0%x.bin" % patch.level
else:
out_file_name = "mc_equivid_%#06x" % patch.equiv_id
for cpuid in equiv_table[patch.equiv_id]:
out_file_name += '_cpuid_%#010x' % cpuid
out_file_name += "_patch_%#010x.bin" % patch.level
out_path = "%s/%s" % (os.getcwd(), out_file_name)
out_file = open(out_file_name, "wb")
os.chdir(cwd)
if equiv_table is not None:
cpuids = equiv_table[patch.equiv_id].values() if patch.equiv_id in equiv_table else []
else:
cpuids = None
write_mc(opts, out_file, [patch], ucode_file, cpuids)
out_file.close()
print(" Patch extracted to %s" % out_path)
def merge_mc(opts, out_path, table, patches):
# Do some sanity checks, ut only warn about the issues
equivid_map = {}
cpuid_map = {}
for entry in table:
if entry.equiv_id not in equivid_map:
equivid_map[entry.equiv_id] = dict()
if entry.cpuid in equivid_map[entry.equiv_id]:
print("WARNING: Duplicate CPUID %#010x (%s) in the equivalence table for equiv_id %#06x " %
(fms2str(cpuid2fms(entry.cpuid)), entry.equiv_id))
else:
equivid_map[entry.equiv_id][entry.cpuid] = entry
if entry.cpuid in cpuid_map:
if entry.equiv_id != cpuid_map[entry.cpuid]:
print("WARNING: Different equiv_id's (%#06x and %#06x) are present in the equivalence table for CPUID %#010x (%s)" %
(entry.equiv_id, cpuid_map[entry.cpuid], entry.cpuid,
fms2str(cpuid2fms(entry.cpuid))))
else:
cpuid_map[entry.cpuid] = entry.equiv_id
with open(out_path, "wb") as out_file:
write_mc(opts, out_file, patches, equiv_table=table)
print("Microcode written to %s" % out_path)
def write_mc(opts, out_file, patches, ucode_file=None, equiv_table=None):
"""
Writes microcode data to the specified file.
"""
if equiv_table is not None:
# Container header
out_file.write(b'DMA\x00')
# Equivalence table header
out_file.write(EQ_TABLE_TYPE.to_bytes(4, 'little'))
table_size = EQ_TABLE_ENTRY_SIZE * (len(equiv_table) + 1)
out_file.write(table_size.to_bytes(4, 'little'))
# Equivalence table
for cpuid in equiv_table:
out_file.write(cpuid.data)
out_file.write(b'\0' * EQ_TABLE_ENTRY_SIZE)
for patch in patches:
# Patch header
if equiv_table is not None:
out_file.write(PATCH_TYPE.to_bytes(4, 'little'))
out_file.write(patch.size.to_bytes(4, 'little'))
if ucode_file is None:
in_file = open(patch.file, "rb")
else:
in_file = ucode_file
in_file.seek(patch.offset, 0)
out_file.write(in_file.read(patch.size))
if ucode_file is None:
in_file.close()
def parse_ucode_file(opts, path, start_offset):
"""
Scan through microcode container file printing the microcode patch level
for each model contained in the file.
"""
table = None
patches = []
with open(path, "rb") as ucode_file:
print("Microcode patches in %s%s:" %
(path, "+%#x" % start_offset if start_offset else ""))
# Seek to end of file to determine file size
ucode_file.seek(0, 2)
end_of_file = ucode_file.tell()
# Check magic number
ucode_file.seek(start_offset, 0)
if ucode_file.read(4) != b'DMA\x00':
print("ERROR: Missing magic number at beginning of container")
return (None, None, None)
# Check the equivalence table type
eq_table_type = read_int32(ucode_file)
if eq_table_type != EQ_TABLE_TYPE:
print("ERROR: Invalid equivalence table identifier: %#010x" %
eq_table_type)
return (None, None, None)
# Read the equivalence table length
eq_table_len = read_int32(ucode_file)
ids, table = parse_equiv_table(opts, ucode_file, start_offset, eq_table_len)
cursor = start_offset + EQ_TABLE_OFFSET + eq_table_len
while cursor < end_of_file:
# Seek to the start of the patch information
ucode_file.seek(cursor, 0)
patch_start = cursor + 8
patch_type_bytes = ucode_file.read(4)
# Beginning of a new container
if patch_type_bytes == b'DMA\x00':
return (cursor, table, patches)
patch_type = int.from_bytes(patch_type_bytes, 'little')
if patch_type != PATCH_TYPE:
print("Invalid patch identifier: %#010x" % (patch_type))
return (None, table, patches)
patch_length = read_int32(ucode_file)
if opts.verbose:
data_code = read_int32(ucode_file)
else:
ucode_file.seek(4, 1)
ucode_level = read_int32(ucode_file)
if opts.verbose >= VERBOSE_DEBUG:
mc_patch_data_id = read_int16(ucode_file)
mc_patch_data_len = read_int8(ucode_file)
init_flag = read_int8(ucode_file)
mc_patch_data_checksum = read_int32(ucode_file)
nb_dev_id = read_int32(ucode_file)
sb_dev_id = read_int32(ucode_file)
else:
ucode_file.seek(16, 1)
equiv_id = read_int16(ucode_file)
if opts.verbose >= VERBOSE_DEBUG:
nb_rev_id = read_int8(ucode_file)
sb_rev_id = read_int8(ucode_file)
bios_api_rev = read_int8(ucode_file)
reserved1 = [read_int8(ucode_file) for _ in range(3)]
match_reg = [read_int32(ucode_file) for _ in range(8)]
if opts.verbose:
add_info = " Start=%u bytes Date=%04x-%02x-%02x Equiv_id=%#06x" % \
(patch_start, data_code & 0xffff, data_code >> 24,
(data_code >> 16) & 0xff, equiv_id)
else:
add_info = ""
if equiv_id not in ids:
print("Patch equivalence id not present in equivalence table (%#06x)"
% (equiv_id))
print(" Family=???? Model=???? Stepping=????: Patch=%#010x Length=%u bytes%s"
% (ucode_level, patch_length, add_info))
# The cpu_id is the equivalent to CPUID_Fn00000001_EAX
for cpuid in ids[equiv_id]:
print(" %s: Patch=%#010x Length=%u bytes%s"
% (fms2str(cpuid2fms(cpuid)), ucode_level, patch_length, add_info))
if opts.verbose >= VERBOSE_DEBUG:
print(" [data_code=%#010x, mc_patch_data_id=%#06x, mc_patch_data_len=%#04x, init_flag=%#04x, mc_patch_data_checksum=%#010x]" %
(data_code, mc_patch_data_id, mc_patch_data_len, init_flag, mc_patch_data_checksum))
print(" [nb_dev_id=%#010x, sb_dev_id=%#010x, nb_rev_id=%#04x, sb_rev_id=%#04x, bios_api_rev=%#04x, reserved=[%#04x, %#04x, %#04x]]" %
(nb_dev_id, sb_dev_id, nb_rev_id, sb_rev_id, bios_api_rev, reserved1[0], reserved1[1], reserved1[2]))
patch = PatchEntry(path, patch_start, patch_length, equiv_id, ucode_level)
patches.append(patch)
if opts.extract:
extract_patch(opts, opts.extract, ucode_file, patch)
if opts.split:
extract_patch(opts, opts.split, ucode_file, patch, ids)
cursor = cursor + patch_length + 8
return (None, table, patches)
def parse_ucode_files(opts):
all_tables = []
all_patches = []
for f in opts.container_file:
offset = 0
while offset is not None:
offset, table, patches = parse_ucode_file(opts, f, offset)
if opts.merge:
if table is not None:
all_tables += table
if patches is not None:
all_patches += patches
if opts.merge:
merge_mc(opts, opts.merge, all_tables, all_patches)
def parse_options():
""" Parse options """
parser = argparse.ArgumentParser(description="Print information about an amd-ucode container")
parser.add_argument("container_file", nargs='+')
parser.add_argument("-e", "--extract",
help="Dump each patch in container to the specified directory")
parser.add_argument("-s", "--split",
help="Split out each patch in a separate container to the specified directory")
parser.add_argument("-m", "--merge",
help="Write a merged container to the specified file")
parser.add_argument("-v", "--verbose", action="count", default=0,
help="Be verbose about the information in the container file")
opts = parser.parse_args()
for f in opts.container_file:
if not os.path.isfile(f):
parser.print_help()
print()
print("ERROR: Container file \"%s\" does not exist" % f)
sys.exit()
return opts
def main():
""" main """
opts = parse_options()
parse_ucode_files(opts)
if __name__ == "__main__":
main()

View File

@ -1,12 +1,12 @@
%global checkout 0e048b06
%global checkout b3132c18
%global firmware_release 119
%global firmware_release 121
%global _firmwarepath /usr/lib/firmware
%define _binaries_in_noarch_packages_terminate_build 0
Name: linux-firmware
Version: 20230824
Version: 20240111
Release: %{firmware_release}.git%{checkout}%{?dist}
Summary: Firmware files used by the Linux kernel
License: GPL+ and GPLv2+ and MIT and Redistributable, no modification permitted
@ -18,7 +18,6 @@ BuildArch: noarch
# This is still causing problems in RHEL9 (see bug 1959913) and because of that we should keep out of RHEL8 too
# 2) git archive --worktree-attributes --format=tar --prefix=linux-firmware-%%{checkout}/ %%{checkout} | xz > linux-firmware-%%{version}.tar.xz
Source0: %{name}-%{version}.tar.xz
Source1: amd_ucode_info.py
Provides: kernel-firmware = %{version} xorg-x11-drv-ati-firmware = 7.0
Obsoletes: kernel-firmware < %{version} xorg-x11-drv-ati-firmware < 6.13.0-0.22
@ -42,7 +41,6 @@ Conflicts: microcode_ctl < 2.1-0
Obsoletes: ivtv-firmware < 2:20080701-28
BuildRequires: git make
BuildRequires: python3
%description
This package includes firmware files required for some devices to
@ -260,14 +258,6 @@ Firmware for Marvell Libertas SD 8787 Network Adapter
%prep
%setup -q -n linux-firmware-%{checkout}
# Repack AMD Family 19h microcode
/usr/bin/python3 %{SOURCE1} -vv -s amd-ucode/fam19 amd-ucode/microcode_amd_fam19h.bin
rm -rvf amd-ucode/fam19/*cpuid_0x00aa0f0*.bin
/usr/bin/python3 %{SOURCE1} -vv amd-ucode/fam19/* -m amd-ucode/microcode_amd_fam19h.bin
/usr/bin/python3 %{SOURCE1} -vv amd-ucode/microcode_amd_fam19h.bin
rm -rvf amd-ucode/fam19
%if 0
git init .
if [ -z "$GIT_COMMITTER_NAME" ]; then
@ -286,7 +276,8 @@ git am %{patches}
%install
mkdir -p $RPM_BUILD_ROOT/%{_firmwarepath}
mkdir -p $RPM_BUILD_ROOT/%{_firmwarepath}/updates
make DESTDIR=%{buildroot}/ FIRMWAREDIR=%{_firmwarepath} install
# copy-firmware.sh requires rdfind unless we pass --ignore-duplicates.
make DESTDIR=%{buildroot}/ FIRMWAREDIR=%{_firmwarepath} COPYOPTS="--ignore-duplicates" install
pushd $RPM_BUILD_ROOT/%{_firmwarepath}
# Remove firmware shipped in separate packages already
@ -411,6 +402,10 @@ sed -e 's/^/%%dir /' linux-firmware.dirs >> linux-firmware.files
%{_firmwarepath}/iwlwifi-ty-a0-gf-a0*.pnvm
%{_firmwarepath}/iwlwifi-so-a0-*.ucode
%{_firmwarepath}/iwlwifi-so-a0-*.pnvm
%{_firmwarepath}/iwlwifi-gl-*.ucode
%{_firmwarepath}/iwlwifi-gl-*.pnvm
%{_firmwarepath}/iwlwifi-ma-*.ucode
%{_firmwarepath}/iwlwifi-ma-*.pnvm
%files -n libertas-usb8388-firmware
%license WHENCE LICENCE.Marvell
@ -438,9 +433,21 @@ sed -e 's/^/%%dir /' linux-firmware.dirs >> linux-firmware.files
%config(noreplace) %{_firmwarepath}/netronome/nic_AMDA*
%changelog
* Tue Sep 26 2023 Patrick Talbert <ptalbert@redhat.com> - 20230824-119.git0e048b06
- Exclude AMD cpu ucode for fam19/*cpuid_0x00aa0f0*
Resolves: RHEL-3903
* Thu Jan 11 2024 Denys Vlasenko <dvlasenk@redhat.com> - 20240111-121.gitb3132c18
- Pass --ignore-duplicates to copy-firmware.sh
- AMD Zen3 and Zen4: fix for INVD instruction causing loss of SEV-ES guest machine memory integrity
Resolves: RHEL-13982
* Wed Nov 22 2023 Denys Vlasenko <dvlasenk@redhat.com> - 20231121-120.git9552083a
- Work around absense of rdfind during build
- Add file directives for new iwlwifi files
Resolves: RHEL-16721, RHEL-14260
* Tue Nov 21 2023 Denys Vlasenko <dvlasenk@redhat.com> - 20231121-119.git9552083a
- Update to latest upstream linux-firmware image for assorted updates
- Update AMD cpu microcode
- hw: intel: Fix protection mechanism failure for some Intel(R) PROSet/Wireless WiFi
Resolves: RHEL-16721, RHEL-14260
* Thu Aug 24 2023 Denys Vlasenko <dvlasenk@redhat.com> - 20230824-118.git0e048b06
- Update to latest upstream linux-firmware image for assorted updates